Vue.js每天必学之组件与组件间的通信(5)

<my-component
  :foo="baz"
  :bar="qux"
  @event-a="doThis"
  @event-b="doThat">
  <!-- content -->
  <img slot="icon" src="https://www.jb51.net/article/...">
  <p slot="main-text">Hello!</p>
</my-component>

异步组件

在大型应用中,我们可能需要将应用拆分为小块,只在需要时才从服务器下载。为了让事情更简单,Vue.js 允许将组件定义为一个工厂函数,动态地解析组件的定义。Vue.js 只在组件需要渲染时触发工厂函数,并且把结果缓存起来,用于后面的再次渲染。例如:

Vue.component('async-example', function (resolve, reject) { setTimeout(function () { 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) })

资源命名约定

一些资源,如组件和指令,是以 HTML 特性或 HTML 自定义元素的形式出现在模板中。因为 HTML 特性的名字和标签的名字不区分大小写,所以资源的名字通常需使用 kebab-case 而不是 camelCase 的形式,这不大方便。

Vue.js 支持资源的名字使用 camelCase 或 PascalCase 的形式,并且在模板中自动将它们转为 kebab-case(类似于 prop 的命名约定):

// 在组件定义中 components: { // 使用 camelCase 形式注册 myComponent: { /*... */ } } <!-- 在模板中使用 kebab-case 形式 --> <my-component></my-component> ES6 对象字面量缩写 也没问题: // PascalCase import TextBox from './components/text-box'; import DropdownMenu from './components/dropdown-menu'; export default { components: { // 在模板中写作 <text-box> 和 <dropdown-menu> TextBox, DropdownMenu } }

递归组件

组件在它的模板内可以递归地调用自己,不过,只有当它有 name 选项时才可以:

var StackOverflow = Vue.extend({ name: 'stack-overflow', template: '<div>' + // 递归地调用它自己 '<stack-overflow></stack-overflow>' + '</div>' })

上面组件会导致一个错误 “max stack size exceeded”,所以要确保递归调用有终止条件。当使用 Vue.component() 全局注册一个组件时,组件 ID 自动设置为组件的 name 选项。

片断实例

在使用 template 选项时,模板的内容将替换实例的挂载元素。因而推荐模板的顶级元素始终是单个元素。

不这么写模板:

<div>root node 1</div>
<div>root node 2</div>

推荐这么写:

<div>
  I have a single root node!
  <div>node 1</div>
  <div>node 2</div>
</div>

下面几种情况会让实例变成一个片断实例:
 1.模板包含多个顶级元素。
 2.模板只包含普通文本。
 3.模板只包含其它组件(其它组件可能是一个片段实例)。
 4.模板只包含一个元素指令,如 <partial> 或 vue-router 的 <router-view>。
 5.模板根节点有一个流程控制指令,如 v-if 或 v-for。 

这些情况让实例有未知数量的顶级元素,它将把它的 DOM 内容当作片断。片断实例仍然会正确地渲染内容。不过,它没有一个根节点,它的 $el 指向一个锚节点,即一个空的文本节点(在开发模式下是一个注释节点)。

但是更重要的是,组件元素上的非流程控制指令,非 prop 特性和过渡将被忽略,因为没有根元素供绑定:

<!-- 不可以,因为没有根元素 -->
<example v-show="ok" transition="fade"></example>

<!-- props 可以 -->
<example :prop="someData"></example>

<!-- 流程控制可以,但是不能有过渡 -->
<example v-if="ok"></example>

当然片断实例有它的用处,不过通常给组件一个根节点比较好。它会保证组件元素上的指令和特性能正确地转换,同时性能也稍微好些。

内联模板

如果子组件有 inline-template 特性,组件将把它的内容当作它的模板,而不是把它当作分发内容。这让模板更灵活。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wzfwzg.html