组件 (Component) 是 Vue.js 最强大的功能之一。组件能够扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素,Vue.js 的编译器为它添加特殊功能。在有些状况下,组件也能够表现为用 is 特性进行了扩展的原生 HTML 元素。
使用组件vue
咱们已经知道,能够经过如下方式建立一个 Vue 实例:webpack
new Vue({ el: '#some-element', // 选项 })
要注册一个全局组件,可使用 Vue.component(tagName, options)。例如:web
Vue.component('my-component', { // 选项 })
请注意,对于自定义标签的命名 Vue.js 不强制遵循 W3C 规则 (小写,而且包含一个短杠),尽管这被认为是最佳实践。数组
组件在注册以后,即可以做为自定义元素 <my-component></my-component> 在一个实例的模板中使用。注意确保在初始化根实例以前注册组件:浏览器
<div id="example"> <my-component></my-component> </div> // 注册 Vue.component('my-component', { template: '<div>A custom component!</div>' }) // 建立根实例 new Vue({ el: '#example' }) 渲染为: <div id="example"> <div>A custom component!</div> </div> A custom component!
你没必要把每一个组件都注册到全局。你能够经过某个 Vue 实例/组件的实例选项 components 注册仅在其做用域中可用的组件:缓存
var Child = { template: '<div>A custom component!</div>' } new Vue({ // ... components: { // <my-component> 将只在父组件模板中可用 'my-component': Child } })
这种封装也适用于其它可注册的 Vue 功能,好比指令。
DOM 模板解析注意事项服务器
当使用 DOM 做为模板时 (例如,使用 el 选项来把 Vue 实例挂载到一个已有内容的元素上),你会受到 HTML 自己的一些限制,由于 Vue 只有在浏览器解析、规范化模板以后才能获取其内容。尤为要注意,像 <ul>、<ol>、<table>、<select> 这样的元素里容许包含的元素有限制,而另外一些像 <option> 这样的元素只能出如今某些特定元素的内部。
在自定义组件中使用这些受限制的元素时会致使一些问题,例如:app
<table> <my-row>...</my-row> </table>
自定义组件 <my-row> 会被看成无效的内容,所以会致使错误的渲染结果。变通的方案是使用特殊的 is 特性:异步
<table> <tr is="my-row"></tr> </table>
应当注意,若是使用来自如下来源之一的字符串模板,则没有这些限制:
<script type="text/x-template">
JavaScript 内联模板字符串
.vue 组件
所以,请尽量使用字符串模板。
data 必须是函数async
构造 Vue 实例时传入的各类选项大多数均可以在组件里使用。只有一个例外:data 必须是函数。实际上,若是你这么作:
Vue.component('my-component', { template: '<span>{{ message }}</span>', data: { message: 'hello' } })
那么 Vue 会中止运行,并在控制台发出警告,告诉你在组件实例中 data 必须是一个函数。但理解这种规则为什么存在也是颇有益处的,因此让咱们先做个弊:
<div id="example-2"> <simple-counter></simple-counter> <simple-counter></simple-counter> <simple-counter></simple-counter> </div> var data = { counter: 0 } Vue.component('simple-counter', { template: '<button v-on:click="counter += 1">{{ counter }}</button>', // 技术上 data 的确是一个函数了,所以 Vue 不会警告, // 可是咱们却给每一个组件实例返回了同一个对象的引用 data: function () { return data } }) new Vue({ el: '#example-2' }) 0 0 0
因为这三个组件实例共享了同一个 data 对象,所以递增一个 counter 会影响全部组件!这就错了。咱们能够经过为每一个组件返回全新的数据对象来修复这个问题:
data: function () { return { counter: 0 } } 如今每一个 counter 都有它本身内部的状态了: 0 0 0
组件设计初衷就是要配合使用的,最多见的就是造成父子组件的关系:组件 A 在它的模板中使用了组件 B。它们之间必然须要相互通讯:父组件可能要给子组件下发数据,子组件则可能要将它内部发生的事情告知父组件。然而,经过一个良好定义的接口来尽量将父子组件解耦也是很重要的。这保证了每一个组件的代码能够在相对隔离的环境中书写和理解,从而提升了其可维护性和复用性。
在 Vue 中,父子组件的关系能够总结为 prop 向下传递,事件向上传递。父组件经过 prop 给子组件下发数据,子组件经过事件给父组件发送消息。看看它们是怎么工做的。
prop 向下传递,事件向上传递
Prop
使用 Prop 传递数据
组件实例的做用域是孤立的。这意味着不能 (也不该该) 在子组件的模板内直接引用父组件的数据。父组件的数据须要经过 prop 才能下发到子组件中。
子组件要显式地用 props 选项声明它预期的数据:
Vue.component('child', { // 声明 props props: ['message'], // 就像 data 同样,prop 也能够在模板中使用 // 一样也能够在 vm 实例中经过 this.message 来使用 template: '<span>{{ message }}</span>' }) 而后咱们能够这样向它传入一个普通字符串: <child message="hello!"></child> 结果: hello! camelCase vs. kebab-case
HTML 特性是不区分大小写的。因此,当使用的不是字符串模板时,camelCase (驼峰式命名) 的 prop 须要转换为相对应的 kebab-case (短横线分隔式命名):
Vue.component('child', { // 在 JavaScript 中使用 camelCase props: ['myMessage'], template: '<span>{{ myMessage }}</span>' })
<!-- 在 HTML 中使用 kebab-case -->
<child my-message="hello!"></child>
若是你使用字符串模板,则没有这些限制。
动态 Prop
与绑定到任何普通的 HTML 特性相相似,咱们能够用 v-bind 来动态地将 prop 绑定到父组件的数据。每当父组件的数据变化时,该变化也会传导给子组件:
<div> <input v-model="parentMsg"> <br> <child v-bind:my-message="parentMsg"></child> </div> 你也可使用 v-bind 的缩写语法: <child :my-message="parentMsg"></child> 结果: Message from parent Message from parent
若是你想把一个对象的全部属性做为 prop 进行传递,可使用不带任何参数的 v-bind (即用 v-bind 而不是 v-bind:prop-name)。例如,已知一个 todo 对象:
todo: { text: 'Learn Vue', isComplete: false } 而后: <todo-item v-bind="todo"></todo-item> 将等价于: <todo-item v-bind:text="todo.text" v-bind:is-complete="todo.isComplete" ></todo-item>
字面量语法 vs 动态语法
初学者常犯的一个错误是使用字面量语法传递数值:
<!-- 传递了一个字符串 "1" -->
<comp some-prop="1"></comp>
由于它是一个字面量 prop,它的值是字符串 "1" 而不是一个数值。若是想传递一个真正的 JavaScript 数值,则须要使用 v-bind,从而让它的值被看成 JavaScript 表达式计算:
<!-- 传递真正的数值 -->
<comp v-bind:some-prop="1"></comp>
Prop 是单向绑定的:当父组件的属性变化时,将传导给子组件,可是反过来不会。这是为了防止子组件无心间修改了父组件的状态,来避免应用的数据流变得难以理解。
另外,每次父组件更新时,子组件的全部 prop 都会更新为最新值。这意味着你不该该在子组件内部改变 prop。若是你这么作了,Vue 会在控制台给出警告。
在两种状况下,咱们很容易忍不住想去修改 prop 中数据:
Prop 做为初始值传入后,子组件想把它看成局部数据来用;
Prop 做为原始数据传入,由子组件处理成其它数据输出。
对这两种状况,正确的应对方式是:
定义一个局部变量,并用 prop 的值初始化它:
props: ['initialCounter'], data: function () { return { counter: this.initialCounter } } 定义一个计算属性,处理 prop 的值并返回: props: ['size'], computed: { normalizedSize: function () { return this.size.trim().toLowerCase() } }
注意在 JavaScript 中对象和数组是引用类型,指向同一个内存空间,若是 prop 是一个对象或数组,在子组件内部改变它会影响父组件的状态。
Prop 验证
咱们能够为组件的 prop 指定验证规则。若是传入的数据不符合要求,Vue 会发出警告。这对于开发给他人使用的组件很是有用。
要指定验证规则,须要用对象的形式来定义 prop,而不能用字符串数组:
Vue.component('example', { props: { // 基础类型检测 (`null` 指容许任何类型) propA: Number, // 多是多种类型 propB: [String, Number], // 必传且是字符串 propC: { type: String, required: true }, // 数值且有默认值 propD: { type: Number, default: 100 }, // 数组/对象的默认值应当由一个工厂函数返回 propE: { type: Object, default: function () { return { message: 'hello' } } }, // 自定义验证函数 propF: { validator: function (value) { return value > 10 } } } }) type 能够是下面原生构造器: String Number Boolean Function Object Array Symbol
type 也能够是一个自定义构造器函数,使用 instanceof 检测。
当 prop 验证失败,Vue 会抛出警告 (若是使用的是开发版本)。注意 prop 会在组件实例建立以前进行校验,因此在 default 或 validator 函数里,诸如 data、computed 或 methods 等实例属性还没法使用。
非 Prop 特性
所谓非 prop 特性,就是指它能够直接传入组件,而不须要定义相应的 prop。
尽管为组件定义明确的 prop 是推荐的传参方式,组件的做者却并不总能预见到组件被使用的场景。因此,组件能够接收任意传入的特性,这些特性都会被添加到组件的根元素上。
例如,假设咱们使用了第三方组件 bs-date-input,它包含一个 Bootstrap 插件,该插件须要在 input 上添加 data-3d-date-picker 这个特性。这时能够把特性直接添加到组件上 (不须要事先定义 prop):
<bs-date-input data-3d-date-picker="true"></bs-date-input>
添加属性 data-3d-date-picker="true" 以后,它会被自动添加到 bs-date-input 的根元素上。
替换/合并现有的特性
假设这是 bs-date-input 的模板:
<input type="date" class="form-control">
为了给该日期选择器插件增长一个特殊的主题,咱们可能须要增长一个特殊的 class,好比:
<bs-date-input data-3d-date-picker="true" class="date-picker-theme-dark" ></bs-date-input>
在这个例子当中,咱们定义了两个不一样的 class 值:
form-control,来自组件自身的模板
date-picker-theme-dark,来自父组件
对于多数特性来讲,传递给组件的值会覆盖组件自己设定的值。即例如传递 type="large" 将会覆盖 type="date" 且有可能破坏该组件!所幸咱们对待 class 和 style 特性会更聪明一些,这两个特性的值都会作合并 (merge) 操做,让最终生成的值为:form-control date-picker-theme-dark。
自定义事件
咱们知道,父组件使用 prop 传递数据给子组件。但子组件怎么跟父组件通讯呢?这个时候 Vue 的自定义事件系统就派得上用场了。
使用 v-on 绑定自定义事件
每一个 Vue 实例都实现了事件接口,即:
使用 $on(eventName) 监听事件
使用 $emit(eventName) 触发事件
Vue 的事件系统与浏览器的 EventTarget API 有所不一样。尽管它们的运行起来相似,可是 $on 和 $emit 并非addEventListener 和 dispatchEvent 的别名。
另外,父组件能够在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
不能用 $on 侦听子组件释放的事件,而必须在模板里直接用 v-on 绑定,参见下面的例子。
下面是一个例子:
<div id="counter-event-example"> <p>{{ total }}</p> <button-counter v-on:increment="incrementTotal"></button-counter> <button-counter v-on:increment="incrementTotal"></button-counter> </div> Vue.component('button-counter', { template: '<button v-on:click="incrementCounter">{{ counter }}</button>', data: function () { return { counter: 0 } }, methods: { incrementCounter: function () { this.counter += 1 this.$emit('increment') } }, }) new Vue({ el: '#counter-event-example', data: { total: 0 }, methods: { incrementTotal: function () { this.total += 1 } } }) 0 0 0
在本例中,子组件已经和它外部彻底解耦了。它所作的只是报告本身的内部事件,由于父组件可能会关心这些事件。请注意这一点很重要。
给组件绑定原生事件
有时候,你可能想在某个组件的根元素上监听一个原生事件。可使用 v-on 的修饰符 .native。例如:
<my-component v-on:click.native="doTheThing"></my-component>
.sync 修饰符
2.3.0+
在一些状况下,咱们可能会须要对一个 prop 进行“双向绑定”。事实上,这正是 Vue 1.x 中的 .sync 修饰符所提供的功能。当一个子组件改变了一个带 .sync 的 prop 的值时,这个变化也会同步到父组件中所绑定的值。这很方便,但也会致使问题,由于它破坏了单向数据流。因为子组件改变 prop 的代码和普通的状态改动代码毫无区别,当光看子组件的代码时,你彻底不知道它什么时候悄悄地改变了父组件的状态。这在 debug 复杂结构的应用时会带来很高的维护成本。
上面所说的正是咱们在 2.0 中移除 .sync 的理由。可是在 2.0 发布以后的实际应用中,咱们发现 .sync 仍是有其适用之处,好比在开发可复用的组件库时。咱们须要作的只是让子组件改变父组件状态的代码更容易被区分。
从 2.3.0 起咱们从新引入了 .sync 修饰符,可是此次它只是做为一个编译时的语法糖存在。它会被扩展为一个自动更新父组件属性的 v-on 监听器。
以下代码
<comp :foo.sync="bar"></comp>
会被扩展为:
<comp :foo="bar" @update:foo="val => bar = val"></comp>
当子组件须要更新 foo 的值时,它须要显式地触发一个更新事件:
this.$emit('update:foo', newValue)
使用自定义事件的表单输入组件
自定义事件能够用来建立自定义的表单输入组件,使用 v-model 来进行数据双向绑定。要牢记:
<input v-model="something"> 这不过是如下示例的语法糖: <input v-bind:value="something" v-on:input="something = $event.target.value"> 因此在组件中使用时,它至关于下面的简写: <custom-input v-bind:value="something" v-on:input="something = arguments[0]"> </custom-input>
因此要让组件的 v-model 生效,它应该 (从 2.2.0 起是可配置的):
接受一个 value prop
在有新的值时触发 input 事件并将新值做为参数
咱们来看一个很是简单的货币输入的自定义控件:
<currency-input v-model="price"></currency-input> Vue.component('currency-input', { template: '\ <span>\ $\ <input\ ref="input"\ v-bind:value="value"\ v-on:input="updateValue($event.target.value)"\ >\ </span>\ ', props: ['value'], methods: { // 不是直接更新值,而是使用此方法来对输入值进行格式化和位数限制 updateValue: function (value) { var formattedValue = value // 删除两侧的空格符 .trim() // 保留 2 位小数 .slice( 0, value.indexOf('.') === -1 ? value.length : value.indexOf('.') + 3 ) // 若是值尚不合规,则手动覆盖为合规的值 if (formattedValue !== value) { this.$refs.input.value = formattedValue } // 经过 input 事件带出数值 this.$emit('input', Number(formattedValue)) } } }) $
固然,上面的例子仍是比较初级的。好比,用户输入多个小数点或句号也是容许的,好恶心吧!所以咱们须要一个复杂一些的例子,下面是一个更加完善的货币过滤器:
自定义组件的 v-model
2.2.0 新增
默认状况下,一个组件的 v-model 会使用 value prop 和 input 事件。可是诸如单选框、复选框之类的输入类型可能把 value 用做了别的目的。model 选项能够避免这样的冲突:
Vue.component('my-checkbox', { model: { prop: 'checked', event: 'change' }, props: { checked: Boolean, // 这样就容许拿 `value` 这个 prop 作其它事了 value: String }, // ... }) <my-checkbox v-model="foo" value="some value"></my-checkbox> 上述代码等价于: <my-checkbox :checked="foo" @change="val => { foo = val }" value="some value"> </my-checkbox> 注意你仍然须要显式声明 checked 这个 prop。
有时候,非父子关系的两个组件之间也须要通讯。在简单的场景下,可使用一个空的 Vue 实例做为事件总线:
var bus = new Vue() // 触发组件 A 中的事件 bus.$emit('id-selected', 1) // 在组件 B 建立的钩子中监听事件 bus.$on('id-selected', function (id) { // ... })
在复杂的状况下,咱们应该考虑使用专门的状态管理模式。
使用插槽分发内容
在使用组件时,咱们经常要像这样组合它们:
<app> <app-header></app-header> <app-footer></app-footer> </app>
注意两点:
<app> 组件不知道它会收到什么内容。这是由使用 <app> 的父组件决定的。
<app> 组件极可能有它本身的模板。
为了让组件能够组合,咱们须要一种方式来混合父组件的内容与子组件本身的模板。这个过程被称为内容分发 (即 Angular 用户熟知的“transclusion”)。Vue.js 实现了一个内容分发 API,参照了当前 Web Components 规范草案,使用特殊的 <slot> 元素做为原始内容的插槽。
编译做用域
在深刻内容分发 API 以前,咱们先明确内容在哪一个做用域里编译。假定模板为:
<child-component>
{{ message }}
</child-component>
message 应该绑定到父组件的数据,仍是绑定到子组件的数据?答案是父组件。组件做用域简单地说是:
父组件模板的内容在父组件做用域内编译;子组件模板的内容在子组件做用域内编译。
一个常见错误是试图在父组件模板内将一个指令绑定到子组件的属性/方法:
<!-- 无效 -->
<child-component v-show="someChildProperty"></child-component>
假定 someChildProperty 是子组件的属性,上例不会如预期那样工做。父组件模板并不感知子组件的状态。
若是要绑定子组件做用域内的指令到一个组件的根节点,你应当在子组件本身的模板里作:
Vue.component('child-component', { // 有效,由于是在正确的做用域内 template: '<div v-show="someChildProperty">Child</div>', data: function () { return { someChildProperty: true } } })
相似地,被分发的内容会在父做用域内编译。
单个插槽
除非子组件模板包含至少一个 <slot> 插口,不然父组件的内容将会被丢弃。当子组件模板只有一个没有属性的插槽时,父组件传入的整个内容片断将插入到插槽所在的 DOM 位置,并替换掉插槽标签自己。
最初在 <slot> 标签中的任何内容都被视为备用内容。备用内容在子组件的做用域内编译,而且只有在宿主元素为空,且没有要插入的内容时才显示备用内容。
假定 my-component 组件有以下模板:
<div> <h2>我是子组件的标题</h2> <slot> 只有在没有要分发的内容时才会显示。 </slot> </div> 父组件模板: <div> <h1>我是父组件的标题</h1> <my-component> <p>这是一些初始内容</p> <p>这是更多的初始内容</p> </my-component> </div> 渲染结果: <div> <h1>我是父组件的标题</h1> <div> <h2>我是子组件的标题</h2> <p>这是一些初始内容</p> <p>这是更多的初始内容</p> </div> </div> 具名插槽
<slot> 元素能够用一个特殊的特性 name 来进一步配置如何分发内容。多个插槽能够有不一样的名字。具名插槽将匹配内容片断中有对应 slot 特性的元素。
仍然能够有一个匿名插槽,它是默认插槽,做为找不到匹配的内容片断的备用插槽。若是没有默认插槽,这些找不到匹配的内容片断将被抛弃。
例如,假定咱们有一个 app-layout 组件,它的模板为:
<div class="container"> <header> <slot name="header"></slot> </header> <main> <slot></slot> </main> <footer> <slot name="footer"></slot> </footer> </div> 父组件模板: <app-layout> <h1 slot="header">这里多是一个页面标题</h1> <p>主要内容的一个段落。</p> <p>另外一个主要段落。</p> <p slot="footer">这里有一些联系信息</p> </app-layout> 渲染结果为: <div class="container"> <header> <h1>这里多是一个页面标题</h1> </header> <main> <p>主要内容的一个段落。</p> <p>另外一个主要段落。</p> </main> <footer> <p>这里有一些联系信息</p> </footer> </div> 在设计组合使用的组件时,内容分发 API 是很是有用的机制。 做用域插槽
2.1.0 新增
做用域插槽是一种特殊类型的插槽,用做一个 (能被传递数据的) 可重用模板,来代替已经渲染好的元素。
在子组件中,只需将数据传递到插槽,就像你将 prop 传递给组件同样:
<div class="child"> <slot text="hello from child"></slot> </div>
在父级中,具备特殊特性 slot-scope 的 <template> 元素必须存在,表示它是做用域插槽的模板。slot-scope 的值将被用做一个临时变量名,此变量接收从子组件传递过来的 prop 对象:
<div class="parent"> <child> <template slot-scope="props"> <span>hello from parent</span> <span>{{ props.text }}</span> </template> </child> </div> 若是咱们渲染上述模板,获得的输出会是: <div class="parent"> <div class="child"> <span>hello from parent</span> <span>hello from child</span> </div> </div>
在 2.5.0+,slot-scope 能被用在任意元素或组件中而再也不局限于 <template>。
做用域插槽更典型的用例是在列表组件中,容许使用者自定义如何渲染列表的每一项:
<my-awesome-list :items="items"> <!-- 做用域插槽也能够是具名的 --> <li slot="item" slot-scope="props" class="my-fancy-item"> {{ props.text }} </li> </my-awesome-list> 列表组件的模板: <ul> <slot name="item" v-for="item in items" :text="item.text"> <!-- 这里写入备用内容 --> </slot> </ul> 解构
slot-scope 的值其实是一个能够出如今函数签名参数位置的合法的 JavaScript 表达式。这意味着在受支持的环境 (单文件组件或现代浏览器) 中,您还能够在表达式中使用 ES2015 解构:
<child>
<span slot-scope="{ text }">{{ text }}</span>
</child>
动态组件
经过使用保留的 <component> 元素,动态地绑定到它的 is 特性,咱们让多个组件可使用同一个挂载点,并动态切换:
var vm = new Vue({ el: '#example', data: { currentView: 'home' }, components: { home: { /* ... */ }, posts: { /* ... */ }, archive: { /* ... */ } } }) <component v-bind:is="currentView"> <!-- 组件在 vm.currentview 变化时改变! --> </component> 也能够直接绑定到组件对象上: var Home = { template: '<p>Welcome home!</p>' } var vm = new Vue({ el: '#example', data: { currentView: Home } }) keep-alive
若是把切换出去的组件保留在内存中,能够保留它的状态或避免从新渲染。为此能够添加一个 keep-alive 指令参数:
<keep-alive>
<component :is="currentView">
<!-- 非活动组件将被缓存! -->
</component>
</keep-alive>
在 API 参考中查看更多 <keep-alive> 的细节。
杂项
在编写组件时,最好考虑好之后是否要进行复用。一次性组件间有紧密的耦合不要紧,可是可复用组件应当定义一个清晰的公开接口,同时也不要对其使用的外层数据做出任何假设。
Vue 组件的 API 来自三部分——prop、事件和插槽:
Prop 容许外部环境传递数据给组件;
事件容许从组件内触发外部环境的反作用;
插槽容许外部环境将额外的内容组合在组件中。
使用 v-bind 和 v-on 的简写语法,模板的意图会更清楚且简洁:
<my-component :foo="baz" :bar="qux" @event-a="doThis" @event-b="doThat" > <img slot="icon" src="..."> <p slot="main-text">Hello!</p> </my-component>
子组件引用
尽管有 prop 和事件,可是有时仍然须要在 JavaScript 中直接访问子组件。为此可使用 ref 为子组件指定一个引用 ID。例如:
<div id="parent">
<user-profile ref="profile"></user-profile>
</div>
var parent = new Vue({ el: '#parent' })
// 访问子组件实例
var child = parent.$refs.profile
当 ref 和 v-for 一块儿使用时,获取到的引用会是一个数组,包含和循环数据源对应的子组件。
$refs 只在组件渲染完成后才填充,而且它是非响应式的。它仅仅是一个直接操做子组件的应急方案——应当避免在模板或计算属性中使用 $refs。
异步组件
在大型应用中,咱们可能须要将应用拆分为多个小模块,按需从服务器下载。为了进一步简化,Vue.js 容许将组件定义为一个工厂函数,异步地解析组件的定义。Vue.js 只在组件须要渲染时触发工厂函数,而且把结果缓存起来,用于后面的再次渲染。例如:
Vue.component('async-example', function (resolve, reject) { setTimeout(function () { // 将组件定义传入 resolve 回调函数 resolve({ template: '<div>I am async!</div>' }) }, 1000) })
工厂函数接收一个 resolve 回调,在收到从服务器下载的组件定义时调用。也能够调用 reject(reason) 指示加载失败。这里使用 setTimeout 只是为了演示,实际上如何获取组件彻底由你决定。推荐配合 webpack 的代码分割功能 来使用:
Vue.component('async-webpack-example', function (resolve) { // 这个特殊的 require 语法告诉 webpack // 自动将编译后的代码分割成不一样的块, // 这些块将经过 Ajax 请求自动下载。 require(['./my-async-component'], resolve) }) 你能够在工厂函数中返回一个 Promise,因此当使用 webpack 2 + ES2015 的语法时能够这样: Vue.component( 'async-webpack-example', // 该 `import` 函数返回一个 `Promise` 对象。 () => import('./my-async-component') ) 当使用局部注册时,也能够直接提供一个返回 Promise 的函数: new Vue({ // ... components: { 'my-component': () => import('./my-async-component') } })
若是你是 Browserify 用户,可能就没法使用异步组件了,它的做者已经代表 Browserify 将“永远不会支持异步加载”。Browserify 社区发现了一些解决方法,可能会有助于已存在的复杂应用。对于其余场景,咱们推荐使用 webpack,由于它对异步加载进行了内置、全面的支持。
其余敬请期待。。。