How to load external html file in a template in VueJs

隐身守侯 提交于 2019-12-22 03:19:11

问题


I'm new to vue js. I'm just creating a simple project where I just include vuejs through CDN. not using node/npm or cli.

I keep all my html markup in single html which looks messy as it grows. I tried to split html to views and want to include it by something analogous to ng-include of angularJs

I have worked in angular previously where there is ng-include to load external html files. I'm looking for something similar to that in vue. the whole point is to split my html files into more maintainable separate files.

have come across <template src="./myfile.html"/> but it doesn't work Can somebody help me out


回答1:


You cant. You must use async components - read guide here




回答2:


It's actually remarkably easy, but you need to keep something in mind. Behind the scenes, Vue converts your html template markup to code. That is, each element you see defined as HTML, gets converted to a javascript directive to create an element. The template is a convenience, so the single-file-component (vue file) is not something you'll be able to do without compiling with something like webpack. Instead, you'll need to use some other way of templating. Luckily there are other ways of defining templates that don't require pre-compiling and are useable in this scenario.

1 - string/template literals

example: template: '<div>{{myvar}}</div>'

2 - render function 🤢

example: render(create){create('div')}

Vue has several other ways of creating templates, but they just don't match the criteria.

here is the example for both:

AddItem.js - using render 😠 functions

'use strict';
Vue.component('add-item', {
  methods: {
    add() {
      this.$emit('add', this.value);
      this.value = ''
    }
  },

  data () {
    return {
      value: ''
    }
  },

  render(createElement) {
    var self = this
    return createElement('div', [
      createElement('input', {
        attrs: {
          type: 'text',
          placeholder: 'new Item'
        },
        // v-model functionality has to be implemented manually
        domProps: {
          value: self.value
        },
        on: {
          input: function (event) {
            self.value = event.target.value
            // self.$emit('input', event.target.value)
          }
        }
      }),
      createElement('input', {
        attrs: {
          type: 'submit',
          value: 'add'
        },
        on: {
          click: this.add
        }
      }),
    ])
  }
});

ListItem.js - using template literals (back-ticks)

'use strict';
Vue.component('list-item', {
  template: `<div class="checkbox-wrapper" @click="check">
    <h1>{{checked ? '☑' : '☐'}} {{ title }}</h1>
  </div>`,
  props: [
    'title',
    'checked'
  ],
  methods: {
    check() {
      this.$emit('change', !this.checked);
    }
  }
});

and the html

<!DOCTYPE html>
<html lang="en">
<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.0/vue.js"></script>
  <script src="ListItem.js"></script>
  <script src="AddItem.js"></script>
</head>
<body>
<div id="app">
  <add-item @add='list.push({title:arguments[0], checked: false})'></add-item>
  <list-item v-for="(l, i) in list" :key="i" :title="l.title" :checked="l.checked" @change="l.checked=arguments[0]"></list-item>
</div>
<script type="text/javascript">
new Vue({
  el: '#app',
  data: {
    newTitle: '',
    list: [
      { title: 'A', checked: true },
      { title: 'B', checked: true },
      { title: 'C', checked: true }
    ]
  }
});
</script>
</body>
</html>


TL; DR;

See it in action at : https://repl.it/OEMt/9




回答3:


Actually you can. This is kinda easy. Depends on your needs and situation. However, this code is NOT technically correct, however it will explain to you how it might work, gives you massive freedom and makes your original vue instance smaller.

To make this work, you will need vue router (cdn is ok) and in this case axios or fetch (if you dont care about supporting older browsers).

The only downfall in my opinion is that in content files you will need to add additional call parameter $parent . This will force vue to work.

index

<div id="app">

  <router-link v-for="route in this.$router.options.routes" :to="route.path" :key="route.path">{{ route.name }}</router-link>

  <section style="margin-top:50px;">
     <component :is="magician && { template: magician }" />
  </section>

</div>

  <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
  <script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>
  <script src="https://unpkg.com/axios/dist/axios.min.js"></script>

  <script>
     const viewer = axios.create({ baseURL: location.origin });

     const routes = [
       {"name":"Hello","slug":"hello","path":"/lol/index.html"},
       {"name":"Page One","slug":"page_one","path":"/lol/page-one.html"},
       {"name":"Page Two","slug":"page_two","path":"/lol/page-two.html"}
     ];

     const app = new Vue({
       router,
       el: '#app',
       data: {
          magician: null,
       },
       watch: {
          $route (to) {
              this.loader(to.path);
          }
       },
       mounted() {
          this.loader(this.$router.currentRoute.path);
       },
       methods: {
          viewer(opt) {
              return viewer.get(opt);
          },
          loader(to) {
              to == '/lol/index.html' ? to = '/lol/hello.html' : to = to;
              this.viewer(to).then((response) => {
                  this.magician = response.data;
              }).catch(error => {
                  alert(error.response.data.message);
              })
          },
          huehue(i) {
            alert(i);
          }
       }
     });
  </script>

hello.html content

<button v-on:click="$parent.huehue('this is great')">Button</button>

page-one.html content

<select>
   <option v-for="num in 20">{{ num }}</option>
</select>

page-two.html content

// what ever you like

router explanation

To make this work perfectly, you will need to find a correct way to configure your htaccess to render everything if current page after first view is not index. Everything else should work fine.

As you can see, if it is index, it will load hello content file.




回答4:


ng-include was really awesome for loading templates for router. An alternative is using fetch and implementing your own promise.



来源:https://stackoverflow.com/questions/47078315/how-to-load-external-html-file-in-a-template-in-vuejs

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!