使用 ElementPlus 组件时,遇到的一些问题及解决方案

  • Post author:
  • Post category:其他



目录


1. el-form 表单相关问题


1.1 使用 el-form 表单校验规则,无法对 number 类型输入框校验


1.2 隐藏后重新显示的 el-input 无法自动获得焦点(双击实现输入框编辑)


2. el-table 表格相关问题


2.1 解决 el-table 某列内容长度超过列宽,默认换行问题


2.2 el-table 滚动条导致的行对不齐问题


2.3 实现 el-table 隔行变色(ts 数据类型定义)


3. el-popover 组件内部添加注释导致的问题


1. el-form 表单相关问题

1.1 使用 el-form 表单校验规则,无法对 number 类型输入框校验

  <el-form :rules="rules" :model="scheduleFormLabel">
    <el-form-item label="活动人数:" required prop="peopleNum">
      <el-input
        type="number"
        placeholder="请输入活动人数"
        v-model="scheduleFormLabel.peopleNum"
      />
        <template #suffix>
          <span class="t-white t-f12">人</span>
        </template>
      </el-input>
    </el-form-item>
  </el-form>
rules: {
  peopleNum: [
    {
      required: true, message: '', trigger: 'blur',
    },
    {
      type: 'number',
      min: 1,
      max: 100000,
      message: '活动人数应该在1-100000之间',
      trigger: 'blur',
    },
  ],
},



解决方案:给 v-model 加上 .number 即可

<el-input v-model.number="scheduleFormLabel.peopleNum"></el-input>

1.2 隐藏后重新显示的 el-input 无法自动获得焦点(双击实现输入框编辑)

需求:这有一个菜单树,双击菜单项文本后,编辑菜单项名称


实现逻辑:

  • 双击菜单文本时,会触发方法 @dblclick=”handleDoubleClickMenuText()” ,该方法记录当前点击的菜单项id,并触发视图更新(当前菜单项id为记录的菜单id时,就会展示输入框,隐藏文本)
  • 通过设置 ref 变量,让输入框获得焦点 menuItemTextInputRef.value.focus(); 输入框实际却没获得
<template>
  <el-tree
     node-key="id"
     :props="propsMap"
     :data="state.data"
   >
      <template #default=" {node, data} ">
        <span>
          <!-- 节点文本 -->
          <span
            v-show="state.operateMenuItemId !== data.id"
            @dblclick="handleDoubleClickMenuText(data.id, data.id)"
          >
            {{node.label}}
          </span>

          <!-- 编辑节点文本的输入框 仅在双击文本的时候展示 -->
          <el-input
            v-model="data.label"
            v-show="state.operateMenuItemId === data.id"
            ref="menuItemTextInputRef"
            @blur="handleDoubleClickMenuText('', data.id)"
           />
         </span>
      </template>
   </el-tree>
</template>

<script lang="ts" setup>
import {
  reactive,
  ref,
} from 'vue';
import { MenuTreeData } from '@/types/common/menu-tree';
import { ElInput } from 'element-plus';

// 配置选项的映射
const propsMap = {
  children: 'children',
  label: 'label',
};

const state = reactive({
  // 树形菜单数据
  data: [
    {
      id: 'a1',
      label: '菜单1',
      children: [
        {
          id: 'aa1',
          label: '菜单1.1',
        },
        {
          id: 'ab1',
          label: '菜单1.2',
          children: [
            {
              id: 'aba1',
              label: '菜单1.2.1',
            },
          ],
        },
      ],
    },
    {
      id: 'b1',
      label: '菜单2',
    },
    //...
  ] as MenuTreeData[],
  // 当前操作的菜单项的id
  operateMenuItemId: '',
});
  
// 菜单项文本输入框DOM
const menuItemTextInputRef = ref();

/**
 * 处理双击菜单项文本
 * @param id - 菜单项id
 */
function handleDoubleClickMenuText(id: string) {
  state.operateMenuItemId = id;
  if (menuItemTextInputRef.value) {
    menuItemTextInputRef.value.focus();
  }
}
</script>

原因分析:

  • 渲染页面时,随着el-tree节点的遍历,会渲染多个el-input节点(因为使用了 v-show,节点存在,只是看不见)
  • 也就是说,页面里有多个 el-input,ref 被赋值了很多次,最终值是最后的一个el-input(果然,双击最后一个菜单项文本时,输入框获取到了焦点)

问题解决:


为了确保 el-input 只渲染一次(只存在一个有 ref=”menuItemTextInputRef” 属性的 el-input),应该采用 v-if 替代 v-show

