vuetify 学习第二天之v-combobox-自定义级联组件v-cascader封装

vuetify学习第二天之v-combobox


目录


内容

0、简介

  vuetify暂时未提供级联组件,我们可以结合element-ui或者iview等ui组件库的下拉部分,以及vuetify的v-combobox输入框部分,实现漂亮的自定义级联组件。

  这里使用iview的cascader组件和vuetify的combobox组件。

  • 效果图:在这里插入图片描述
  • 页面源代码:
<template>
  <cas :data="options" @on-change="handleChange" :loadData="loadOption" transfer>
    <v-combobox
      :label="label"
      chips
      clearable
      v-model="selected"
      multiple
    >
      <template v-slot:selection="{ item }">
        <v-chip
          @click.stop
          v-if="multiple"
          close
          @click:close="remove(item)"
          small
          outlined
          color="green"
        >{{ item.label }}&nbsp;</v-chip>
        <v-chip @click.stop v-else small>{{ item.__label }}</v-chip>
      </template>
    </v-combobox>
  </cas>
</template>

<script>
import { Cascader } from "iview";

export default {
  name: "vCascader",
  components: {
    cas: Cascader
  },
  props: {
    value: {},
    label: {
      type: String
    },
    url: {
      type: String
    },
    itemText: {
      type: String,
      default: "name"
    },
    itemValue: {
      type: String,
      default: "id"
    },
    children: {
      type: String,
      default: "children"
    },
    multiple: {
      type: Boolean,
      default: false
    },
    showAllLevels: {
      type: Boolean,
      default: false
    },
    required: {
      type: Boolean,
      default: false
    },
    rules: {
      type: Array
    }
  },
  data() {
    return {
      options: [],
      selected: [],
      defaultRules: []
    };
  },
  methods: {
    handleChange(value, selectedData) {
      console.log("start: ", this.selected);
      // 获取最后一级
      const option = selectedData[selectedData.length - 1];
      // 如果是多选,则默认只保存最后一级选项
      if (this.multiple) {
        // 将最后一级保存到selected中
        if (this.selected.findIndex(o => o.value === option.value) < 0) {
          this.selected.push(option);
        }
        // 返回已选中的值
        console.log("end: ", this.selected);

        this.$emit("input", this.transfer(this.selected));
      } else {
        // 单选,则需要判断是否需要显示所有级别
        if (this.showAllLevels) {
          // 显示所有级别,将各级别label进行拼接
          this.selected = [option.__label];
          // 返回id数组
          this.$emit("input", this.transfer(selectedData));
        } else {
          // 只显示最后一级
          this.selected = [option.label];
          // 返回
          this.$emit("input", this.transfer([option])[0]);
        }
      }
    },
    loadOption(item, callback) {
      // 延迟加载次级选项
      item.loading = true;
      this.loadData(item.value)
        .then(data => {
          item.children = data;
          item.loading = false;
          callback();
        })
        .catch(() => {
          item.loading = false;
          callback();
        });
    },
    loadData(pid) {
      // 从指定的url地址加载数据,并格式化
      return new Promise(resolve => {
        this.axios
          .get(this.url, {
            params: {
              pid: pid
            }
          })
          .then(resp => {
            const data = [];
            for (let d of resp.data) {
              const node = {
                value: d[this.itemValue],
                label: d[this.itemText]
              };
              if (d.isParent) {
                node["children"] = [];
                node["loading"] = false;
              }
              data.push(node);
            }
            resolve(data);
          });
      });
    },
    remove(item) {
      this.selected = this.selected.filter(o => o.value !== item.value);
      this.$emit("input", this.transfer(this.selected));
    },
    transfer(arr) {
      return arr.map(({ label, value }) => {
        const obj = {};
        obj[this.itemText] = label;
        obj[this.itemValue] = value;
        return obj;
      });
    },
    validate() {
      if (this.required) {
        this.$refs.form.validate();
      }
    }
  },
  created() {
    this.loadData(0).then(data => {
      this.options = data;
    });
    if (this.required) {
      this.defaultRules.push(v => v.length > 0 || this.label + "不能为空");
    }
    if (this.rules) {
      this.rules.forEach(r => this.defaultRules.push(r));
    }
  },
  watch: {
    value: {
      deep: true,
      handler(val) {
        if (!val) {
          this.selected = [];
          return;
        }
        if (val && this.showAllLevels && !this.multiple) {
          this.selected = [val.map(o => o[this.itemText]).join("/")];
        } else if (this.multiple && val) {
          this.selected = val.map(o => {
            return {
              label: o[this.itemText],
              value: o[this.itemValue]
            };
          });
        } else {
          this.selected = [val[this.itemText]];
        }
      }
    }
  }
};
</script>

<style scoped>
.ivu-cascader-menu-item {
  font-size: 14px;
}
</style>

1、iview之cascader组件

1.1、简介

  级联选择框常用来从有明显分级结果的数据集和中选取数据,比如省/市/县,公司结构,商城分类等等。

