升级的代价并不是那么简单,一篇文章vue2项目升级到vue3经历分享1,只好再写一篇。
1 cdn使用
在vue2中cdn使用,在public中放入js,如果cdn失效则取本地的js
在vue.config.js
中指定外部cdn资源的分发
在vue3中使用yarn add vite-plugin-cdn-import --dev
,然后在vite.config.ts
中配置
import cdn from 'vite-plugin-cdn-import'
cdn({
modules: [
{
name: "element-plus",
var: "ElementPlus",
path: "https://cdn.jsdelivr.net/npm/element-plus@2.2.32/dist/index.full.min.js",
},
{
name:"echarts", // 按需引入echarts
var: "echarts",
path: "https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js",
},
{
name: "axios",
var: "axios",
path: "https://cdn.jsdelivr.net/npm/axios@1.6.1/dist/axios.min.js",
},
{
name: 'vue',
var: 'Vue',
path: 'https://cdn.jsdelivr.net/npm/vue@3.3.8/dist/vue.global.min.js',
},
{
name:'vue-router',
var: 'VueRouter',
path: 'https://cdn.jsdelivr.net/npm/vue-router@4.2.5/dist/vue-router.global.min.js',
},
],
}),
执行yarn build:dev
后就可以看到打包的效果,即开发环境默认是不启用cdn的
哪些需要引用cdn呢,安装yarn add rollup-plugin-visualizer --save
在vite.config.ts
中配置
import {visualizer} from 'rollup-plugin-visualizer'
visualizer({
filename: './bundle-visualizer.html',
open: true,
gzipSize: true,
}),
在执行yarn build
之后,就可以看到,哪些文件大,就那个文件使用cdn进行加速
发布到生产环境,并不能总能如愿的顺利,提示下面的错误
aria.ts:22 Uncaught TypeError: Cannot read properties of undefined (reading 'defineComponent')
at aria.ts:22:19
at index.full.min.js:1:240
at index.full.min.js:1:268
(anonymous) @ aria.ts:22
(anonymous) @ index.full.min.js:1
(anonymous) @ index.full.min.js:1
index.min.js:3 Uncaught SyntaxError: Cannot use import statement outside a module (at index.min.js:3:28)
index.8942f36c.js:44 Uncaught ReferenceError: ElIcons is not defined
at Object.install (index.8942f36c.js:44:2101)
at Object.use (vue.global.js:5190:20)
at index.8942f36c.js:44:3839
install @ index.8942f36c.js:44
use @ vue.global.js:5190
(anonymous) @ index.8942f36c.js:44
index.8942f36c.js:31 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'error')
at index.8942f36c.js:31:128159
at vue-router.global.js:3615:39
at Array.forEach (<anonymous>)
at z (vue-router.global.js:3615:20)
at vue-router.global.js:3335:19
(anonymous) @ index.8942f36c.js:31
(anonymous) @ vue-router.global.js:3615
z @ vue-router.global.js:3615
(anonymous) @ vue-router.global.js:3335
Promise.then (async)
L @ vue-router.global.js:3336
I @ vue-router.global.js:3262
(anonymous) @ index.8942f36c.js:31
await in (anonymous) (async)
(anonymous) @ vue-router.global.js:1991
(anonymous) @ vue-router.global.js:1963
runWithContext @ vue.global.js:5298
D @ vue-router.global.js:3387
(anonymous) @ vue-router.global.js:3739
Promise.then (async)
(anonymous) @ vue-router.global.js:3739
ne @ vue-router.global.js:3739
(anonymous) @ vue-router.global.js:3413
Promise.then (async)
V @ vue-router.global.js:3406
L @ vue-router.global.js:3328
L @ vue-router.global.js:3304
I @ vue-router.global.js:3262
install @ vue-router.global.js:3701
use @ vue.global.js:5190
(anonymous) @ index.8942f36c.js:44
index.8942f36c.js:44 Uncaught (in promise) ReferenceError: ElIcons is not defined
at Object.install (index.8942f36c.js:44:2101)
at Object.use (vue.global.js:5190:20)
at index.8942f36c.js:44:3839
这个问题说明上面cdn配置,各js是有加载顺序,不能随便的写,vue
的引入,要在element-plus
之前
2 vite编译
2.1 多余标签的问题
下面的代码,在webpack中可以build通过,但是在vite中是不行,明显是代码错误,但是开发工程师却忽略了。
2.2 v-model cannot be used on a prop
是因为 prop 是单向数据流,父组件向子组件传递值,子组件不应直接修改这些值
ERROR error during build: 11:09:35
SyntaxError: v-model cannot be used on a prop, because local prop bindings are not writable.
Use a v-bind binding combined with a v-on listener that emits update:x event instead.
at createCompilerError (E:\workspace\vuework\acc3\node_modules\@vue\compiler-core\dist\compiler-core.cjs.js:18:17)
at Object.transformModel (E:\workspace\vuework\acc3\node_modules\@vue\compiler-core\dist\compiler-core.cjs.js:5052:21)
处理方案
然后watch其变化即可
2.3 expects exactly one child element or component.
期望仅有一个子元素或组件作为其内容,但你可能提供了多个子元素或没有提供任何子元素
处理方案如下,按照下面进行拆分
<transition name="fade-transform" mode="out-in">
<tax-declaration ref="taxDeclaration" @change='change' v-if="isShow"/>
</transition>
<transition name="fade-transform" mode="out-in">
<tax-add ref="taxAdd" @change='change' v-if="!isShow"/>
</transition>
2.4 [vite:vue] v-model value must be a valid JavaScript member expression.
跟2.2一张,只是这是设置一个对象作为参数。
2.5 图片加载问题
下面的处理方式在vue3和vite架构中是不支持的
.voucher_debit {
background: url("~@/assets/voucher/格.png");
background-repeat: repeat-y;
background-size: 100%;
}
调整为
.voucher_debit {
background: url("@/assets/voucher/ge.png");
background-repeat: repeat-y;
background-size: 100%;
}
3 element-plus相关
3.1 table找不到doLayout问题
element-ui
有的doLayout
即使调整为 this.$nextTick(
,调试发现that.$refs.table
还是为空
3.2 el-form-item__label问题
在element-plus
下写法有些变化,
在element-ui
下面就有
原先写法
<span slot="label">
<span class="span-box" >
<!-- <i class="iconfont iconicon1-12" /> -->
<span> 账套启用年月 </span>
</span>
</span>
应调整为
<template #label>
<span >
<span class="span-box" >
<!-- <i class="iconfont iconicon1-12" /> -->
<span> 账套启用年月 </span>
</span>
</span>
</template>
3.3 <el-popover调整
涉及slot="reference"
改造,否则显示不出来
<el-button class="btn" type="text" style="color: #4f71ff;" slot="reference">备注</el-button>
应调整为
<template #reference>
<el-button class="btn" type="text" style="color: #4f71ff;">备注</el-button>
</template>
el-select
、el-date-picker
等需要添加:teleported="false"
,如下。否则el-popover自动关闭
<el-select v-model="form.startPeriod" class="filter-item" :teleported="false">
<el-option v-for="item in periodOptions" :key="item.period" :label="item.periodFormat" :value="item.period" />
</el-select>
3.3 日期picker-options被弃用
看似是一个很简单的日期初始化,初始化为当前日期,结果出现了一个2024-02-01
,搞不清楚换成element-plus
后,是怎么赋值上去的。
<el-date-picker v-model="voucher.vDate" type="date" placeholder="选择日期" class="w185" @change="dateChange" :clearable='false' value-format="yyyy-MM-dd HH:mm:ss" :picker-options="pickerOptions"> </el-date-picker>
之所以出现这个问题,一定是出在:picker-options="pickerOptions"
,因为不可能一个默认值都会出错,推论是element-plus
将这个属性废弃了,查看官网果然没有此属性,取而代之的是disabled-date
pickerOptions(time){
// 日期界定
return this.dataList && this.dataList.length > 0 ? this.disabledDate(time) : this.disabledBindTime(time)
},
disabledDate(time) { //结转当月
const timeFormat = moment(time).format('YYYY-MM-DD')
if (this.dataList.length > 0) {
if (this.dataList.indexOf(timeFormat) >= 0) {
return false
}
return true
} else {
return false
}
},
禁用日期现在好了,但是初始化日期的问题依旧没有解决。
这样只有一种可能就是出现再value-format
上,element-plus
不支持yyyy-MM-dd
这种写法,改用YYYY-MM-DD
,这样日期就对了。
下面的日期也有问题
同样的原因,element-plus
日期格式需要写成全大写的。
3.4 el-checkbox-group样式问题
样式问题需要跟踪是怎么被覆盖的。
跟踪css中盒子模型,发现高度为0.对比应该是少了line-height
,当然这个问题看似element-plus关系并不大
接着可以推测出less
加载有问题,查看页面资源,发现有
继续调试样式发现.el-checkbox-group
把行高给重置为0了。
而elemetnui中是没有这个样式的,最终确认还是兼容性问题
于是重写一下,这样的问题,在列表界面给el-checkbox-group
增加行高
.el-checkbox-group{
line-height: 40px;
}
3.5 ElementPlusError: [ElAutocomplete] autocomplete suggestions must be an array
同样的代码一直到element-plus
,那基本可以推断就是兼容性问题了。在下面的回调方法中添加[]
问题处理
3.6 el-col自定义宽度
在element-ui
中el-col
中可以定义style,从而自定义设置宽度,但是这样就破坏自身的栅格系统。
其实这种情况完全可以避免,使用:span
就可以,没必要这样搞。不清楚为什么工程师当初为什么要这么做。