我是靠谱客的博主 暴躁凉面,最近开发中收集的这篇文章主要介绍vue基础篇- 组件详解(第七章)(一),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

一、组件与复用
1、为什么使用组件
vue组件就是提高重用性,代码可复用。还有一些自定义标签,每一个标签代表一个组件,比如:<Card>、<Row>、<i-col>等。
2、组件用法
Vue组件需要注册后才可以使用。注册有全局注册局部注册两种方式。
全局注册

Vue.component('my-component', {
});

要在父实例中使用这个组件,必须要在实例创建前注册,之后就可以用的形式来使用组件。使用小写加减号分割的形式命名。

Vue.component('my-component', {
template: `<div>这是一个组件</div>`
});

template的DOM结构必须被一个元素包含,缺少<div></div>会无法渲染并报错。
在Vue实例中,使用components选项可以局部注册组件,注册后的组件只在该实例作用域下有效。

<div id="app">
<my-component></my-component>
</div>
<script>
var Child = {
template:'<div>局部注册组件内容</div>'
}
var app = new Vue({
el:'#app',
components:{
'my-component':Child
}
})
</script>

Vue组件的模板在某些情况下会受到HTML的限制,比如<table>内规定只允许是<tr>、<td>、<th>等这些表格元素,所以在<table>内直接使用组件时无效的。这种情况下,可以使用特殊的is属性来挂载组件。

<div id="app">
<table>
<tbody is="my-component"></tbody>
</table>
</div>
Vue.component('my-component', {
template: `<div>这里是组件内容</div>`
});

常见的限制元素还有<ul>、<ol>、<select>。
除了template选项外,组件中还可以像Vue实例那样使用其他的选项,比如data、computed、methods等。

但是在使用data时,data必须是函数,然后将数据return出去。

<my-component></my-component>
Vue.component('my-component',{
template:'<div>{{message}}/div>',
data:function(){
return {
message:'组件内容'
}
}
});
var app = new Vue({
el:'#app',
})

javascript对象是引用关系,所以如果return出的对象引用了外部的一个对象,那这个对象就是共享的,任意一方修改皆会改变。


<my-component></my-component>
<my-component></my-component>
<my-component></my-component>
Vue.component('my-component',{
template:'<button @click="counter++">{{counter}}</button>',
data:function(){
return data;
}
});
var app = new Vue({
el:'#app',
})

组件使用了3次,每次点击button,3个数字都会加1,因为data引用了外部对象,可以,给组件返回一个新的data 对象来独立。


<my-component></my-component>
<my-component></my-component>
<my-component></my-component>
Vue.component('my-component',{
template:'<button @click="counter++">{{counter}}</button>',
data:function(){
var data={
counter:0
};
}
});
var app = new Vue({
el:'#app',
})

注:data 必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:

data: function () {
return {
count: 0
}
}

二、使用props传递数据
1、基本用法
组件不仅要把模板的内容进行复用,更重要的是组件间进行通信。

通常父组件的模板中包含子组件,父组件要正向地向子组件传递数据或参数,子组件接收后根据参数的不同渲染不同效果。这个正向传递数据的过程通过props来实现。

在组件中,使用选项props声明需要从父级接收的数据,props的值可以是两种,一种是字符串数组,一种是对象。

<my-component message="来自父组件的数据"></my-component>
Vue.component('my-component',{
props:{'message'},
template:'<div>{{message}}</div>',
});
var app = new Vue({
el:'#app',
})

props中声明的数据组件data函数中return的数据主要区别:
props的数据来自父级;
data中的是组件自己的数据,作用域是组件本身;
这两种数据都可以在模板template计算属性computed方法methods中使用。

由于HTML特性不区分大小写,当使用DOM模板时,驼峰命名的props名称要转为短横线分割命名。

<my-component warning-text="提示信息"></my-component>

传递的数据来自父级的动态数据时,使用指令v-bind动态绑定props的值,当父组件的数据变化时,也会传递子组件

<div id="app">
<input type="text" v-model="parentMessage">
<my-component :message="parentMessage"></my-component>
</div>
props: ['message'],
template: `<div>{{message}}</div>`,
data: {
parentMessage: ''
}

这里用v-model绑定了父级的数据parentMessage,当通过输入框任意输入时,子组件接收到的props["message"]也会实时响应,并更新组件模板。

2、单向数据流
Vue2.X通过props传递数据是单向的,父组件数值变化可以传递到子组件,反过来不行。