1.2、常用属性

  • 页面源代码:
 <template>
	 <cas :data="options" @on-change="handleChange" 				:loadData="loadOption" transfer></cas>
 <template>
 <script>
 ...
 	data() {
		return {
			options: []
			...
		}
	...
	methods: {
		handleChange(val, selectData){...} // 选择改变触发
		loadOption(val){...} // 次级数据延迟加载
		...
	}
...
 
名称 默认值 描述 详解
data [] 需要渲染的数据数组 1.2.1.1
value [] 选中的数据 1.2.1.2
load-data - 延迟加载函数 1.2.1.2

1.2.1、详细描述

1.2.1.1、data
  • 示例:
常规形式:
data:[
	{// 一级下拉框
	  text: '', // 每一项展示的内容
	  value: , // 每一项对应的key
	  children: [ // 二级下拉框
	  	text: '',
		value: ,
		children: [...]
	  ]
	}
	...
]

示例:
data: [
      {
	  	text: '手机',
	  	value: 76,
	  	children: [
	  		{ 
				text: '手机通讯',
				value: 100,
				children: [
					text: '手机',
					value: 260
				]
	  		}
		]
	}
	...
]
  • 详解
名称 类型 默认值 描述
text string ‘’ 每一项的显示的内容
value key 每一项的唯一标志
children array [] 子级下拉框数据

tips : value为每一项的唯一标志,建议用数据库返回的每一项的id值。

1.2.1.2、value
  • 示例:
示例数据:
[76, 100, 260]
	

itips : value 中存储的为选择条目对应的vulue值的集合。

1.2.1.3 、load-data
  • 示例:
// val 为点击条目对应的value值
loadData(val) {...} // load-data绑定的函数为延迟处理函数,用来延迟加载次级数据。触发时机:点击上级条目的时候触发。

1.3、常用事件

1.3.1、on-change

  • 示例:
// onChange为on-change绑定的处理函数
onChange(val, selectedData){...}
  • 参数详解
名称 类型 默认值 描述
val array [] 选中条目对应value值集合
selectedData array [] 选中条目对应对象集合

tips :val与selectedData都为一维数组,只记录选中的条目。

2、vuetify之chip组件

2.1、简介

  v-chip组件用来展示碎片化的信息,常被镶嵌于插槽中。

  • 页面源代码:
<template v-slot:selection="{ item }">
        <v-chip
          @click.stop
          v-if="multiple"
          close
          @click:close="remove(item)"
          small
          outlined
          color="green"
        >{{ item.label }}&nbsp;</v-chip>
        <v-chip @click.stop v-else small>{{ item.__label }}</v-chip>
      </template>
	
 

2.2、常用属性

名称 默认值 描述 详解
close false 是否添加关闭图标
color undefined 颜色 1.2.1.2
outlined false 是否显示幽灵样式 1.2.1.2
small false 是否大小变小 1.2.1.2

tips : v-chip组件相对很简单,不在做过多介绍,此处作为插槽内容嵌入cascader,用来替换原显示的文字,使cascader看起来更舒服。

2.3、常用事件

1.3.1、click:close

  • 示例:
@click:close="remove(item)"


// remove为click:close绑定的处理函数,用来删除选中的某一项
remove(item){...}
  • 参数详解
名称 类型 默认值 描述
item string/array ‘’/[] 要删除的项

tips :只有属性定义了close ,click:close才有意思,用来点击v-chip图标上小叉号,删除该项。

3、vuetify之combobox组件

3.1、简介

  v-combobox为带有自动完成功能,允许用户展示项目中不存在的值。

3.2、常用属性

  • 页面源代码:
  <v-combobox
  		:items="items"
      :label="label"
      chips
      clearable
      v-model="selected"
      multiple
    ></v-combobox>
...
 
名称 默认值 描述 详解
items [] 需要渲染的数据数组 3.2.1.1
value ‘’/[] 选中的数据 3.2.1.2
label ’‘ 该下拉框提示标签 延迟加载函数 3.2.1.3
clearable false 是否可清除 3.2.1.4
chips false 是否展示为chip 3.2.1.5
multiple false 是否可多选 3.2.1.6

3.2.1、详细描述

3.2.1.1、items
  • 示例:

示例:
data: [
      {
	  	text: '手机',
	  	value: 76,
	  	},
		{
			text: '电脑',
			value: 100
		}
	...
]
  • 详解
名称 类型 默认值 描述
text string/number/object 每一项的显示的内容
value string/number/object 每一项的唯一标志

tips :v-combobox作为下拉框,显示内容比较简单。

3.2.1.2、value与iview组件类似
  • 示例:
示例数据:
[76, 100, 260]
或者
67
	

itips : value是单相数值还是数组有 multiple决定,数据类型由items中数据决定。multiple为true,value为数组;multiple为false,value值为单值。

3.2.1.3 、label
  • 作用同input的label
3.2.1.4、clearable
  • 是否可清楚,既input框后带X号标记,点击可一次清空input框。
3.2.1.5、multipl 多选

3.3、常用事件与插槽

  • 参考官网和iview,这里不在详述。

4、自定义v-cascader组件

因为iview下拉框和vuetify下拉框各自有缺点和优点,刚好实现互补,这里就结合2者自定义实现本文开始展示的级联插件。

4.1、简单解析

  • iview部分为下拉框部分结构、样式和行为,vuetify为输入框部分结构、样式和行为
  • 桥梁: 通过监听i-cascader的value值的变化,改变v-conbobox的value的变化,实现整体的下拉框选择和输入框展示更新。
  • 渲染数据为请求后,稍加修改为符合展示的数据
  • v-combobox 允许展示渲染数据没有的项
  • data中props数组为自定义属性名称、类型及默认值,详细参考vue自定义组件。

后记: 刚开始学习vuetify ui组件,如有错误之处欢迎指正,共同进步,本人QQ:806797785

发布了17 篇原创文章 · 获赞 3 · 访问量 2690

猜你喜欢

转载自blog.csdn.net/gaogzhen/article/details/103797100