艺灵设计

全部文章
×

Vue3踩坑系列之把Element-UI升级到Element-Plus时遇到的若干坑

作者:艺灵设计 - 来源:http://www.yilingsj.com - 发布时间:2022-09-19 15:22:34 - 阅: - 评:0 - 积分:0

摘要:前两篇文章一直在讲升级Element-Plus组件库为@2.x后,老代码中的upload功能出现了异常。今天接着说一些在升级后遇到的其他问题,包括Dialog对话框、slot插槽、Flex布局、select选择器在打包后空白等。

一、背景

前段时间,公司要开发一个新的后台项目。当时@徐大大和@牟万都想用Vue3练练手,毕竟现在的前端更新迭代速度不亚于坐火箭!我当然是乐意的,于是配合他们在本地搭建了一个开源的Vue3后台项目

忙活了一会儿,项目初步能正常运行,也能配合我的打包工具在多环境下进行一键打包并部署到服务器,访问线上也一切正常。至此,我的事情就结束了。

他们两个则按照需求开发新的任务,遇到能复用别的项目代码的地方则copy过来改改直接使用,遇到搞不定的地方我再过来解决。

哦,差点儿忘记说了。当时package.json中安装的Element-Plus版本正好是1.0.2-beta.53。项目里面也还没有使用<el-select>组件,所以也就没有暴露出问题。

直到第一阶段项目开发完毕,我打包项目到线上。测试进行测试时发现所有的select下拉框全部空白!但开发时一切都正常!!这就离谱啊!!!gif动态图↓↓↓select组件下拉框中一片空白

这就是我前面两篇文章中为什么要升级Element-Plus版本的主要原因之一。

下面是我整理的在这个项目中从Element-UI升级到Element-Plus@2.x时遇到的所有问题,在此做个记录,避免日后其他项目升级时继续踩坑。

一、Dialog 对话框

Element-UI时,通过:visible属性可控制Dialog 对话框的显示和隐藏。

当升级到Element-Plus@2.x时,需要更换成model-valuev-model才行。

对比代码见下方↓↓↓

<!-- Element-UI时的Dialog对话框 ↓↓↓ -->
<el-dialog :visible.sync="dialogVisible">
  ......
</el-dialog>

<!-- Element-Plus@2.x时的Dialog对话框 ↓↓↓ -->
<el-dialog v-model="dialogVisible">
  ......
</el-dialog>

二、slot插槽要加父级

Element-UI代码的基础上,把原来的slot="xxx"放到新建的父级<template #xxx>上。

对比代码见下方↓↓↓

<!-- Element-UI时的slot插槽 ↓↓↓ -->
<el-dialog :visible.sync="dialogVisible">
  <!-- 下面的 slot="footer" 是一个具名插槽 -->
  <div slot="footer" class="dialog-footer">
    ......
  </div>
</el-dialog>

<!-- Element-Plus@2.x时的slot插槽 ↓↓↓ -->
<el-dialog v-model="dialogVisible">
  <!-- 注意下面的template #xx -->
  <template #footer>
    <div class="dialog-footer">
      ......
    </div>
  </template>
</el-dialog>

再来个Upload 上传组件的示例。

<!-- Element-UI时的代码 ↓↓↓ -->
<el-upload ref="upload">
  <el-button slot="trigger" type="primary">
    选取文件
  </el-button>
  <el-button type="success" @click="submitUpload">
    上传到服务器
  </el-button>
  <div slot="tip" class="el-upload__tip">
    只能上传jpg/png文件,且不超过500kb
  </div>
</el-upload>

<!-- Element-Plus@2.x时的代码 ↓↓↓ -->
<el-upload ref="upload">
  <template #trigger>
    <el-button type="primary">选取文件</el-button>
  </template>
  <el-button type="success" @click="submitUpload">
    上传到服务器
  </el-button>
  <template #tip>
    <div class="el-upload__tip">
      只能上传jpg/png文件,且不超过500kb
    </div>
  </template>
</el-upload>

除了DialogUpload组件外,类似的组件还有很多。比如:Input 输入框Table 表格Image 图片等,此处不再举例。

三、float布局升级为Flex布局