<template>
  <el-tree
     node-key="id"
     :props="propsMap"
     :data="state.data"
   >
      <template #default=" {node, data} ">
        <span>
          <!-- 节点文本 -->
          <span
            v-if="state.operateMenuItemId !== data.id"
            @dblclick="handleDoubleClickMenuText(data.id, data.id)"
          >
            {{node.label}}
          </span>
          <!-- 编辑节点文本的输入框 仅在双击文本的时候展示 -->
          <el-input
            v-model="data.label"
            v-else
            ref="menuItemTextInputRef"
            @blur="handleDoubleClickMenuText('', data.id)"
           />
         </span>
      </template>
   </el-tree>
</template>

拓展:

  • 页面上本来没有 el-input 这个DOM,只有双击后,更新了当前选中的菜单ID(state.operateMenuItemId) ,才能触发 DOM 更新;
  • DOM更新完成之后,才能获取 el-input 的焦点

    (也就是说,获取焦点这一步,应该稍微等一下,等 DOM 更新了,el-input 加载出来了,才能获取焦点);

  • 因此,采用 setTimeout 来延迟执行获取输入框焦点的代码;
function handleDoubleClickMenuText(id: string) {
  state.operateMenuItemId = id;
  setTimeout(() => {
    if (menuItemTextInputRef.value) {
      menuItemTextInputRef.value.focus();
    }
  });
}

2. el-table 表格相关问题

2.1 解决 el-table 某列内容长度超过列宽,默认换行问题

如图所示,非理想效果:

理想效果其实是:不换行,溢出隐藏,鼠标滑上去后有 tooltip 进行提示

实现方法:

<el-table-column
  v-for="(item, index) in header"
  :key="index"
  :class-name="'table-cell'"
  :show-overflow-tooltip="true"
  :label="item.title"
  :prop="item.key"
/>

// 可以在全局 SCSS 中添加,也可以单独加在页面当中
.el-tooltip__popper {
  max-width: 800px;
  background-color: red!important;
}



注意:



  • 不能在 <style scoped></style> 中修改 ElementPlus 样式,不会生效



  • show-overflow-tooltip 属性需要谨慎使用,多列使用会影响页面加载速度

2.2 el-table 滚动条导致的行对不齐问题

如下图所示,左侧列固定,右侧列可以横向滚动,如果添加了滚动条,就会出现一行对不齐的情况



在行对齐的情况下,修改滚动条样式的解决方案:



  • 给 el-table 添加属性 height=”300px”



  • 在全局公共样式 .scss 中,添加设置:

    ::-webkit-scrollbar {


    width: 10px; // 纵向滚动条的宽度

    height: 10px; // 横向滚动条的高度

    }



  • 在自定义滚动条的页面或组件中,重新定义 ::-webkit-scrollbar 属性

2.3 实现 el-table 隔行变色(ts 数据类型定义)

如下图所示,直接解构参数会导致 ts 报错,缺少数据类型接口

interface changeRowParameter {
  row?: number; // 行
  column?: number; // 列
  rowIndex: number; // 行下标
  columnIndex?: number; // 列下标
}

/**
 * 间隔行颜色
 */
const changeRow = ({ rowIndex }: changeRowParameter) => {
  if (rowIndex % 2 === 0) {
    // 奇数行背景色
    return props.cStyle.rowContent;
  }
  // 偶数行背景色
  return props.cStyle.wrapperContent;
};

3. el-popover 组件内部添加注释导致的问题

如下代码所示,看起来似乎没有问题,却出现了报错

<el-popover
  ref="popover1"
  placement="bottom-start"
  width="213"
  trigger="click"
  :show-arrow="false"
  popper-class="reset-tool-popover"
  :disabled="disable"
  v-model:visible="visible"
>
  <template #reference>
    <!-- 属性文本 -->
    <span class="label" @click="handleClick">{{ label }}</span>
  </template>
  <div class="reset-box">
    <div class="reset-button-wrapper" v-if="reset">
      <!-- 重置按钮 -->
      <div class="reset-button" @click="handleReset">
        <div class="reset-left">
          <img src="@/assets/images/design/settings/reset.svg" alt="" />
          <span class="reset-action">Reset</span>
        </div>
        <span class="reset-shortcut">Alt + click</span>
      </div>
    </div>
    <!-- 重置说明 -->
    <p class="reset-explain">{{ explain }}</p>
    <div class="reset-button-wrapper global-explain" v-if="isGlobal">
      <img src="@/assets/images/design/settings/all-pages.svg" />
      <span class="global-explain-text">Body (All Pages)</span>
    </div>
  </div>
</el-popover>

报错内容:Uncaught (in promise) ElementPlusError: [renderTrigger] trigger expects single rooted node…



报错原因:



  • 根据提示可得,el-popover 希望只有一个根节点



  • <div class=”reset-box”> 作为内容区,只有一个DOM元素,不会导致报错



  • <template #reference> 作为插槽,不仅包含了一个DOM,还包含了一条注释



综上,使用 el-popover 时,在插槽里一定 “不能 ”使用注释



版权声明:本文为Lyrelion原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。