业务中有 两种需要改变prop的情况,一种是父组件传递初始值进来,子组件将它作为初始值保存起来,在自己的作用域下可以随意使用和修改。这种情况要在组件data内声明一个数据,引用父组件的prop。

 <my-component :init-count="1"></my-component>
Vue.component('my-component', {
props: ['initCount'],
template: `<div>{{count}}</div>`,
data() {
return {
count:this.initCount
}
}
});

组件中声明了数据count,在初始化时会获取父组件的initCount,之后就与之无关了,只用维护count,可以避免直接操作initCount

另一种情况就是prop作为需要被转变的原始值传入,这种下需要用计算属性就可以。

<div id="app">
<my-component :width="100"></my-component>
</div>
Vue.component('my-component', {
props: ['width'],
template: `<div :style="style">组件内容</div>`,
computed: {
style: function () {
return {
width: this.width + 'px'
}
}
}
});

因为用CSS传递宽度要带单位(px),数值计算一般不带单位,所以统一在组件内使用计算属性。

在JavaScript中对象和数组时引用类型,指向同一个内存空间,所以props是对象和数组时,在子组件内改变是会影响父组件。

3、数组验证
当prop需要验证时,需要对象写法。

Vue.component('my-component', {
props: {
// 必须是数字
propA: Number,
// 必须是字符串或数字类型
propB: [String, Number],
// 布尔值,如果没有定义,默认值是true
propC: {
type: Boolean,
default: true
},
// 数字,而且是必传
propD: {
type: Number,
default: true
},
// 如果是数组或对象,默认值必须是一个函数来返回
propE: {
type: Array,
default: function () {
return []
}
},
// 自定义一个验证函数
propF: {
validator: function (value) {
return value > 10
}
}
}
});

验证的type类型可以是:

String
Number
Boolean
Object
Array
Function

type也可以是一个自定义构造器,使用instanceof检测。

三、组件通信
组件关系可分为父组件通信、兄弟组件通信、跨级组件通信。
1、自定义事件
当子组件需要向父组件传递数据时,就要用到自定义事件。
v-on除了监听DOM事件外,还可以用于组件之间的自定义事件。
JavaScript的设计模式——观察者模式方法:

  • dispatchEvent
  • addEventListener

Vue组件的子组件用 e m i t ( ) 来 触 发 事 件 , 父 组 件 用 emit()来触发事件,父组件用 emit()on()来监听子组件的事件。

父组件也可以直接在子组件的自定义标签上使用v-on来监听子组件触发的自定义事件。

<div id="app">
<p>总数:{{total}}</p>
<my-component
@increase="handleGetTotal" @reduce="handleGetTotal"></my-component>
</div>
Vue.component('my-component', {
template: `
<div>
<button @click="handleIncrease">+</button>
<button @click="handlereduce">-</button>
</div>
`,
data() {
return {
counter: 0
}
},
methods: {
handleIncrease: function () {
this.counter++;
this.$emit('increase', this.counter);
},
handlereduce: function () {
this.counter--;
this.$emit('reduce', this.counter)
}
}
});
new Vue({
el: '#app',
data: {
total: 0
},
methods: {
handleGetTotal: function (total) {
this.total = total;
}
}
});

在改变组件的data "counter"后,通过 e m i t ( ) 再 把 它 传 递 给 父 组 件 , 父 组 件 用 @ i n c r e a s e 和 @ r e d u c e 。 emit()再把它传递给父组件,父组件用@increase和@reduce。 emit()@increase@reduceemit()方法的第一个参数是自定义事件的名称。

除了用v-on在组件上监听自定义事件外,也可以监听DOM事件,这时可以用.native修饰符表示监听时一个原生事件,监听的是该组件的根元素。

<my-component @click:native="handleClick"></my-component>

2、使用v-model
Vue可以在自定义组件上使用v-model指令。

<my-component v-model="total"></my-component>

组件$emit()的事件名时特殊的input,在使用组件的父级,并没有在<my-component>上使用@input="handler",而是直接用了v-model绑定的一个数据total

<my-component @input="handleGetTotal"></my-component>

v-model还可以用来创建自定义的表单输入组件,进行数据双向绑定。

<div id="app">
<p>总数:{{total}}</p>
<my-component v-model="total"></my-component>
<button @click="handleReduce">-</button>
</div>
Vue.component('my-component', {
props: ['value'],
template: `<input :value="value" @input="updateValue">`,
methods: {
updateValue: function () {
this.$emit('input', event.target.value)
}
}
});
new Vue({
el: '#app',
data: {
total: 10
},
methods: {
handleReduce: function () {
this.total--;
}
}
});

