6.组件 - 计数器Demo为例
-
组件使用细节
-
全局组件 and 局部组件
全局组件:
// 全局组件(子组件) Vue.component('row', { template: '<tr><td>{{ content }}</td></tr>', // 2. 子组件中的data必须是函数方法形式返回唯一的数据对象 data: function () { return { content: 'this is content' } } }),
局部组件: 在根组件中需要声明局部组件
var counter = { template: '<tr><td>{{ content }}</td></tr>', // 2. 子组件中的data必须是函数方法形式返回唯一的数据对象 data: function () { return { content: 'this is content' } } } var vm = new Vue({ el: "#root", // 声明局部组件 components: { counter: counter }, )}
-
组件复用:组件进行任意次数的复用
<!-- 计数器Demo --> <counter @change="handleChange" ref="one"></counter> <counter @change="handleChange" ref="two"></counter>
-
组件中 data 必须是一个函数,每个组件实例可以维护一份被返回对象的独立拷贝。
-
-
父子组件传值
-
父组件通过属性props向子组件进行传值
<div id="root"> <!-- 父组件通过属性向子组件进行传值 --> <counter :count="0" @inc="handleIncrease"></counter> <counter :count="0" @inc="handleIncrease"></counter> <div>{{ total }}</div> </div>
可以看出,上述代码通过:count,绑定了count属性,并添加了@inc自定义事件。
父组件(根组件)通过**:count**,对子组件进行传值。此时,子组件通过props对父组件传值进行获取。
// 定义局部组件 var counter = { // 子组件通过props获取父组件传过来的值。注意:子组件不可直接对props中的数据进行更改,单向数据流原理。 props: ['count'], // 对父组件传递过来的值,子组件进行备份后进行更改 data: function () { return { number: this.count } }, // 下文待填充 }
-
子组件通过事件$emit向父组件进行传值
通过上述操作,子组件可以对父组件的数据进行获取,并由于单项数据流原理进行了备份。
接下来,根据备份的父组件数据number进行模板渲染。
template: "<div @click='handleCilck'>{{ number }}</div>",
此时,在子组件渲染的<div>中添加了click事件,当块级元素被点击时,向父组件进行传值。
methods: { handleCilck: function () { this.number ++ // 向父组件传递已更改的值,触发事件 this.$emit('inc', 1) } }
点击该块级元素时,备份数据number执行自增操作,之后,通过$emit方法进行自定义事件inc声明,以及参数传递。
上述提到的**@inc="handleIncrease"**,在父组件接收子组件的触发事件,并获取事件携带参数。 var vm = new Vue({ el: "#root", // 声明局部组件 components: { counter: counter }, data: { total: 0 }, methods: { // 接收子组件触发事件,获取事件携带参数 handleIncrease: function (step) { this.total += step } } })
自定义方法inc所对应的 handleIncrease 方法触发后,响应式更新数据 total 的值。
-
组件的参数校验与非Props特性
-
Prop验证:组件的 prop 指定验证要求,对格式、长度等方面进行参数验证。
<child content="hello "></child>
子组件中添加Prop验证:
Vue.component('child', { props: { content :{ // 类型验证,数组可包含多个数据类型 type: [String, Number], // 是否必需 required: false, // 默认值 default: 'default value', // 参数长度判断 validator: function (value) { return (value.length > 5) } } }, template: '<div>{{content}}</div>', })
-
Props特性和非Props特性
Props特性:常规配置,父组件传值、子组件接值、DOM内直接使用。
非Pros特性:1. 子组件未通过props接收,因此不能显示在DOM上。 2. 子组件模板内直接写入内容而非插值表达式,会显示在DOM最外层标签上。
-
-
组件绑定原生事件
在组件的根元素上直接进行原生事件的监听,此时可以使用v-on的.native修饰符。
<div id="root"> <!-- 子组件中绑定原生的点击事件 --> <child @click.native="handleCilck"></child> </div> <script> Vue.component('child', { template: '<div>Child</div>' }) var vm = new Vue({ el: "#root", methods: { handleCilck: function () { alert("组件绑定原生事件") } } }) </script>
-
非父子组件间传值(Bus/总线/发布订阅模式/观察者模式)
业务场景如下,图片取自Vue.js官网文档,非父子组件进行传值的几种形式。
举例: 兄弟组件之间的传值问题,页面如下:
<div id="root"> <child content="Tom"></child> <child content="Jerry"></child> </div>
组件中的设置:
// 对Vue中prototype的bus属性添加vue实例 Vue.prototype.bus = new Vue() // 全局组件 Vue.component('child', { // 组件模板 template: "<div @click='handleClick'>{{selfContent}}</div>", // 父组件通过props进行数据传递 props: { content: { // 数据传递约束 type: String, required: true } }, // 应对单项数据流问题,建立数据副本 data: function () { return { selfContent: this.content } }, methods: { handleClick: function () { // 由于bus属性是一个vue实例,因此可以使用$emit进行事件的声明,携带参数,当前数据副本 this.bus.$emit('change', this.selfContent) } }, // 生命周期钩子函数 mounted() { // 防止this作用域发生变化,创建保存副本 var this_ = this // 使用$on进行自定义事件change的处理 this.bus.$on('change', function (msg) { this_.selfContent = msg }) }, })
TIPS:采用 $emit 和 $on 实现非父子组件的传值操作,需要注意的是:$emit 和 $on 事件必须在一个公共实例上,才能触发。(本例中,公共实例为:bus )
-
v-once指令和动态组件
动态组件场景,页面中需要通过按钮进行组件的切换。
页面:针对组件添加v-if,进行组件判断
<div id="root"> <child-one v-if="type === 'child-one'"></child-one> <child-two v-if="type === 'child-two'"></child-two> <button @click="handleBtnClick">change</button> </div>
组件配置: 在handleBtnClick方法中,根实例进行三元表达式判断,通过data中的type进行组件切换。
<script> Vue.component('child-one', { template: '<div>child-one</div>' }) Vue.component('child-two', { template: '<div>child-two</div>' }) var vm = new Vue({ el: '#root', data: { type: 'child-one' }, methods: { handleBtnClick: function () { this.type = this.type === 'child-one' ? 'child-two' : 'child-one' } } }) </script>
改造上述代码:
-
component为动态组件,属性is绑定组件名称(对应根实例中data中的type)。
<!-- component标签为动态组件 属性is绑定组件名称 --> <component :is="type"></component>
-
采用v-once指令,提高静态数据内容的渲染效率。
template: '<div v-once>child-one</div>'
TIPS:本篇内容关于Vue中is特性以及ref和$refs的使用将在后续博文中补充说明。
-