vue3.x + elementPlus 封装组件之Cascader 级联选择器

老规矩----前面文章的步骤创建文件导入js等

1.cascader .vue 组件

<template>
  <!--
    cascaderData.value // 默认展示数据
    options // 列表数据
    radio // 是否单选 默认不是
    multiple // 是否多选 默认不是
    is-search // 是否远程搜索 默认不是
    handleChange // 事件回调
    <MjbCascader v-model="cascaderData.value" :options="cascaderData.options" :radio="false" @handleChange="handleChange"></MjbCascader> -->
  <div>
    <!-- 单选 -->
    <el-cascader
      v-if="radio"
      v-model="cascaderData.valueArrRadio"
      :options="options"
      :props="cascaderData.propsObjRadio"
      clearable
      @change="handleChange"
    >
      <template #default="{ node, data }">
        <span>{{ data[showName] }}</span>
        <span v-if="!node.isLeaf"> ({{ data[childrenName].length }}) </span>
      </template>
    </el-cascader>
    <!-- 多选 -->
    <el-cascader
      v-else-if="multiple"
      v-model="cascaderData.valueArrMut"
      :options="options"
      :props="cascaderData.propsObj"
      collapse-tags
      collapse-tags-tooltip
      clearable
      @change="handleChange"
    >
      <template #default="{ node, data }">
        <span>{{ data[showName] }}</span>
        <span v-if="!node.isLeaf"> ({{ data[childrenName].length }}) </span>
      </template>
    </el-cascader>
    <!-- 搜索 -->
    <el-cascader
      v-else-if="isSearch"
      v-model="cascaderData.valueArrSearch"
      :props="propsIsSearch"
      clearable
      @change="handleChange"
    />
    <!-- 默认 -->
    <el-cascader
      v-else
      v-model="cascaderData.valueDef"
      :options="options"
      :props="cascaderData.propsDef"
      clearable
      @change="handleChange"
    >
      <template #default="{ node, data }">
        <span>{{ data[showName] }}</span>
        <span v-if="!node.isLeaf"> ({{ data[childrenName].length }}) </span>
      </template>
    </el-cascader>
  </div>
</template>
<script>
import { reactive, watch, ref } from 'vue'
const cascaderData = reactive({
  propsObjRadio: { expandTrigger: 'hover' },
  propsObj: { expandTrigger: 'hover' },
  propsDef: { expandTrigger: 'hover' },
  valueArrRadio: '',
  valueArrMut: [],
  valueArrSearch: [],
  valueDef: []
})
export default {
  props: {
    // // 单选默认值
    // valueAudio: {
    //   default() {
    //     return ''
    //   },
    //   type: String
    // },
    // // 多选默认值
    title: {
      default() {
        return
      },
      // eslint-disable-next-line vue/require-prop-type-constructor
      type: Number
    },
    // 数据的名称
    showName: {
      default() {
        return 'label'
      },
      type: String
    },
    // children的名称
    childrenName: {
      default() {
        return 'children'
      },
      type: String
    },
    // value的名称
    valueName: {
      default() {
        return 'value'
      },
      type: String
    },
    radio: {
      default() {
        return false
      },
      type: Boolean
    },
    // 非搜索的数据
    options: {
      default() {
        return []
      },
      type: Array
    },
    // 是否多选
    multiple: {
      default() {
        return false
      },
      type: Boolean
    },
    // 是否是远程搜索状态
    isSearch: {
      default() {
        return false
      },
      type: Boolean
    },
    // 搜索的数据
    propsIsSearch: {
      default() {
        return {}
      },
      type: Object
    }
  },
  emits: ['handleChange'],
  setup(props, ctx) {
    // 单选
    if (props.radio) {
      cascaderData.propsObjRadio = {
        expandTrigger: 'hover',
        checkStrictly: true,
        children: props.childrenName,
        label: props.showName,
        value: props.valueName
      }
    }
    // 多选
    if (props.multiple) {
      cascaderData.propsObj = {
        expandTrigger: 'hover',
        multiple: true,
        children: props.childrenName,
        label: props.showName,
        value: props.valueName
      }
    }
    // 搜索
    if (props.isSearch) {
      console.log(props.isSearch)
      // console.log(cascaderData.propsObj)
    } else {
      // 默认
      cascaderData.propsDef = {
        expandTrigger: 'hover',
        children: props.childrenName,
        label: props.showName,
        value: props.valueName
      }
    }
    // eslint-disable-next-line vue/no-setup-props-destructure
    watch(() => props.title, (n) => {
      // 要执行的方法
      // console.log(n)
      if (props.radio) {
        cascaderData.valueArrRadio = n
      }
      // 多选
      if (props.multiple) {
        cascaderData.valueArrMut.length = 0
        cascaderData.valueArrMut.push(n)
      } else {
        cascaderData.valueDef.length = 0
        cascaderData.valueDef.push(n)
      }
    }, { immediate: true, deep: true })
    // console.log(props.options)
    const handleChange = (value) => {
      ctx.emit('handleChange', value)
    }
    return { cascaderData, handleChange }
  }
}
</script>