实现这样一个具有双向绑定的v-model组件要满足下面两个要求:

  1. 接收一个value属性
  2. 在有新的value时触发input事件

3、非父子组件通信
在实际业务中,除了父子组件通信外,还有很多非父子组件通信的场景,非父子组件一般有两种,兄弟组件和跨多级组件。

在Vue 1.x版本中,除了$emit()方法外,还提供了¥dispatch()$broadcast()

$dispatch()用于向上级派发事件,只要是它的父级(一级或多级以上),都可以在Vue实例的events选项内接收。
此实例只在Vue 1.x版本中有效:

<div id="app">
<p>{{message}}</p>
<my-component></my-component>
</div>
Vue.component('my-component', {
template: `<button @click="handleDispatch">派发事件</button>`,
methods: {
handleDispatch: function () {
this.$dispatch('on-message', '来自内部组件的数据')
}
}
});
new Vue({
el: '#app',
data: {
message: ''
},
events: {
'on-message': function (msg) {
this.message = msg;
}
}
});

这些方法在Vue 2.x版本中已废弃。
在Vue 2.x中,推荐任何一个空的Vue实例作为中央事件总线(bus),也就是一个中介。

<div id="app">
<p>{{message}}</p>
<component-a></component-a>
</div>
var bus = new Vue();
Vue.component('component-a', {
template: `<button @click="handleEvent">传递事件</button>`,
methods: {
handleEvent: function () {
bus.$emit('on-message', '来自组件component-a的内容')
}
}
});
var app = new Vue({
el: '#app',
data: {
message: ''
},
mounted: function () {
var _this = this;
// 在实例初始化时,监听来自bus实例的事件
bus.$on('on-message', function (msg) {
_this.message = msg;
})
}
});

这种方法巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级。
除了中央事件总线bus外,还有两种方法可以实现组件间通信:父链和子组件索引。
父链
在子组件中,使用this.$parent可以直接访问该组件的父实例或组件,父组件也可以通过this.$children访问它所有的子组件,而且可以递归向上或向下无限访问,直到根实例或最内层的组件。

<div id="app">
<p>{{message}}</p>
<component-a></component-a>
</div>
Vue.component('component-a', {
template: `<button @click="handleEvent">通过父链直接修改数据</button>`,
methods: {
handleEvent: function () {
this.$parent.message = '来自组件component-a的内容'
}
}
});
var app = new Vue({
el: '#app',
data: {
message: ''
}
});
  • 父子组件最好还是通过props和$emit()来通信。

子组件索引
当子组件较多时,通过this.$children来遍历出需要的一个组件实例是比较困难的,尤其是组件动态渲染时,它们的序列是不固定的。

Vue提供了子组件索引的方法,用特殊的属性ref来为子组件指定一个索引名称。

<div id="app">
<button @click="handleRef">通过ref获取子组件实例</button>
<component-a ref="comA"></component-a>
</div>
Vue.component('component-a', {
template: `<div>子组件</div>`,
data() {
return {
message: '子组件内容'
}
},
});
var app = new Vue({
el: '#app',
methods: {
handleRef: function () {
// 通过$refs来访问指定的实例
var msg = this.$refs.comA.message;
console.log(msg);
}
}
});

在父组件模板中,子组件标签上使用ref指定一个名称,并在父组件内通过this.$refs来访问指定名称的子组件。

r e f s 只 在 组 件 渲 染 完 成 后 才 填 充 , 并 且 它 是 非 响 应 式 的 。 它 仅 仅 作 为 一 个 直 接 访 问 子 组 件 的 应 急 方 案 , 应 当 避 免 在 模 板 或 计 算 属 性 中 使 用 refs只在组件渲染完成后才填充,并且它是非响应式的。它仅仅作为一个直接访问子组件的应急方案,应当避免在模板或计算属性中使用 refs访使refs。

Vue 2.x将v-el和v-ref合并成ref,Vue会自动去判断是普通标签还是组件。

最后

以上就是暴躁凉面为你收集整理的vue基础篇- 组件详解(第七章)(一)的全部内容,希望文章能够帮你解决vue基础篇- 组件详解(第七章)(一)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(45)

评论列表共有 0 条评论

立即
投稿
返回
顶部