上海做网站吧,wordpress默认分类链接,用wordpress建立电商网站,专门做墓志铭的网站需求背景
在日常开发中#xff0c;我们会遇见很多不同的业务需求。如果让你用element-ui实现一个 tree-select 组件#xff0c;你会怎么做#xff1f;
这个组件在 element-plus 中是有这个组件存在的#xff0c;但是在 element-ui 中是没有的。
可能你会直接使用 elemen…需求背景
在日常开发中我们会遇见很多不同的业务需求。如果让你用element-ui实现一个 tree-select 组件你会怎么做
这个组件在 element-plus 中是有这个组件存在的但是在 element-ui 中是没有的。
可能你会直接使用 element-plus 组件库或者其他组件库。但是若你的项目目前的基于vue2和element-ui进行开发的呢
下面这种思路利用 el-tree 和 el-select 进行嵌套从而实现我们想要的 tree-select 组件 最终效果 大致思路
el-select和el-tree进行嵌套将el-tree放到el-option里循环遍历el-option同时定义一个方法比如formatData对树形数据进行递归处理这样就可以实现无论嵌套的层级有几层都可以正常渲染在界面上 利用 v-model 和 update:selectValue 实现父子组件之间的双向通信同时利用computed进行监听以实现实时更新 组件中的 v-model
我们在input中可以使用v-model来完成双向绑定
这个时候往往会非常方便因为v-model默认会帮助我们完成两件事 v-bind:value的数据绑定和input的事件监听
如果我们现在封装了一个组件其他地方在使用这个组件时是否也可以使用v-model来同时完成这两个功能呢
当我们在组件上使用的时候等价于如下的操作
我们会发现和input元素不同的只是属性的名称和事件触发的名称而已 如果我们希望绑定多个属性呢
也就是我们希望在一个组件上使用多个v-model是否可以实现呢 我们知道默认情况下的v-model其实是绑定了 modelValue 属性和 update:modelValue的事件 如果我们希望绑定更多可以给v-model传入一个参数那么这个参数的名称就是我们绑定属性的名称
实现代码示例
子组件
templatedivh4Counter: {{modelValue}}/h4button clickchangeCounter修改数据/button/div
/templatescript
export default {props: {modelValue: {type: Number},},emits: [update:modelValue],methods: {changeCounter(){this.$emit(update:modelValue,101)}}
}
/script
父组件
template!-- child v-modelappCounter / --!-- 等同于如下做法modelValue--默认可以自定义名称通过 v-model:counter 类似于这种格式--child :modelValueappCounter update:modelValueappCounter $event /
/templatescript
import child from /components/child.vue
export default {components: {child},data() {return {appCounter: 100,};},methods: {},
};
/script
有了上面的知识那么下面实现就很简单了这里直接上代码 组件封装
子组件TreeSelect.vue
templatediv classapp-container stylepadding: 0el-selectclassmain-select-treerefselectTreev-modelvaluestylewidth: 240pxclearableclearclearSelectInputel-inputstylewidth: 220px; margin-left: 10px; margin-bottom: 10pxplaceholder输入关键字进行过滤v-modelfilterTextclearable/el-inputel-optionv-foritem in formatData(data):keyitem.value:labelitem.label:valueitem.valuestyledisplay: none/el-treeclassmain-select-el-treerefselecteltree:datadatanode-keyidhighlight-current:propsdefaultPropsnode-clickhandleNodeClick:current-node-keyvalue:expand-on-click-nodetruedefault-expand-all:filter-node-methodfilterNode//el-select/div
/templatescript
export default {props: {selectValue: {type: String,default: ,},},data() {return {filterText: ,value: ,data: [{id: 1,label: 云南,children: [{id: 2,label: 昆明,children: [{id: 3,label: 五华区,children: [{id: 8,label: xx街道,children: [{id: 81,label: yy社区,children: [{ id: 82, label: 北辰小区 }],},],},],},{ id: 4, label: 盘龙区 },],},],},{id: 5,label: 湖南,children: [{ id: 6, label: 长沙 },{ id: 7, label: 永州 },],},{id: 12,label: 重庆,children: [{ id: 10, label: 渝北 },{ id: 9, label: 合川 },],},{id: 13,label: 江苏,children: [{ id: 14, label: 盐城 }],},],defaultProps: {children: children,label: label,},};},watch: {filterText(val) {this.$refs.selecteltree.filter(val);},},methods: {filterNode(value, data) {if (!value) return true;return data.label.indexOf(value) ! -1;},// 递归遍历数据formatData(data) {let options [];const formatDataRecursive (data) {data.forEach((item) {options.push({ label: item.label, value: item.id });if (item.children item.children.length 0) {formatDataRecursive(item.children);}});};formatDataRecursive(data);return options;},// 点击事件handleNodeClick(node) {this.value node.id;this.$refs.selectTree.blur();this.$emit(update:selectValue, node.label);},// 清空事件clearSelectInput() {this.$emit(update:selectValue, );// 获取 el-tree 实例的引用const elTree this.$refs.selecteltree;// 将当前选中的节点设置为 nullelTree.setCurrentKey(null);},},
};
/scriptstyle
.main-select-el-tree .el-tree-node .is-current .el-tree-node__content {font-weight: bold;color: #409eff;
}
.main-select-el-tree .el-tree-node.is-current .el-tree-node__content {font-weight: bold;color: #409eff;
}
/style
使用方式
TreeSelect v-modelselectedValue update:selectValuehandleSelectValueChange/TreeSelectel-button sizemedium :disabledtodoIsTotal交接当前{{ tableData.length }}条任务/el-buttonimport TreeSelect from ./TreeSelect.vue;export default {components: {TreeSelect,},data() {selectedValue: ,},computed: {todoIsTotal() {return this.selectedValue ;},},methods: {handleSelectValueChange(value) {if (value value.length 0) {this.selectedValue value;} else {this.selectedValue ;}},},
}