V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
17681880207
V2EX  ›  问与答

Vue3 二次封装 Element Plus Form 组件的疑问,请求大家帮忙。

  •  
  •   17681880207 · 2021-11-16 10:46:21 +08:00 · 948 次点击
    这是一个创建于 1122 天前的主题,其中的信息可能已经有所发展或是发生改变。

    原因是这样的,因为项目中需要频繁的使用 form 表单,劳动力感觉非常重复,就决定还是对 element-plus 的 form 组件进行二次封装,尽量的做到配置化的开发。其中在开发 select 的 remote 模式的时候遇到了一些问题,自己调试了很久也没有找到解决办法。代码如下:

    代码块 1 为二次封装的组件。核心思路就是根据 formItem 中的 type 字段,渲染不同类型的表单组件。

    // 仅展示有问题的核心逻辑
    <template>
      <el-form class="table-search-form"
               :model="props.model"
               :rules="props.rules">
        <el-row :gutter="32">
          <el-col
              v-for="(formItem, index) in props.formItems"
              :key="index"
              :span="formItem.span ? formItem.span : 6">
            <el-form-item
                :label="formItem.label"
                :prop="formItem.prop">
              <-- 隐藏其他类型 -->
              <el-select
                  v-if="formItem.type === FORM_ITEM_TYPES.REMOTE_SELECT"
                  v-model="props.model[formItem.prop]"
                  :placeholder="formItem.placeholder ? formItem.placeholder : formItem.label"
                  clearable
                  filterable
                  remote
                  :remote-method="formItem.remoteMethod"
                  style="width: 100%;">
                <el-option
                    v-for="(option, index) in formItem.options"
                    :key="index"
                    :label="option.label"
                    :value="option.value"/>
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
    </template>
    
    <script lang="ts" setup>
    import {defineProps} from 'vue'
    
    enum FORM_ITEM_TYPES {
      INPUT = 'input',
      SELECT = 'select',
      REMOTE_SELECT = 'remoteSelect'
    }
    
    const props = defineProps({
      formItems: {
        type: Array,
        default: () => []
      },
      model: {
        type: Object,
        default: () => ({})
      },
      rules: {
        type: Object,
        default: () => ({})
      }
    })
    </script>
    

    代码块 2 为使用模块。

    <template>
        <table-search-form
            :form-items="formItems"
            :model="model"
            :rules="rules"/>
    </template>
    
    <script lang="ts" setup>
    import {reactive, ref} from 'vue'
    import TableSearchForm from '@/components/TableSearchForm/index.vue'
    
    const roles = ref<any[]>([
      {label: 'Role 1', value: 1}
    ])
    
    const handleRemoteMethod = (query: string) => {
      setTimeout(() => {
        roles.value = [
          {label: 'Role 2', value: 2},
          {label: 'Role 3', value: 3}
        ]
        // 打印点 1
        console.log(roles.value)
      }, 1000)
    }
    
    const formItems = [
      // ...省略
      {
        label: '角色 ID',
        prop: 'roleId',
        type: 'remoteSelect',
        remoteMethod: handleRemoteMethod,
        options: roles.value
      }
    ]
    
    const model = reactive({
      username: '张三',
      gender: 0,
      roleId: ''
    })
    
    const rules = {
      username: [{required: true, message: '用户名未输入。', trigger: 'none'}]
    }
    </script>
    

    问题

    因为是 remote 模式的 select ,所以我会传入一个 handleRemoteMethod 函数,动态修改它的 options ,这里的 options 用了一个 ref 进行接受然后传递到组件内部。但是当我发现触发 handleRemoteMethod 之后,打印出来的值(即:打印点 1 )已经修改了,但是组件渲染依旧只有 “Role 1” 这 1 个选项。但是我使用 roles.value.push(...[]) 的方法,可以正常的改变其渲染。 请问各位大佬,这是为啥?我应该如何做,求答疑解惑。

    17681880207
        1
    17681880207  
    OP
       2021-11-16 11:26:39 +08:00
    // 我将其中的代码,修改为如下,发现可以修改 options 了。
    // 整个 formItems 加上 ref ,哪步的 roles 取消 .value 。
    // 但是还是不是很清楚其中的缘由,有大佬可以帮忙分析一下吗?
    const formItems = ref([
    // ...省略
    {
    label: '角色 ID',
    prop: 'roleId',
    type: 'remoteSelect',
    remoteMethod: handleRemoteMethod,
    options: roles
    }
    ])
    4ark
        2
    4ark  
       2021-11-16 20:46:31 +08:00 via iPhone
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1181 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 17:53 · PVG 01:53 · LAX 09:53 · JFK 12:53
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.