最近给 Twitter Monitor 前端部分升级到 Vue3
,就讲讲 欢(Ku)乐(Bi)的 升级故事吧
前情提要
给这玩意升级vue大版本的事我干了好几回了,每次都到一半顶不住了一个 git stash
回滚了。这次升级的前一晚我又一次这样做了,总之就是非常后悔……于是顶着不爽又来一遍。
*注:写文章时我不知道 git stash pop
这种东西
升级过程
按照官方迁移指南走了个流程,什么事都没有发生直接白屏了,调完对应的错误以后,就什么都不给纯白屏了。然后开始了改改改(以下顺序不分先后)
this.$root -> vuex
因为我在使用vue2的时候大量使用 this.$root
来充当全局变量,在试过vuex以后,我还是用vuex重构了这部分内容,这种转换不是简单的覆盖就能完成,我还是花了一点时间将原本混乱的直接赋值逐步修改成使用计算属性引入,使用 $store.commit
改动
Vue.prototype -> provide/inject
在vue2时,我使用Vue.prototype来挂全局方法,虽然很方便(随时随地都能靠this来访问内容),但不是很应该跑去污染原型链,所以我换成了推荐的 provide/inject 模式
//main.js
...
const foo = () => {console.log('hi')}
const app = createApp(App)
...
app.provide('foo', foo)
...
//example.vue
...
export default {
setup () {
const foo = inject('foo')
return {
foo
}
},
mounted: function() {
this.foo
}
}
2022/02/10 更新:
我把常用的函数都丢到独立的文件里面,再 export
导出
//share.ts
const shareFoo = (text: string = 'hello') => {
console.log(text)
}
export {shareFoo}
//example.vue
import {shareFoo} from 'share.ts'
shareFoo('world')
element-ui -> element-plus
翻看 package.json 的提交历史,你会发现我一直用的都是自己打包的element-ui,因为我刚选的时候这玩意要啥缺啥,用得很难受,我还写过一篇文章 Element-ui填坑指北,吐槽遇过的坑;这玩意升级到vue3还是继续折磨人,包括但不限于
- 升级指南在讲谜语
- 推荐的自动引入是什么玩意,手动引入少了一半的大小
- 不能点击图片外区域关闭图片预览
- 使用了固钉(Affix)以后手机划动屏幕时内容会抖~~因为
offset
只能设置数字,我看着我的1.5rem
傻了(于是我在下一个commit就换回来了)<!--position: sticky--> <div :style="{'position': 'sticky', 'top': '1.5rem', 'z-index': 1000}"> ... </div> <!--el-affix--> <el-affix :offset="22" style="width: 100%" target="#left-card"> ... </el-affix>
被 position: sticky 包裹的组件开出来的遮罩有它自己的想法(错怪element-plus
了,这是bootstrap
的组件的z-index
是1000
的锅,需要设置z-index
……以及大图预览有一个z-index
属性可以拉满就不会被覆盖了)就是不上就是玩
- input组件背景色覆盖边框问题
逼死强迫症
- 错位的图标,翻了一下issues,就差一个方向就凑齐偏上下左右了……
- (容我再想想)
axios -> fetch
我刚开始学vue的时候对ajax的认知还停留在 XMLHttpRequest
和 jQuery 的 $.GET
,所以看到 Vue2 的计算属性这章时看到了个 axios
就先入为主用上了,后来又因为想对IE的兼容,就一直没做改动。
既然升级到了 Vue3,就不用管对 IE 的兼容了,不如直接上 fetch
,我根据我的需求对原本使用 axios
的部分做了一个简单的转换
//axios
import axios from "axios"
const CancelToken = axios.CancelToken
let cancel = function () {}
export default {
mounted: function() {
new CancelToken(c => cancel = c);
},
methods: {
foo: function () {
axios.get("https://example.com/example.json", {
cancelToken: new CancelToken(c => cancel = c)
}).then(response => {
console.log(response.data)//反序列化后的数据
}).catch(e => console.log(e))
}
}
}
//fetch
export default {
setup () {
let controller = [new AbortController()]
return { controller }
},
methods: {
foo: function () {
this.controller[this.controller - 1].abort()
this.controller.push(new AbortController())
fetch("https://example.com/example.json", {
signal: this.controller[this.controller.length - 1].signal
}).then(async response => {
response = await response.json()//反序列化
console.log(response)
}).catch(e => {
if (!this.controller[this.controller.length - 1].signal.aborted) {
//AbortController 干的
console.log("by AbortController")
} else {
//别的问题
console.log(e)
}
})
}
}
}
当然转换并不是完美的,有一点瑕疵,abort 的时候后面的 catch 已经获取不到被 abort
的 signal
了,因为状态已经被下一行的 new AbortController()
覆盖掉
塞进数组里面就解决问题了(新的问题又来了,如何保证这个数组不被篡改呢)
vue-i18n -> vue-i18n@next
这个没什么问题,迁移指南说得挺详细的
vue-meta -> @vueuse/head
nuxt.js 的vue3支持还在咕咕咕,作为插件的vue-meta虽然说是支持了Vue3,但兼容似乎不是很完美,我就换了 @vueuse/head,写法几乎没变,上手没什么问题
blurhash -> removed
是的,被我说了好看好用的 blurhash 被我移除了,因为暂时没找到组件,虽然照葫芦画瓢写了一个,但是有着很严重的性能问题,会渲染图片时会阻塞全局JavaScript的执行,我一时也没什么头绪,就删了
Proxy
vuex来的数据全是proxy,看了半天看了个云里雾里,就把以前用 watch 处理的全改成用 computed 了
2022/02/10 更新
满脑子都是 .value
打包大小问题
感觉自己也没塞什么,打包大小直接快翻倍了
让我想想
一些问题也没什么头绪怎么修,不过总算能用了就先凑合着吧
摆烂了