1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > cascader 动态加载 回显_ElementUI cascader级联动态加载回显和搜索看这个就够了

cascader 动态加载 回显_ElementUI cascader级联动态加载回显和搜索看这个就够了

时间:2019-06-29 12:13:32

相关推荐

cascader 动态加载 回显_ElementUI cascader级联动态加载回显和搜索看这个就够了

这一篇是上一次讨论cascader级联动态加载回显问题的延续,文末有链接。

以下是思考和开发的过程,不感兴趣可以直接看使用文档。

/zhuss/lazy-cascader​

为什么要再写一篇呢?

当然不是思想觉悟有多高,还不是因为产品提的需求,产品哭哭唧唧的说:“类目太多啦,我要有一个搜索的功能。”

一开始我是拒绝的,毕竟上一次为了解决回显问题,耗费了一波本来就不多的头发,可是后来想一想,都是打工人,打工人和打工人应该是相亲相爱的一家人。

既然接下这个锅,那就想办法解决吧。

最开始,延续的原有的思路,既然回显可以,那搜索应该也不在话下,所以就埋头去研究官方文档,然后发现了 filter-method 和 before-filter 这两个方法。

尝试过之后就pass掉了filter-method,这个只是在选择的时候判断节点是否匹配,不适合动态请求和处理数据。

而 before-filter 方法是可以的,而且文档写的比较明确。

筛选之前的钩子,参数为输入的值,若返回 false 或者返回 Promise 且被 reject,则停止筛选

如果我们在方法中根据输入值去请求后端接口,拿到一组备选项,然后根据拿到的备选项动态更新我们的options参数,那么就可以在组件中筛选出我们想要的节点了吧,至于动态更新options的方法,可以同上一篇的回显逻辑类似。

按照这个思路,同事在一番倒腾之后,确实可以实现动态搜索的需求。

但是,这样处理是有不足的地方的。

1、产品设计的UI和ElementUI的组件并不一致,交互方式也不一样。

2、在动态更新options参数的时候会动态请求很多节点数据,而这些节点大部分都是不需要展示的。

所以,为了解决这两个问题,我又陷入的沉思,甚至想不看ElementUI手动撸一个组件(想想而已)。

那既然原有组件在UI上没办满足产品需求,那我们就自己写这个UI吧,顺着这个思路,那我们就需要用到一个关键的东西,级联面板。

因为上图UI的组成部分就这么几个东西。

输入框Popover 弹出框搜索选择框级联选择面板

级联选择面板的值仅仅是一个数据,也就是节点id的路径数组,那我们就必须根据这个值,然后遍历options得到对应的label的数组,显示在输入框中。

通过搜索拿到的数据也可以拿到一个节点的值。

那么我们只需要根据值的变化,动态请求需求展示的节点,获取到对应的label即可。

于是就有了最紧要的一段代码。

html

/**格式化id=>object */async getObject(id) {let options = this.options;let nameArray = [];for (let i = 0; i < id.length; i++) {let index = options.findIndex(item => {return item[this.props.value] == id[i];});nameArray.push(options[index][this.props.label]);if (i < id.length - 1 && options[index].children == undefined) {let list = new Promise(resolve => {this.props.lazyLoad(id[i], list => {resolve(list);});});this.$set(options[index], "children", await list);options = options[index].children;} else {options = options[index].children;}}return {value: id, label: nameArray };}

解决了这个问题,基本上就已经实现了回显了。

至于搜索,直接用的ElementUI的组件autocomplete就可以了,最后在仿照cascader的参数封装这个组件的,把需要的参数暴露出去就可以了。

完整的代码看下

<template><div class="lazy-cascader" :style="{ width: width }"><!-- 禁用状态 --><divv-if="disabled"class="el-input__inner lazy-cascader-input lazy-cascader-input-disabled"><span class="lazy-cascader-placeholder" v-show="placeholderVisible">{{ placeholder }}</span><div class="lazy-cascader-tags" v-if="props.multiple"><el-tagclass="lazy-cascader-tag"type="info"disable-transitionsv-for="(item, index) in labelArray":key="index"closable><span> {{ item.label.join(separator) }}</span></el-tag></div><div class="lazy-cascader-label" v-else><el-tooltipplacement="top-start":content="labelObject.label.join(separator)"><span>{{ labelObject.label.join(separator) }}</span></el-tooltip></div></div><!-- 禁用状态 --><!-- 可选状态 --><el-popover v-else trigger="click" placement="bottom-start" ref="popover"><!-- 搜索 --><div class="lazy-cascader-search"><el-autocomplete:style="{ width: width }"v-if="filterable"class="inline-input"prefix-icon="el-icon-search"label="name"v-model="keyword":fetch-suggestions="querySearch":trigger-on-focus="false"placeholder="请输入"@select="handleSelect"><template slot-scope="{ item }"><div class="name">{{ item[props.label].join(separator) }}</div></template></el-autocomplete></div><!-- 搜索 --><!-- 级联面板 --><div class="lazy-cascader-panel"><el-cascader-panelref="panel"v-model="current":options="options":props="currentProps"@change="change"></el-cascader-panel></div><!-- 级联面板 --><!--内容区域--><divclass="el-input__inner lazy-cascader-input":class="disabled ? 'lazy-cascader-input-disabled' : ''"slot="reference"><span class="lazy-cascader-placeholder" v-show="placeholderVisible">{{ placeholder }}</span><div class="lazy-cascader-tags" v-if="props.multiple"><el-tagclass="lazy-cascader-tag"type="info"disable-transitionsv-for="(item, index) in labelArray":key="index"closable@close="handleClose(item)"><span> {{ item.label.join(separator) }}</span></el-tag></div><div class="lazy-cascader-label" v-else><el-tooltipplacement="top-start":content="labelObject.label.join(separator)"><span>{{ labelObject.label.join(separator) }}</span></el-tooltip></div></div><!--内容区域--></el-popover><!-- 可选状态 --></div></template>

