一、 vue组件传值之事件总线(EventBus)
1、初始化
其实事件总线就是vue的一个实例,也就是在这种情况下被称作为EventBus,让后将这个实例导出就可以使用了。定义如下:
import Vue from 'vue'
export default new Vue()
淡然啦,我们也可以直接在main.js中直接初始化,这样初始化的就是全部的事件总线了。
// main.js
Vue.prototype.$EventBus = new Vue()
现在EventBus已经创建好了,接下来就是需要再你的组件中引入,调用事件的方法就可以使用了。
2、发送事件
发送事件使用的就是$emit,接受两个参数,一个是事件名称,一个是参数,这里以ElementUI侧边栏菜单的折叠为例子:
<template>
<div class="header">
<div class="header-logo">
<img alt="Vue logo" src="../../assets/images/common/logo.png" @click="changeCollapse">
</div>
</div>
</template>
<script>
import bus from '@/utils/eventBus.js'
export default {
data() {
return {
collapse: false
}
},
methods: {
changeCollapse(){
this.collapse = !this.collapse
bus.$emit('collapse', this.collapse)
}
}
}
</script>
上面的例子就是当我们点击log的时候来切换侧边栏菜单的折叠的,这是在顶部组件中,那么要控制侧边栏组件的折叠显然直接是不可能的,所以这里就使用了vue事件总线来实现的。上面的发送事件也很简单,就是事件名称为collapse,参数就是当前data中定义的collapse了。
3、接受事件
接受事件就是使用$on来接受,当顶部组件改变的时候也会通知到这里的,所以使用起来还是很方便的吧。例子如下:
<template>
<div class="sidebar">
<el-scrollbar class="scroll-wrapper">
<el-menu class="sidebar-el-menu" :default-active="$route.path" :collapse="collapse" unique-opened router>
<subItem :items="items" :collapse="collapse" />
</el-menu>
</el-scrollbar>
<div class="slideIn" @click="changeCollapse">||</div>
</div>
</template>
<script>
import bus from "@/utils/eventBus.js"
import subItem from "./subitem"
export default {
props:['items'],
data() {
return {
collapse: false
}
},
created() {
bus.$on("collapse", msg => {
this.collapse = msg
})
},
methods: {
changeCollapse() {
this.collapse = !this.collapse
bus.$emit("collapse", this.collapse)
}
}
}
</script>
上面的例子中当改变折叠状态时,也会发送相应的事件通知事件中心,如果有其他地方使用到也会随着这里的改变改变。
4、移除事件
移除事件可使用$off,如果想单独移除某一个事件的监听就可以使用第一个参数即为事件名称,如果想全部移除不带任何参数即可。例子如下:
<script>
import bus from "@/utils/eventBus.js"
export default {
methods: {
handleClick() {
bus.$off("collapse", {}) // 移除单个事件
// bus.$off() // 移除全部事件
}
}
}
</script>
二、vue的keep-alive之缓存组件状态
会缓存不活动的组件的状态。
作用:避免多次重复渲染降低性能
1、include 字符串或正则表达式。只有名称匹配的组件会被缓存
<keep-alive include="路由">
<router-view />
</keep-alive>
2、exclude 字符串或正则表达式。任何名称匹配的组件都不会被缓存
<keep-alive exclude="路由">
<router-view />
</keep-alive>
3、max 数字。最多可以缓存多少组件实例
<keep-alive include="路由">
<router-view />
</keep-alive>
4、结合router,缓存部分页面 $route.meta.keepAlive
配置路由页面
{
path: 'home',
name: '主页',
component: () => import("@/views/home/home.vue"),
meta:{
keepAlive:true
}
},
主页面
<keep-alive>
<router-view v-if="$route.meta.keepAlive" />
</keep-alive>
<router-view v-if="!$route.meta.keepAlive" />
三、vueJs的provide和inject父子组件传值?
provide 和 inject
提供 / 注入
用处: 父组件可以向其所有子组件传入数据,而“不管子组件层次结构有多深”
特性: 父组件有一个provide选项来提供数据 子组件有一个inject选项来开始使用这个数据
参考组件层级 index组件 _a组件 _b组件
props方式传值:index-->a-->b
provide/inject方式传值 index-->a index-->b
index组件 js
export default{
provide:{
text:this.msg
}
data(){
msg:"index组件内容"
}
}
a组件 js
export default{
inject:["text"]
data(){
msg:this.text
}
}
四、 vue表格合并单元格
需求
vue表格同列不同行的相同内容合并单元格,直接看图更直观。
原表格
效果
很明显,后一列的合并项受前一项的合并项的限制。
实现
废话不多说,直接上代码
<template>
<div class="table_box">
<table class="table">
<thead>
<tr>
<th>序号</th>
<th>名字</th>
<th>性别</th>
<th>年龄</th>
<th>地址</th>
<th>兴趣</th>
<th>电话</th>
</tr>
</thead>
<tbody>
<tr v-for="(item, index) in data" :key="index">
<td>{{index}}</td>
<td ref="td">{{item.name}}</td>
<td ref="td">{{item.sex}}</td>
<td ref="td">{{item.age}}</td>
<td ref="td">{{item.address}}</td>
<td ref="td">{{item.habit}}</td>
<td ref="td">{{item.tel}}</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
data: [
{name: '小明', sex: '男', age: '24', address: '湖北', habit: '篮球', tel: '15927001701'},
{name: '小明', sex: '男', age: '24', address: '湖北', habit: '篮球', tel: '15927001702'},
{name: '小明', sex: '男', age: '24', address: '湖北', habit: '足球', tel: '15927001703'},
{name: '小明', sex: '男', age: '24', address: '湖南', habit: '篮球', tel: '15927001704'},
{name: '小明', sex: '男', age: '23', address: '湖南', habit: '篮球', tel: '15927001705'},
{name: '小明', sex: '男', age: '23', address: '湖北', habit: '篮球', tel: '15927001706'},
{name: '小明', sex: '男', age: '24', address: '湖北', habit: '篮球', tel: '15927001707'},
{name: '小明', sex: '女', age: '24', address: '湖北', habit: '篮球', tel: '15927001708'},
{name: '小红', sex: '女', age: '24', address: '湖北', habit: '篮球', tel: '15927001709'},
{name: '小红', sex: '女', age: '24', address: '湖南', habit: '篮球', tel: '15927001700'}
]
}
},
mounted() {
this.merge()
},
methods: {
merge()
// 如果数据是乱序,整理顺序,按自己的数据结构排序
// this.data.sort((a,b) => {
// return JSON.stringify(a) >=JSON.stringify(b)?1:-1;
// })
// console.log(this.data)
this.$nextTick(() => {
var tds = this.$refs.td;
console.log(tds)
let n=0; // 每次合并单元格从第几行开始合并
for(let col=0,collen=6; col<collen;col++) {
n=0;
for(let row=0,len=this.data.length; row<len;row++) {
if(n!=row && tds[col+n*collen].innerHTML == tds[col+row*collen].innerHTML) {
if(col!=0) {
if(tds[col+row*collen-1].rowSpan == 0){ // 前一列被合并,才能进行此列合并
tds[col+n*collen].rowSpan = tds[col+n*collen].rowSpan + 1;
tds[col+row*collen].rowSpan = 0;
tds[col+row*collen].hidden = true;
}else {
n=row; // 合并中止,重置开始合并行
}
}else {
tds[col+n*collen].rowSpan = tds[col+n*collen].rowSpan + 1;
tds[col+row*collen].rowSpan = 0;
tds[col+row*collen].hidden = true;
}
}else {
n=row; // 合并中止,重置开始合并行
}
}
}
})
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped lang="less">
.table_box{
.table{
border: 1px solid #cccccc;
border-collapse: collapse;
th{
// align-items: center;
padding: 10px 20px;
border: 1px solid #cccccc;
text-align: left;
}
td{
padding: 10px 20px;
border: 1px solid #cccccc;
text-align: left;
}
}
}
</style>