Vue 中可以定义组件模版的几种方式

前置知识回顾

new Vue({...options})一些基本知识
new Vue(options)的选项中,也可以拥有 data、methods、components、生命周期函数等等,和组件实例的 options 一样。如下例子

<div id="app">
  {{uname}}
  <hello-word></hello-word>
</div>
<script>
  Vue.component("HelloWord", {
    data() {
      return {
        msg: "你好,世界!",
      };
    },
    template: "<div>HelloWord组件-{{msg}}</div>",
  });

  var app = new Vue({
    el: "#app",
    data() {
      return {
        uname: "小红",
      };
    },
  });
</script>

根实例的 template、render 不是必须的,如上例子就是.
它们的作用是接受一个根组件,然后将其编译后的内容填充到 el 内.
通过 template、render 引入一个根组件,从而组成一个由上至下的组件树结构
一般情况下,我们不在根实例中定义普通选项,根实例中常用的配置项有:

{
    el: "#app",
    router,
    store,
    render:h=>h(App)
  }

之所以说这些,是因为我下边的例子中,根实例有的没有用到 template、render
下边我们举例说一下vue都有哪些模板技术

方式 1: 模板-vue 单文件

使用构建工具 cli 创建项目,综合来看单文件组件应该是最好的定义组件的方式,而且不会带来额外的模版语法的学习成本。
如下,就一个完整的组件,使用的地方直接导入即可
import MyHeader from './my-header.vue'

<template>
  <h1>{{title}}</h1>
</template>
<script>
  // ./my-header.vue
  export default {
    name: "MyHeader",
    props: {
      title: "",
    },
  };
</script>

方式 2: 模板-template

Vue 最简单直接的一种定义组件模版的方式,但是方式写起来很不友好,就像我们以前拼接 HTML 元素是一样的,很痛苦,所以我们并不常用
字符串模板,template 选项对象的属性,模板将会替换挂载的元素,挂载元素的内容都将被忽略

<div id="app">
  <my-header title="xx列表"></my-header>
</div>
<script>
  var MyHeader = {
    props: {
      title: "",
    },
    // 此处也可以使用es6的字符串模板能力
    template: "<h1>{{title}}</h1>",
  };

  var app = new Vue({
    el: "#app",
    components: { MyHeader },
  });
</script>

回忆过去

需要注意是的是,大概 2018 年的时候,脚手架创建的项目
vue 实例都是使 template 属性来指定根组件
不过现在都被 render 函数写法代替了

const app = new Vue({
  el: "#app",
  components: { App },
  template: "<App/>",
});
const app = new Vue({
  render: (h) => h(App),
}).$mount("#app");

展望未来

X-Template,本质上讲,它仍是字符串模板 template 技术,是属于字符串模板的辅助性技术
定义一个 <script> 标签,标记 text/x-template类型,通过 id 链接
这个跟腾讯的artTemplate很像

<div id="app">
  <my-header title="xx列表"></my-header>
</div>
<script type="text/x-template" id="my-header-xt">
  <h1>{{this.title}}</h1>
</script>
<script>
  Vue.component("MyHeader", {
    props: {
      title: "",
    },
    template: "#my-header-xt",
  });

  var app = new Vue({
    el: "#app",
  });
</script>

方式 3: 模板-内联模板

与 「X-template」模版定义方式被称为模版定义的替代品,把内容定义在组件标签元素的内部,而不是作为 slot 内容分发,方式比较灵活,但是给让我们组件的模版与其他属性分离开。

<div id="app">
  <my-template inline-template>
    <div>
      <!-- 🚀只能有一个根元素 -->
      <div>{{uname}}</div>
      <!-- ❌❌ 无法使用父组件data -->
      <div>{{msg}}</div>
    </div>
  </my-template>
</div>
<script>
  Vue.component("MyTemplate", {
    data() {
      return {
        msg: "在子组件中声明的数据",
      };
    },
  });

  var app = new Vue({
    el: "#app",
    data() {
      return {
        uname: "小红",
      };
    },
  });
</script>

方式 4: 模板-render 函数

单文件组件底层内部最终也是会被编译成 render 函数形式
render 函数将会替换挂载的元素,挂载元素的内容都将被忽略
模板-template的代替方案

Vue.component("MyHeader", {
  props: {
    title: "",
  },
  render(createElement) {
    // 此处可以替换为jsx,会更加简介
    return createElement("h1", this.title);
  },
});
var app = new Vue({
  el: "#app",
});

以上就是 Vue 中可以定义组件模版的几种方式,有人可能说,我特么要知道这么多干嘛,只要一种不就行了,我想说兄 die 多知道几种可以帮助我们在不同的条件下做出更好的选择。

比如:你就需要开发一个简单的页面,你非要弄个单文件组件,脚手架跑起来,何必呢,你说对不。

解析 DOM 模板时的注意事项

有些 HTML 元素,诸如 <ul><ol><table><select>,对于哪些元素可以出现在其内部是有严格限制的。而有些元素,诸如 <li><tr><option>,只能出现在其它某些特定的元素内部。

这会导致我们使用这些有约束条件的元素时遇到一些问题。例如:

<table>
  <blog-post-row></blog-post-row>
</table>

这个自定义组件 <blog-post-row> 会被作为无效的内容提升到外部,并导致最终渲染结果出错。幸好这个特殊的 is attribute 给了我们一个变通的办法:

<table>
  <tr is="blog-post-row"></tr>
</table>

需要注意的是如果我们从以下来源使用模板的话,这条限制是不存在的:

  • 字符串模板 (例如:template: '...')
  • 单文件组件 (.vue)
  • 模板定义的替代品之 X-Template

解读官方文档的描述,意思是说,普通这种写法(我把它称之为html模板)是不行的

<div id="app">
  <select>
    <my-option></my-option>
  </select>
</div>
<script>
  Vue.component("MyOption", {
    template: "<option>选项一</option>",
  });

  var app = new Vue({
    el: "#app",
  });
</script>

使用字符串模板(模板-template)来使用组件,是可以的

<div id="app"></div>
<script>
  Vue.component("MyOption", {
    template: "<option>选项一</option>"
  });
  var app = new Vue({
    el: "#app",
    // 在模板-template使用也没问题
    template: `<select>
      <my-option></my-option>
    </select>`
  });
</script>

单文件组件 (.vue),是可以的

<template>
  <div id="app">
    <select>
      <!-- 在单文件模板里这么用没问题 -->
      <my-option></my-option>
    </select>
  </div>
</template>

<script>
import MyOption from './my-option.vue'
export default {
  name: 'App',
  components: { MyOption },
}
</script>

在x-template中,是可以的

<div id="app"></div>
<script type="text/x-template" id="my-app-xt">
  <select>
    <!--  在x-template使用没问题 -->
    <my-option></my-option>
  </select>
</script>
<script>
  Vue.component("MyOption", {
    template: `
      <option>选项一</option>
    </select>`,
  });

  var app = new Vue({
    el: "#app",
    template: "#my-app-xt",
  });
</script>

但是以上所有,只要is属性,就都可以解决该问题。

posted @ 2021-12-15 14:15  丁少华  阅读(532)  评论(0编辑  收藏  举报