精读 Vue 官方文档系列 ?
组件的本质与作用
- 组件实际上就是一个独立的 Vue 实例。
- 组件的作用就是为了功能与 UI 的复用。
data 必须是一个函数
为了避免多个组件共享同一份响应式数据,Vue 特意规定组件的 data
选项必须是一个函数,用来返回独立的对象。
var common = {count:0};
Vue.component('comp-1', {
data(){
return common;
},
template:`<button @click="count++">click count items {{count}}</button>`
});
Vue.component('comp-2', {
data(){
return common;
},
template:`<button @click="count++">click count items {{count}}</button>`
});
复制代码
例如上例的两个组件中虽然
data
属性是一个函数,但是返回的仍然是同一个对象的引用,所以此时两个组件共享同一份响应式数据。
组件的组织
应用 是通过组件树的嵌套组织体现的。
例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。
组件的注册主要有:
- 全局注册:
Vue.component(name, option)
- 局部注册:
{components:{}}
通过 Prop 向子组件传递数据
如果传递的是静态数据/静态字符串那么直接在组件上使用普通的 HTML Attribute 即可。
<comp-1 name="comp-1" title="comp-1 component example"></comp-1>
复制代码
但是如果要传递的数据是动态数据/响应式数据那么必须要使用 v-bind
指令进行属性的绑定。
<comp-1 :post="dataItem.post"></comp-1>
复制代码
其中
dataItem.post
是一个变量。
单个根元素
组件必须要有一个唯一的根节点来包裹所有内容。
组件的事件监听
- 父组件通过
v-on
指令来监听子组件发出的事件。 - 子组件内部通过
$emit(eventName[,arguments])
来发出事件并传递事件参数。 - 事件可以携带要传递的值(事件参数),在父组件的模板中可以通过专门的
$event
来获取子组件传递的值。
<comp-1 v-on:triggel="count+=$event"></comp-1>
复制代码
你也可以指定一个事件响应处理的方法。
v-model 的原理
v-model
的实现是建立在组件事件通信的基础上。
v-model
是一个语法糖,它默认绑定了组件的 input
事件,接收事件携带的值,然后变更组件的 value
属性的值,从而实现数据的双向绑定。
<input v-model="searchText">
<!--等价于:-->
<input
v-bind:value="searchText"
v-on:input="searchText = $event.target.value"
>
复制代码
slot 插槽
<slot>
, [slɒt] 元素是 Vue 内置的组件之一。
<slot>
元素可以用来接收和分发组件起始标签与结束标签之间的内容。
<alert-box>
Something bad happened.
</alert-box>
复制代码
Vue.component('alert-box', {
template: `
<div class="demo-alert-box">
<strong>Error!</strong>
<slot></slot>
</div>
`
})
复制代码
动态组件
<component>
元素也是 Vue 内置的组件之一。
<component>
元素用来实现动态组件技术。
我们可以将 <component>
理解成是一个空的组件容器,它会基于 :is
属性传递的组件名称来动态渲染对应的组件。因此也可以将其理解成组件的占位符。
<component>
组件支持像一般组件那样绑定属性、绑定事件,这些事件与属性会自动传递到要实际渲染的组件上。
<component
title="title"
:is="componentName"
:post="dataItem.post"
v-on:triggel="count += $event"
></component>
<!--等价于-->
<component-name
title="title"
:post="dataItem.post"
v-on:triggel="count += $event"
></component>
复制代码
解析 DOM 模板时的注意事项
有些 HTML 标签对其内部的子元素有着严格的限制要求,例如<table>
只能是 <tr>
,<ul>
只能是 <li>
,<select>
只能是 <option>
等。如果我们用自定义组件去替代此类元素的类容,就会被浏览器解析为无效的内容提升到外部,从而导致最终渲染结果出错。
幸好,动态组件技术的 is
attribute 给了我们一个变通方法的启发:
<table>
<tr is="blog-post-row"></tr>
</table>
复制代码
这种问题只会出现在将 自定义组件 使用在了一个 HTML 文件中(例如 public.html
中),而且所处的父元素对其内部的子元素还有着严格的要求。所以如果我们使用的是 “单文件组件”、“模板字符串”、“脚本模板” 的任一种方式都不会出现此类问题:
- 字符串 (例如:template: ‘…’)
- 单文件组件 (.vue)
<script type="text/x-template">
因为它们都会事先通过 Vue 编译器进行编译输出,而不是事先固定存在在一个 html 文件中直接被浏览器加载并解析。