2.使用

<template>
  <div>
    <span>默认Cascader</span>
    <LZCascader
      :show-name="cascaderData.showName"
      :children-name="cascaderData.children"
      :value-name="cascaderData.valuet"
      :title="cascaderData.value"
      :options="cascaderData.options"
      :radio="false"
      @handleChange="handleChange"
    ></LZCascader>
  </div>
  <div>
    <span>单选Cascader</span>
    <LZCascader
      :show-name="cascaderData.showName"
      :children-name="cascaderData.children"
      :value-name="cascaderData.valuet"
      :title="cascaderData.value2"
      :options="cascaderData.options"
      radio
      @handleChange="handleChange2"
    ></LZCascader>
  </div>
  <div>
    <span>多选Cascader</span>
    <LZCascader
      :show-name="cascaderData.showName"
      :children-name="cascaderData.children"
      :value-name="cascaderData.valuet"
      :title="cascaderData.value3"
      :options="cascaderData.options"
      multiple
      @handleChange="handleChange3"
    ></LZCascader>
  </div>
  <div>
    <span>远程搜索Cascader</span>
    <LZCascader
      :show-name="cascaderData.showName"
      :children-name="cascaderData.children"
      :value-name="cascaderData.valuet"
      :title="cascaderData.value4"
      is-search
      :props-is-search="cascaderData.propsIsSearch"
      @handleChange="handleChange4"
    ></LZCascader>
  </div>
