本篇绪论
1,vue处理边界之emit、
root、
children的使用
2,vue父子通信
3,js中的 ...(展开运算符/剩余运算符)
1,vue处理边界之
emit、
root、
children的使用
$refs: 父组件调用子组件的方法并传递数据
父组件
<Son :sendData="string" ref="child"/>
<div @click="getMyEvent">点击父组件</div>
getMyEvent() {
this.$refs.child.sonEvent('我是父组件中的数据') // sonEvent是子组件的方法
}
子组件
<button @click="sonEvent"></button>
sonEvent(val) {
console.log(`接收到的数据-------->${val}`)
}
$emit: 子组件调用父组件的方法并传递参数
父组件
<Son :sendData="string" @myEvent="getMyEvent"/>
methods: {
getMyEvent (val) {
console.log(val) // [1,2,3,4,5]
}
}
子组件
<div @click="emitEvent">send</div>
methods: {
emitEvent () {
let arr = [1,2,3,4,5]
this.$emit('myEvent', arr)
}
}
$on:兄弟组件之间相互传递数据
首先创建一个空白(bus.js)实例(兄弟间的桥梁),兄弟组件都引入它
import Vue from 'vue'
export default new Vue()
A组件
<div @click="sendData">把A组件传给B</div>
sendData() {
bus.$emit('event', this.datas) // $emit自定义事件把数据传过去
}
B组件
mounted() {
bus.$on('event', (val) => {
console.log(val)
})
}
$root
vue子组件可以通过$root属性访问到根父组件实例的属性和方法
console.log(this.$root.$el) // <div id="app"></div>
$parent
vue子组件可以通过$parent属性访问最近一级的父组件
$children
vue父组件可以通过$child属性访问最近一级的子组件
2,vue父子通信
- 1,props
- 2,$emit
- 3,.sync修饰符(语法糖)
- 4,
listeners
- 5,provide、inject
- 6, vuex
- 7, eventBus
props
// 父组件
<Son :sendMsg="msg"/>
// 子组件
props: ['sendMsg']
$emit
$emit触发当前实例上的事件,附加参数都会传给监听回调
// 父组件
<Son @greet="sayHi"/>
sayHi(val) {console.log(val) // [1,2,3,4,5]}
// 子组件
<div @click="event">触发事件</div>
event() {
this.$emit('greet', [1,2,3,4,5])
}
.sync修饰符(语法糖)
.sync作为一个编译时的语法糖存在,我们可以手动更新父组件中的值,从而使数据改动来源更加的明显。引入官方的话:有些情况下,我们可能需要对一个prop进行双向绑定,不幸的是,真正的双向绑定会带来维护上的问题,因为子组件可以修改父组件,且在父组件和子组件都没有明显的改动来源。
既然作为一个愈发糖,肯定是某种写法的简写形式,哪种写法呢,看代码:
<text-document
v-bind:title="doc.title"
v-on:update:title="doc.title = $event"
></text-document>
为什么方便起见,我们为这种模式提供一个缩写, 即 .sync 修饰符
看实例:
// 父组件
<div>{{name}}</div>
<Son :foo="name" @update:foo="(val) => name = val"/>
name: 'xiaowang'
// 子组件
<div @click="$emit('update:foo', 'dawang')">更新事件</div>
// $emit('uodate:foo') foo表示要更新的 prop 值。
以上代码简写:
<Son :foo.sync="name"/>
属性attrs、$listeners
官网对$attrs的解释如下:
包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。
官网对$listeners的解释如下:
包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。
看实例:
// 父组件
<Son :foo="foo" :bar="bar" @one.native="triggerOne" @two="triggerTwo"/>
foo: 'foo---',
bar: 'bar---'
triggerOne(){
console.log('triggerOne')
},
triggerTwo(){
console.log('triggerTwo')
}
// 子组件
props: ['foo'],
created () {
console.log(this.$attrs)
console.log(this.$listeners)
},

可以理解为
listeners收集所有的事件(除.native修饰符外的事件),且都是以对象的形式来保存数据。
以上代码可以看出我们可以通过listeners进行数据传递,在需要的地方进行调用和处理。
当我们在组件上赋予一个非prop声明时,编译之后的代码会把这个属性当成原始属性对待,添加到html原生标签上,以上代码会被编译为:
// 子组件
<h2>{{this.$attrs.bar}}</h2>

这样会很难看,同时也爆了某些东西,这就到了 inheritAttrs 的用武之地了,给组件加上这个属性就行了,看代码:
export default {
inheritAttrs: false, // 默认为true
}
再次编译:

provide / inject
这对选项需要一起使用
看实例:
// 父组件
export default {
provide: {
name: 'Jerry',
age: 18
}
}
// 子组件
export default {
inject: {
name: {
default: 'Tom'
},
age: {
default: 10
}
}
}
created () {
console.log(this.name) // Jerry
console.log(this.age) // 18
}
vuex
vuex可参考我的文章【面试题Day07】,这里就不做解释了
eventBus
策略是声明一个全局vue实例变量eventBus,把所有的通信数据、事件监听都存储到这个变量上。这样就达到在组件间数据共享了,有点类似vuex。这种方式只适用于极小的项目,复杂项目还是推荐vuex。看实例:
// main.js
Vue.prototype.$EventBus = new Vue() // 将eventBus绑定到vue实例的原型上,也可以直接绑定在window对象上 window.eventBus = new Vue() 使用的时候:eventBus.xx
// 父组件
this.$EventBus.message = 'hello world'
// 子组件
console.log(this.$EventBus.message)
3,js中的 ...(展开运算符/剩余运算符)
三个点 ... 具有两个含义:展开运算符和剩余运算符
我们知道对于引用类型来说赋值操作其实传递的只是这个对象的地址,意味着如果按照obj2 = obj1的写法,当obj1中的属性值改变,obj2的属性值也会相应的发生改变,即obj1和obj2两个变量指向了同一段内存地址。如果改为obj2 = {...obj1},由于obj1中的属性类型是基本类型,相当于新建了一个对象,此时改变obj1的属性值,obj2不受影响,某种意义上实现了对象之间的浅拷贝,但是仅限于其属性都为基本类型,或者说只是进行了一层的拷贝。
即当我们需要修改一个对象,但又不想改变原对象的时候,可以使用展开运算符进行拷贝。
展开运算符
展开运算符允许迭代器在接收器内部分别展开和扩展。迭代器和接收器可以是任何可以循环的对象(数组、对象、集合、映射等),可以把一个容器的每个部分放入到另一个容器。
const newObj = {name: 'xiaowang', ...obj}
剩余参数
剩余参数允许我们将无限数量的参数表示为数组。
const foo = (a, b, ...rest) => {
console.log(rest) // [3,4,5,6]
}
foo(1,2,3,4,5,6)
网友评论