起初我并没有注意到这个问题,毕竟页面在Element-Plus@1.0.2-beta.53时还是正常的,直到我升级为@2.x后,页面发生了明显的变化。拿Form 表单组件来说,各版本对比见下图↓↓↓Element-UI中表单样式在升级后发生了错乱

经调试发现此时已经变成了Flex布局了。而官方中也明确说明了这一点,原话如下:

TIP
Form 组件已经从 2. x 的 Float 布局升级为 Flex 布局。
文档链接:https://element-plus.gitee.io/zh-CN/component/form.html

为了尽可能用最小变动来解决问题,我不得不重置了.el-form-item__contentdisplay: flex样式。

除了Form 表单使用了Flex布局外,Layout 布局也全面升级为Flex布局了。它也同样影响了这个项目的布局。

四、若干组件的size="small"属性

升级后,我发现带有size="small"属性的组件都小了好多。拿Button 按钮组件举例,各版本对比如下图↓↓↓Button组件设置small后各版本对比图

受影响的组件有很多,比如这个项目中的Input 输入框Select 选择器DatePicker 日期选择器等等。

与其重置样式,我发现去掉size="small"更省事儿。于是全局替换了一波。

五、Icon图标无法显示

这个问题在上一篇《Vue3踩坑系列之Element-Plus库中upload上传组件的坑(下)》中有提及过。简单来说就是Element-Plus@2.x不再把iconfont字体库图标当做首选,而是改用SVG了

解决的方案就是安装相关插件,然后做对应的修改。官方原文档链接:https://element-plus.gitee.io/zh-CN/component/icon.html

5.1、手动安装@element-plus/icons-vue

npm install @element-plus/icons-vue --save-dev // 先安装图标库

安装后还需要修改main.js文件。

import * as ElementPlusIconsVue from '@element-plus/icons-vue'

const app = createApp(App)
for (const [key, component] of Object.entries(ElementPlusIconsVue)) {
  app.component(key, component)
}

前面两步完成后,接下来把页面中的老写法改成新的即可。

<!-- 之前的写法,兼容vue2、vue3+Element-Plus@1.0.2-beta.53 ↓↓↓ -->
<i class="el-icon-plus"></i>
<!-- 按钮上的图标↓↓↓ -->
<el-button icon="el-icon-search"></el-button>

<!-- Element-Plus高版本时的写法↓↓↓ -->
<el-icon><Plus /></el-icon>
<!-- 按钮上的图标↓↓↓ -->
<el-button icon="Search"></el-button>

上面的<Plus>对应原来的el-icon-plus

我原以为只需要把所有的el-icon-前缀去掉,再把后面的单词的首字母改成大写就能兼容Element-Plus。吭哧吭哧改完后,结果发现部分页面中的图标仍无法显示!

。。。。。。

5.2、发现的规律

在对比Element-UIElement-Plus的图标库后,我发现这一转换是有规律的,但有个别例外。详细见下表。

Element-UI中的图标转换为Element-Plus图标
Element-UIElement-Plus转换规律
<i class="el-icon-plus"></i><Plus />大多数图标可通过去掉el-icon-前缀,并把剩下的首字母进行大写即可兼容Element-Plus
<i class="el-icon-zoom-in"></i><ZoomIn />当剩余字母中出现-时,一般继续使用驼峰写法。
注意el-icon-s-home是例外
<i class="el-icon-switch-button"></i><SwitchButton />
<i class="el-icon-s-home"></i><HomeFilled />如果Element-UI图标背景为非镂空时,转换后需要加上Filled
<i class="el-icon-info"></i><InfoFilled />
<i class="el-icon-error"></i><CircleCloseFilled />
<i class="el-icon-more"></i><MoreFilled />
<i class="el-icon-warning"></i><WarningFilled />
<i class="el-icon-edit"></i><EditPen />这个我就看不出来规律了,难道是因为像笔?
..................

上面表格中的图标渲染后见下图↓↓↓图标转换后正常显示

这里我还是想吐槽一下,你说你换成SVG就算了,不同的图标转换还有不同的规律,你就不能统一点儿嘛!累死前端。。。。。。

除了Icon 图标本身外,像Button 按钮Input 输入框Upload 上传等用到Icon图标的组件都会受影响!

六、不点击Image图片组件仍想实现预览功能