</template>
<script>
import { reactive } from 'vue'
const cascaderData = reactive({
  showName: 'label',
  valuet: 'value',
  children: 'children',
  value: '',
  value2: '',
  value3: '',
  value4: '',
  propsIsSearch: {},
  options: [
  {
    value: 'guide',
    label: 'Guide',
    disabled: true,
    children: [
      {
        value: 'disciplines',
        label: 'Disciplines',
        children: [
          {
            value: 'consistency',
            label: 'Consistency',
          },
          {
            value: 'feedback',
            label: 'Feedback',
          },
          {
            value: 'efficiency',
            label: 'Efficiency',
          },
          {
            value: 'controllability',
            label: 'Controllability',
          },
        ],
      },
      {
        value: 'navigation',
        label: 'Navigation',
        children: [
          {
            value: 'side nav',
            label: 'Side Navigation',
          },
          {
            value: 'top nav',
            label: 'Top Navigation',
          },
        ],
      },
    ],
  },
  {
    value: 'component',
    label: 'Component',
    children: [
      {
        value: 'basic',
        label: 'Basic',
        children: [
          {
            value: 'layout',
            label: 'Layout',
          },
          {
            value: 'color',
            label: 'Color',
          },
          {
            value: 'typography',
            label: 'Typography',
          },
          {
            value: 'icon',
            label: 'Icon',
          },
          {
            value: 'button',
            label: 'Button',
          },
        ],
      },
      {
        value: 'form',
        label: 'Form',
        children: [
          {
            value: 'radio',
            label: 'Radio',
          },
          {
            value: 'checkbox',
            label: 'Checkbox',
          },
          {
            value: 'input',
            label: 'Input',
          },
          {
            value: 'input-number',
            label: 'InputNumber',
          },
          {
            value: 'select',
            label: 'Select',
          },
          {
            value: 'cascader',
            label: 'Cascader',
          },
          {
            value: 'switch',
            label: 'Switch',
          },
          {
            value: 'slider',
            label: 'Slider',
          },
          {
            value: 'time-picker',
            label: 'TimePicker',
          },
          {
            value: 'date-picker',
            label: 'DatePicker',
          },
          {
            value: 'datetime-picker',
            label: 'DateTimePicker',
          },
          {
            value: 'upload',
            label: 'Upload',
          },
          {
            value: 'rate',
            label: 'Rate',
          },
          {
            value: 'form',
            label: 'Form',
          },
        ],
      },
      {
        value: 'data',
        label: 'Data',
        children: [
          {
            value: 'table',
            label: 'Table',
          },
          {
            value: 'tag',
            label: 'Tag',
          },
          {
            value: 'progress',
            label: 'Progress',
          },
          {
            value: 'tree',
            label: 'Tree',
          },
          {
            value: 'pagination',
            label: 'Pagination',
          },
          {
            value: 'badge',
            label: 'Badge',
          },
        ],
      },
      {
        value: 'notice',
        label: 'Notice',
        children: [
          {
            value: 'alert',
            label: 'Alert',
          },
          {
            value: 'loading',
            label: 'Loading',
          },
          {
            value: 'message',
            label: 'Message',
          },
          {
            value: 'message-box',
            label: 'MessageBox',
          },
          {
            value: 'notification',
            label: 'Notification',
          },
        ],
      },
      {
        value: 'navigation',
        label: 'Navigation',
        children: [
          {
            value: 'menu',
            label: 'Menu',
          },
          {
            value: 'tabs',
            label: 'Tabs',
          },
          {
            value: 'breadcrumb',
            label: 'Breadcrumb',
          },
          {
            value: 'dropdown',
            label: 'Dropdown',
          },
          {
            value: 'steps',
            label: 'Steps',
          },
        ],
      },
      {
        value: 'others',
        label: 'Others',
        children: [
          {
            value: 'dialog',
            label: 'Dialog',
          },
          {
            value: 'tooltip',
            label: 'Tooltip',
          },
          {
            value: 'popover',
            label: 'Popover',
          },
          {
            value: 'card',
            label: 'Card',
          },
          {
            value: 'carousel',
            label: 'Carousel',
          },
          {
            value: 'collapse',
            label: 'Collapse',
          },
        ],
      },
    ],
  },
  {
    value: 'resource',
    label: 'Resource',
    children: [
      {
        value: 'axure',
        label: 'Axure Components',
      },
      {
        value: 'sketch',
        label: 'Sketch Templates',
      },
      {
        value: 'docs',
        label: 'Design Documentation',
      },
    ],
  },
  ]
})
export default {
  setup() {
    cascaderData.value = cascaderData.options[0].children[0].children[0].value
    // 这里是远程搜索的逻辑
    let id = 0
    cascaderData.propsIsSearch = {
      lazy: true,
      multiple: true, // 是否多选
      lazyLoad(node, resolve) {
        const { level } = node
        setTimeout(() => {
          const nodes = Array.from({ length: level + 1 }).map((item) => ({
            value: ++id,
            label: `Option - ${id}`,
            leaf: level >= 2
          }))
          // Invoke `resolve` callback to return the child nodes data and indicate the loading is finished.
          resolve(nodes)
        }, 1000)
      }
    }
    const handleChange = (value) => {
      console.log(value)
    }
    const handleChange2 = (value) => {
      console.log(value)
    }
    const handleChange3 = (value) => {
      console.log(value)
    }
    const handleChange4 = (value) => {
      console.log(value)
    }
    return { cascaderData, handleChange, handleChange2, handleChange3, handleChange4 }
  }
}
</script>

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你可以尝试以下步骤来封装一个Vue 3和TypeScript下使用Element Plus的表单提交组件: 1. 安装必要的依赖: - Vue 3:`npm install vue@next` - TypeScript:`npm install -D typescript` - Element Plus:`npm install element-plus` 2. 创建一个新的Vue组件,并为其选择一个合适的名称,例如`FormSubmit.vue`。 3. 在`FormSubmit.vue`文件中,导入必要的模块和样式: ```vue <template> <!-- 表单内容 --> </template> <script lang="ts"> import { defineComponent } from 'vue'; import { ElButton, ElForm, ElFormItem } from 'element-plus'; export default defineComponent({ components: { ElButton, ElForm, ElFormItem, }, }); </script> <style scoped> /* Element Plus 样式 */ @import 'element-plus/packages/theme-chalk/src/index.scss'; /* 自定义样式 */ /* ... */ </style> ``` 4. 在模板中编写表单内容,并使用Element Plus的组件来构建表单: ```vue <template> <el-form ref="form" :model="formData" label-width="120px"> <el-form-item label="姓名" prop="name"> <el-input v-model="formData.name"></el-input> </el-form-item> <!-- 更多表单项 --> <el-form-item> <el-button type="primary" @click="submitForm">提交</el-button> </el-form-item> </el-form> </template> <script lang="ts"> // ... export default defineComponent({ // ... data() { return { formData: { name: '', // 更多表单字段 } }; }, methods: { submitForm() { // 表单提交逻辑 if (this.$refs.form.validate()) { // 表单验证通过,执行提交操作 // ... } } } }); </script> ``` 这样,你就可以使用封装好的表单提交组件来方便地处理表单提交了。你可以根据实际需求添加更多的表单项,并在`submitForm`方法中实现你的提交逻辑。希望这可以帮到你!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值