效果
问题
在开发级联选择器的时候出现了一个问题
1、首先在选择框上,我是通过递归数据options,给其添加上后面级联时所需要的数据
// 初始化处理(设置层级id, 设置上一级指向)
initHandler(parent, obj, index) {
// 层级
obj.uid = index;
// 指向上一级的指针
obj.pre = parent;
// 默认没有选中
obj.select = false;
// 有子元素则继续初始化处理
if (obj.children) {
obj.children.forEach(child => {
this.initHandler(obj, child, index + 1)
})
}
return obj;
},
watch: {
options: {
handler(newV) {
if (!newV.length) return;
this.frist.child = newV.map(child => {
// 初始化数据
return this.initHandler(null, child, 1)
});
}, immediate: true, deep: true
},
}
后面当我点击对应的子项时,子项会通过provide/inject给根组件触发一个点击事件,在根组件中对数据进行选中方面的修改。但是修改时却发现后代项无法监听到数据的更改(涉及到多个组件的嵌套)
调试后发现是因为根组件是将数据列表发送给组件1, 而组件1将数据列表的每一项中的数据发送给组件2
这个过程中根组件的数据列表是响应式的, 在传递给子组件后,因为本身是响应式数组的元素,其不是响应式,所以组件2接受到的数据并不是响应式。
解决 通过Object.assign()混入,将非响应数据混入到一个响应的空对象,再将响应式对象发送到组件2
deepList: {
get() {
return this.data.child.map(child => {
// 问题
// 这里如果传递不加处理的child到deep组件时会出现deep无法监听到父组件更新的清况
// 因为这里的child是响应式数组的元素,本身不是响应式的,所以deep无法监听child内部变化
// 解决 混入
// 通过assign合并对象, 将响应式的{}与非响应式的child合并得到一个响应式的对象
// deep就可以监听到child内部的变化
return Object.assign({}, child)
})
}
}
2、还有再点击展开弹窗时应该在点击其他位置时关闭弹窗
这里使用了自定义指令
<!-- 弹出 -->
<div class="Eject" v-if="isPop" v-clickOutside="handlerOutside">
......
</div>
methods:{
...
// 点击非当前元素触发
handlerOutside() {
this.isPop = false
}
...
}
指令////
export default {
name: 'clickOutside',
directive: {
bind(el, binding) {
// 点击非当前组件触发
function clickOutSideHandler(e) {
// 判断当前元素是否是在外部触发点击
/*
el.contains(e.target) 检测某元素是否包含在另一元素
*/
if (el.contains(e.target)) {// 触发元素在某元素内
return false
}
// 触发元素在某元素内
if (binding.value && typeof binding.value == 'function') binding.value(e)
}
// 在el上绑定方法
el.outSide = clickOutSideHandler;
// 注册全文档页面的点击事件
document.addEventListener('click', clickOutSideHandler)
},
unbind(el) {
// 指令绑定元素卸载时卸载事件, 同时清空el上的属性
document.removeEventListener('click', el.outSide)
el.outSide = null
}
}
}