官方给的案例都是点击图片本身才能弹出预览的效果,但开发中可能需求多变,往往会出现点击某一按钮或图标就实现预览的功能。这个问题在上一篇文章中有也提及,此处放个简单demo。

6.1、Vue2+Element-UI时的代码,兼容Element-Plus@1.0.2

<!-- 此代码兼容Element-UI和Element-Plus@1.0.2-beta.53 -->
<template>
  <div>
    <el-button @click="handlePicPreview">查看附件</el-button>

    <!-- 预览图片功能↓↓↓ -->
    <div class="demo-image__preview" v-if="dialogImageUrl">
      <el-image ref="elImage" :src="dialogImageUrl" :preview-src-list="previewSrcList">
      </el-image>
    </div>
  </div>
</template>

<script>
export default {
  methods: {
    // 预览图片
    handlePicPreview() {
      this.dialogImageUrl = this.url // 附件图片地址
      this.$nextTick(() => {
        this.$refs.elImage.clickHandler() // 主要是这行代码
      })
    },
  }
}
</script>

6.2、Element-Plus@2.x时的代码

<!-- 预览图片功能↓↓↓ -->
<div class="demo-image__preview" v-if="dialogImageUrl">
  <!-- 注意这里由原来的 el-image 改为 el-image-viewer ↓↓↓ -->
  <el-image-viewer
    ref="elImage"
    :src="dialogImageUrl"
    :url-list="previewSrcList"
    @close="handleDialogCloseImage"
  >
  </el-image-viewer>
</div>

<script>
export default {
  methods: {
    // 预览图片
    handlePicPreview() {
      this.dialogImageUrl = this.url // 附件图片地址
      this.$nextTick(() => {
        // this.$refs.elImage.clickHandler() // Vue2、Vue3+Element-Plus@1.0.2-beta.53时可用
        this.$refs.elImage.setActiveItem(0) // Element-Plus高版本时可用
      })
    },
    // 关闭“预览图片”功能(兼容Element-Plus)
    handleDialogCloseImage() {
      this.dialogImageUrl = ''
    },
  },
}
</script>

七、Upload 组件相关

Upload 组件相关的问题,在上两篇文章详细写过。这里不再赘述,有兴趣的看官可以回看文章→→→
Vue3踩坑系列之Element-Plus库中upload上传组件的坑》、
Vue3踩坑系列之Element-Plus库中upload上传组件的坑(下)

八、Select 选择器在打包后空白?

我不得不说这是一个十分诡异的问题!为什么说诡异呢?且听我慢慢道来。

先来看下我的package.json配置文件,只展示核心代码。

{
  "scripts": {
    "build:dev": "vite build --mode development", // 打包开发环境
    "build:prod": "vite build --mode production", // 打包正式环境
    "key-upload:prod": "cross-env NODE_ENV=prod key-upload" // 一键打包并上传到服务器的命令
  },
  "dependencies": {
    "element-plus": "1.0.2-beta.53", // 注意这里版本还是@1.x
    "vue": "3.2.2"
  },
  "devDependencies": {
    "vite": "2.3.8" // 注意这里是2.3.8
  }
}

我像往常一样使用npm run key-upload:prod zip命令一键打包并部署项目到服务器。当音乐响起后,访问线上项目。初看正常,但所有使用Select 选择器的地方,下拉框中全部空白!gif动态图↓↓↓select组件下拉框中一片空白

我非常纳闷,为啥开发时是正常的,打包后就异常了!

此时@牟万使用npm run build:prod打包项目,打完包后在本地跑了下打包后的代码,所有使用Select 选择器的下拉框又是有内容的!

我的第一反应是:嗯?还有这种事儿??

为了排除缓存干扰,我删除了项目中的node_modules目录,也清除了缓存,然后重新npm install安装依赖,继续走了一把命令。结果同上。

我又试了下npm run build:prod,打包后跑了下代码,select下拉框还真是好的!

难道是我的一键打包脚本出了问题???

我又仔细对比了下下两个打包命令在编译后的区别,试图找出问题。相关对比见下方。

  1. 编译前:npm run build:prod
  2. 编译后:vite build --mode production
  3. 编译前:npm run key-upload:prod zip
  4. 编译后:npx cross-env NODE_ENV=production vite build --mode production

