自定义事件及事件总线
父子组件自定义事件
- 子组件:
this.$emit("my-event")
发送事件 - 父组件:
<dialog-component @dialog-closed="eventHandler" />
监听事件
事件总线
可以将事件发送到同级、祖父母、层次结构中的任何其他组件
为此,我们可以使用一种称为事件总线的模式。在这里,我们创建了一个单独的Vue实例,以将事件传输到导入该事件的任何组件。
eventBus.js:
// 首先,在新的模块文件中创建并导出Vue实例:
import Vue from 'vue'
export default new Vue()
HelloWorld.vue:
// 接下来,将总线导入到您要发出事件的组件中。您可以使用$emit总线Vue实例的方法。
<template>
<div>
<button @click="handleClick">按钮</button>
</div>
</template>
<script>
import EventBus from './eventBus.js'
export default {
data () {
return {}
},
methods: {
handleClick () {
EventBus.$emit('bus-emit')
}
}
}
</script>
Home.vue:
// 最后,将总线导入到您想听事件的组件中。然后,您应该在代码中的某个位置设置侦听器。我建议您使用生命周期挂钩,就像created您可以在此处访问组件实例一样。
<script>
import EventBus from './eventBus.js'
export default {
name: 'Home',
created () {
EventBus.$on('bus-emit', () => {
console.log('监听到了')
})
}
}
</script>
长列表性能优化(Object.freeze)
一个大的数据对象里,在你确信它不需要改变的时候,你可以给他freeze(),可以大大的增加性能。
也可用作冻结线上的配置文件中的对象,以防有人误改。
被冻结的对象不能修改、添加、删除其属性或者属性值
freeze冻结的是堆内存中的值,和栈中的引用无关。
data () {
return{
obj: {}
}
},
mounted () {
const obj1 = await axios.get('/user')
this.obj = Object.freeze(obj1)
},
项目当中,会涉及到非常多的长列表场景,区别于普通的分页来说,大部分的前端在做这种 无限列表 的时候,大部分新手前端都是通过一个 vFor 将数据遍历出来,想的多一点的就是做一个分页。滚动到底部的时候就继续请求 API 。其实这也是未思考妥当的。随着数据的加载,DOM会越来越多,这样就导致了性能开销的问题产生了,当页面上的DOM太多的时候,难免给我的客户端造成一定的压力,所以对于长列表渲染的时候,建议将DOM移除掉,类似于图片懒加载的模式,只有出现在视图上的DOM才是重要的DOM。网络上有一些很好的解决方案,如 vue-virtual-scroller 库等等,大家可以理性的选择。
函数式组件
函数式组件是一种stateless和instanceless的组件,它内部没有生命周期处理方式,因而非常轻量,渲染性极高,当需要创建的组件只需要根据外部数据的变化而变化时,就可以将其创建为函数式组件。
写法:
- 在 template标签里面标明 functional
- 只接受 props值
- 不需要 script标签
代码:
父组件:
<template>
<div>
<Child :list="list" :item-click="handleClick"></Child>
</div>
</template>
<script>
import Child from './Child.vue'
export default {
components: {
Child
},
data () {
return {
list: [1, 2, 3, 4]
}
},
methods: {
handleClick (val) {
console.log(val) // 接收子组件传递的数据
}
}
}
</script>
子组件:
<template functional>
<div>
<ul>
{{props}}
<li v-for="item in props.list" @click="props.itemClick(item)">
{{item}}
</li>
</ul>
</div>
</template>
作用域插槽
普通插槽、具名插槽及作用域插槽的理解:
- 普通插槽就是父组件中可以传递任意的内容到子组件,子组件中用slot接收接口,数据流是父组件到-子组件
- 具名插槽就是父组件用slot标识,在子组件中通过name指定位置显示,数据流是服务间-子组件
- 作用域插槽是:在作用域插槽内,父组件可以拿到子组件的数据。子组件可以在slot标签上绑定属性值数据。
子组件
// Detail.vue
<template>
<div>
<slot say="hello" :userInfo="userInfo"></slot>
</div>
</template>
<script>
export default {
data () {
return {
userInfo: {
name: 'zs',
age: 23
}
}
}
}
</script>
父组件
<Detail>
<template slot-scope="data">
{{data}}
</template>
</Detail>
效果: