Vue 定义组件模板的七种方式

By timebusker on January 18, 2019

在 Vue 中定义一个组件模板,至少有七种不同的方式:

  • 字符串
  • 模板字面量
  • x-template
  • 内联模板
  • render 函数
  • JSF
  • 单文件组件

字符串

默认情况下,模板会被定义为一个字符串。我想我们的观点会达成一致:字符串中的模板是非常难以理解的。除了广泛的浏览器支持之外,这种方法没有太多用处。

单行:不适合组件内容复杂的场景使用

Vue.component('my-checkbox', {
    template: `<div class="checkbox-wrapper" @click="check"><div :class="{ checkbox: true, checked: checked }"></div><div class="title"></div></div>`,
    data:{
        return { 
		    checked: false, 
			title: 'Check me' 
		}
    },
    methods: {
        check: function(){ 
		this.checked = !this.checked; 
		}
    }
});

模板字面量

ES6 模板字面量允许你使用多行定义模板,这在常规 JavaScript 字符串中是不被允许的。此方式阅读体验更佳,并在许多现代浏览器中得到支持, 不过安全起见你还是需要把代码转换成 ES5 。这种方法并不完美,我发现大多数 IDE 仍然会通过语法高亮、tab 格式化、换行符等地方的问题折磨着你。

多行:不适合组件内容复杂的场景使用

Vue.component('my-checkbox', {
    template: `<div class="checkbox-wrapper" @click="check">
                            <div :class="{ checkbox: true, checked: checked }"></div>
                            <div class="title"></div>
                        </div>`,
    data:{
        return { 
		    checked: false, 
			title: 'Check me' 
		}
    },
    methods: {
        check: function(){ 
		this.checked = !this.checked; 
		}
    }
});

x-template

使用此方法,你的模板被定义在例如index.html文件中的 script 标签里。此script标签使用text/x-template标记,并由组件定义的id引用。 我喜欢这种方法,它允许你使用适当的HTML标记编写你的HTML,不过不好的一面是,它把模板和组件定义的其它部分分离开来

Vue.component('my-checkbox', {
    template: '#checkbox-template',
    data:{
        return { 
		    checked: false, 
			title: 'Check me' 
		}
    },
    methods: {
        check: function(){ 
		this.checked = !this.checked; 
		}
    }
});
<script type="text/x-template" id="checkbox-template">
    <div class="checkbox-wrapper" @click="check">
        <div :class="{ checkbox: true, checked: checked }"></div>
        <div class="title"></div>
    </div>
</script>

内联模板

通过在组件中添加inline-template属性,你可以向Vue指示内部内容是其模板,而不是将其视为分布式内容(参考 slot )。 它与x-templates具有相同的缺点,不过一个优点是,内容在 HTML 模板的正确位置,因此可以在页面加载时呈现,而不是等到 JavaScript 运行。

Vue.component('my-checkbox', {
    data:{
        return { 
		    checked: false, 
			title: 'Check me' 
		}
    },
    methods: {
        check: function(){ 
		this.checked = !this.checked; 
		}
    }
});
<my-checkbox inline-template>
    <div class="checkbox-wrapper" @click="check">
        <div :class="{ checkbox: true, checked: checked }"></div>
        <div class="title"></div>
    </div>
</my-checkbox>

render 函数

render 函数需要你将模板定义为 JavaScript 对象,这显然是最详细和抽象的模板选项。 不过,优点是你的模板更接近编译器,并允许你使用完整的 JavaScript 功能,而不是指令提供的子集。

Vue.component('my-checkbox', {
    data() {
        return { checked: false, title: 'Check me' }
    },
    methods: {
        check() { this.checked = !this.checked; }
    },
    render(createElement) {
        return createElement(
            'div',
            {
                    attrs: {
                        'class': 'checkbox-wrapper'
                    },
                    on: {
                        click: this.check
                    }
            },
            [
                createElement(
                'div',
                {
                    'class': {
                        checkbox: true,
                        checked: this.checked
                    }
                }
                ),
                createElement(
                'div',
                {
                    attrs: {
                    'class': 'title'
                    }
                },
                [ this.title ]
                )
            ]
        );
    }
});

JSX

Vue 中最有争议的模板选项是 JSX,一些开发者认为它丑陋、不直观,是对 Vue 精神的背叛。JSX 需要你先编译,因为它不能被浏览器运行。 不过,如果你需要完整的 JavaScript 语言功能,又不太适应 render 函数过于抽象的写法,那么 JSX 是一种折衷的方式。

Vue.component('my-checkbox', {
    data() {
        return { checked: false, title: 'Check me' }
    },
    methods: {
        check() { this.checked = !this.checked; }
    },
    render() {
        return <div class="checkbox-wrapper" onClick={ this.check }>
                 <div class=></div>
                 <div class="title">{ this.title }</div>
               </div>
    }
});

单文件组件

只要你把构建工具设置的很舒服,单文件组件就是模板选项中的王者。它允许你写 HTML 标签定义组件,并且将所有组件定义保留在一个文件中。 尽管它也有一些劣势:需要预编译,某些 IDE 不支持 .vue 文件的语法高亮,不过其地位依然难以被撼动。你还可以通过引入 pug 之类的预处理器,来获得模板定义的更多可能性。

<template>
  <div class="checkbox-wrapper" @click="check">
    <div :class="{ checkbox: true, checked: checked }"></div>
    <div class="title"></div>
  </div>
</template>
<script>
  export default {
    data() {
      return { checked: false, title: 'Check me' }
    },
    methods: {
      check() { this.checked = !this.checked; }
    }
  }
</script>