通过对比可以发现唯一的区别就是多了npx cross-env NODE_ENV=production这一句。

cross-env NODE_ENV=production是用来指定自定义环境的,可起到重置环境变量的作用,这个大家都知道。

剩下只有一个npx了,注意我没有写错单词哈。简单来说,这个npxnpm的升级版,比npm功能更强大。更多细节问题,看官可自行网上查询。

8.1、测试一:删除cross-env就正常

我尝试着去掉cross-env NODE_ENV=production,直接使用npx vite build --mode production进行打包项目。打包后神奇的事情出现了!select选择器的下拉框恢复正常了!!!而我只要加上cross-env NODE_ENV=production这一句,下拉框就不显示!

这就离谱啊!

如果有哪位看官知道原因,还请多多指教一下,谢谢。

8.2、测试二:在onMounted()中赋值就正常

后来,我又进行了另外一个测试,结果也是很神奇。先来看下相关代码吧。

<template>
  <el-form :model="form">
    <el-form-item label="状态" prop="status">
      <el-select v-model="form.status" placeholder="请选择">
        <el-option
          v-for="item in statusList"
          :key="item.value"
          :value="item.value"
          :label="item.label"
        ></el-option>
      </el-select>
    </el-form-item>
  </el-form>
</template>

<script setup>
import { ref, reactive, onMounted } from 'vue'
// 表单字段
const form = reactive({
  status: '' // 商品状态
})
// select下拉框的内容
const statusList = ref([
  { value: '1', label: '在售' },
  { value: '2', label: '待售' },
  { value: '6', label: '待审核' },
  { value: '7', label: '被驳回' }
])
onMounted(() => {

})
</script>

上面代码是精简过的,用npx打包后select下拉框中仍是空白。如果我做下修改,奇迹就出现了。

<script setup>
import { ref, reactive, onMounted } from 'vue'
// 表单字段
const form = reactive({
  status: '' // 商品状态
})
// select下拉框的内容
const statusList = ref([])

onMounted(() => {
  statusList.value = [
    { value: '1', label: '在售' },
    { value: '2', label: '待售' },
    { value: '6', label: '待审核' },
    { value: '7', label: '被驳回' }
  ]
})
</script>

对,你没有看错!我在onMounted()函数中对statusList进行了重新赋值,此时select下拉框就正常了。

我在网上也搜索过别的方案,但都不靠谱。

Element-Plus官网一看,已经2.2.16版本了。再看看我们的版本,才1.0.2-beta.53,所以我才有了升级到@2.x的想法。

8.3、测试三:升级到@2.x后就正常

第一次时,我升级到了@2.2.9版本。继续使用一键打包命令,也就是npx cross-nev ....。线上的Select下拉框正常显示。

但此时新的问题出现了,部分页面样式发生错乱,于是我选择了继续升级。

第二次升级到了@2.2.16,当时的最新版。再次打包后Select下拉框仍正常显示,在@2.2.9时异常的界面也恢复了正常。

所以你看,我啥也没改,只是升级了Element-Plus的版本问题就得已解决。你说诡异不诡异!

通过以上三组不同的测试,虽然问题都能得已解决,但我仍十分懵逼!

大胆猜测,就是Element-Plus组件库的问题。

九、最后

好了,关于Element-Plus组件库的使用问题,我已经跟它刚了好几天了。目前遇到的坑都在这三篇文章中,吐槽就到此结束。日后再有新问题,再更新。

转载声明:
  若亲想转载本文到其它平台,请务必保留本文出处!
本文链接:/xwzj/2022-09-19/vue3-element-to-element-plus.html

若亲不想直保留地址,含蓄保留也行。艺灵不想再看到有人拿我的技术文章到他的地盘或者是其它平台做教(装)程(B)而不留下我的痕迹。文章你可以随便转载,随便修改,但请尊重艺灵的劳动成果!谢谢理解。

亲,扫个码支持一下艺灵呗~
如果您觉得本文的内容对您有所帮助,您可以用支付宝打赏下艺灵哦!

Tag: Vue3 踩坑系列 项目优化 Vue Element-UI vite Element-Plus upload slot 插槽 Flex

上一篇: Vue3踩坑系列之Element-Plus库中upload上传组件的坑(下)   下一篇: 返回列表

评论区