Blog

Hello vue3

2021-12-08

#前端
#Vue3
#Twitter Monitor
#水

最近给 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-index1000的锅,需要设置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 已经获取不到被 abortsignal 了,因为状态已经被下一行的 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

打包大小问题

感觉自己也没塞什么,打包大小直接快翻倍了

让我想想

一些问题也没什么头绪怎么修,不过总算能用了就先凑合着吧

摆烂了

摆烂了


评论区