js

export default {props: {value: {type: Array,default: () => {return [];}},separator: {type: String,default: " > "},placeholder: {type: String,default: "请选择"},width: {type: String,default: "400px"},filterable: Boolean,disabled: Boolean,props: {type: Object,default: () => {return {};}}},data() {return {keyword: "",options: [],current: [],labelObject: {label: [], value: [] },labelArray: [],currentProps: {multiple: this.props.multiple,checkStrictly: this.props.checkStrictly,value: this.props.value,label: this.props.label,leaf: this.props.leaf,lazy: true,lazyLoad: this.lazyLoad}};},computed: {placeholderVisible() {if (this.current) {return this.current.length == 0;} else {return true;}}},watch: {current() {this.getLabelArray();},value(v) {this.current = v;}},created() {this.initOptions();},methods: {//搜索querySearch(query, callback) {this.props.lazySearch(query, list => {callback(list);});},//选中搜索下拉搜索项handleSelect(item) {if (this.props.multiple) {let index = this.current.findIndex(obj => {return obj.join() == item[this.props.value].join();});if (index == -1) {this.current.push(item[this.props.value]);this.$emit("change", this.current);}} else {//选中下拉选变更值if (this.current == null ||item[this.props.value].join() !== this.current.join()) {this.current = item[this.props.value];this.$emit("change", this.current);}}this.keyword = "";},//初始化数据async initOptions() {this.props.lazyLoad(0, list => {this.$set(this, "options", list);if (this.props.multiple) {this.current = [...this.value];} else {this.current = this.value;}});},async getLabelArray() {if (this.props.multiple) {let array = [];for (let i = 0; i < this.current.length; i++) {let obj = await this.getObject(this.current[i]);array.push(obj);}this.labelArray = array;this.$emit("input", this.current);if (!this.disabled) {this.$nextTick(() => {this.$refs.popover.updatePopper();});}} else {this.labelObject = await this.getObject(this.current || []);this.$emit("input", this.current);}},/**格式化id=>object */async getObject(id) {let options = this.options;let nameArray = [];for (let i = 0; i < id.length; i++) {let index = options.findIndex(item => {return item[this.props.value] == id[i];});nameArray.push(options[index][this.props.label]);if (i < id.length - 1 && options[index].children == undefined) {let list = new Promise(resolve => {this.props.lazyLoad(id[i], list => {resolve(list);});});this.$set(options[index], "children", await list);options = options[index].children;} else {options = options[index].children;}}return {value: id, label: nameArray };},//懒加载数据async lazyLoad(node, resolve) {let current = this.current;if (this.props.multiple) {current = [...this.current];}if (node.root) {resolve();} else if (node.data[this.props.leaf]) {resolve();} else if (node.data.children) {resolve();} else {this.props.lazyLoad(node.value, list => {node.data.children = list;if (this.props.multiple) {this.current = current;}resolve(list);});}},//删除多选值/**删除**/handleClose(item) {let index = this.current.findIndex(obj => {return obj.join() == item.value.join();});if (index > -1) {let node = this.$refs.panel.getCheckedNodes().find(n => {return n.value == this.current[index][this.current[index].length - 1];});if (node) {node.checked = false;}this.current.splice(index, 1);this.$emit("change", this.current);}},change() {this.$emit("change", this.current);}}};

css

.lazy-cascader {display: inline-block;width: 300px;.lazy-cascader-input {width: 100%;background: #fff;height: auto;min-height: 36px;padding: 5px;line-height: 1;cursor: pointer;> .lazy-cascader-placeholder {padding: 0 2px;line-height: 28px;color: #999;font-size: 14px;}> .lazy-cascader-label {padding: 0 2px;line-height: 28px;color: #606266;font-size: 14px;overflow: hidden;text-overflow: ellipsis;white-space: nowrap;}}.lazy-cascader-input-disabled {background-color: #f5f7fa;border-color: #e4e7ed;color: #c0c4cc;cursor: not-allowed;> .lazy-cascader-label {color: #c0c4cc;}> .lazy-cascader-placeholder {color: #c0c4cc;}}}.lazy-cascader-tag {display: inline-flex;align-items: center;max-width: 100%;margin: 2px;text-overflow: ellipsis;background: #f0f2f5;> span {flex: 1;overflow: hidden;text-overflow: ellipsis;}> .el-icon-close {-webkit-box-flex: 0;-ms-flex: none;flex: none;background-color: #c0c4cc;color: #fff;}}.lazy-cascader-panel {margin-top: 10px;display: inline-block;}

其实,在自己封装组件的时候,也会不自觉的学习或者掌握一些东西,还是比较有趣的。

比如,为了解决多选的时候Popover 弹出框错位的问题,看了Element 的源码,发现Popover组件有一个updatePopper方法。

而且,封装组件需要考虑的问题比较多,倒不是说复杂,就是尽可能要全面。

好了,这一篇就写到这里,至于适用性,我也不能保证,至少很好的解决了cascader级联动态加载的不足,而且简化了动态加载的方法,很方便的实现了回显和搜索。

如果这正是你需要的,或者你预感自己会需要,可以先收藏,对于组件的不足之处也可以交流和讨论,以方便我去优化和改进。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。