完成第一个 Vue3.2 项目后,使用体会

打印 上一主题 下一主题

主题 879|帖子 879|积分 2639

第一次Composition API

在vue3.2中,正式支持了script setup的写法,这样可以大大简化组件的代码量,减少一些重复操作,我认为当你写vue3时,应该把这当作默认写法。在vue3.2之前,一般会这样写。
  1. [/code]那么现在,我们可以这样写,对比一下,减少了多少行代码呢
  2. [code]
复制代码
PS:之后的代码我会省略script setup,默认都在script setup标签下。
也许你会觉得这样就更简单了,其实恰恰相反,CompositionAPI其实要求你对逻辑处理有更清晰的认识,对于封装有更高的要求,否则,你一样会写成比以前更丑的代码。例如:
  1. const a = ref(0)
  2.    const b = ref('')
  3.    const c = ref(true)
  4.    const d = reactive({})
  5.    const actionA = ()=>{a.value++}
  6.    const actionC = ()=>{c.value=!c.value}
  7.    const actionB = ()=>{b.value += 'test' }
  8.    const actiond = async ( )=> {
  9.        const res =  await ajax(`url`)
  10.        d.a = res.a
  11.        d.b = res.b
  12.        d.c = res.c
  13.    }
  14.    const resetD = ()=>{
  15.        Object.keys(d).forEach(key=>delete d[key])
  16.    }
复制代码
这一堆代码其实就是当你没有考虑逻辑,没有想过封装的时候,像流水账一样直接写出来的代码,这些代码真的比optionsApi更好阅读吗,当然不。
这里更加混乱,你很难一眼看出某个函数用的是哪个变量,顺序混乱,这时候需要封装,需要组合,这也是CompositionAPI的含义之一。
  1. /usePage.js
  2. export default ()=>{
  3.     const a = ref(0)
  4.    const b = ref('')
  5.    const c = ref(true)
  6.     const actionA = ()=>{a.value++}
  7.    const actionC = ()=>{c.value=!c.value}
  8.    const actionB = ()=>{b.value += 'test' }
  9.    //这时候需要写return
  10.    return {
  11.        a,actionA,
  12.        b,actionB,
  13.        c,actionC
  14.    }
  15. }
  16. // usePageD.js
  17. export default ()=>{
  18. const d = reactive({})
  19. const actionD = async ( )=> {
  20.        const res =  await ajax(`url`)
  21.        d.a = res.a
  22.        d.b = res.b
  23.        d.c = res.c
  24.    }
  25.    const resetD = ()=>{
  26.        Object.keys(d).forEach(key=>delete d[key])
  27.    }
  28.    return {
  29.        d,actionD,resetD
  30.    }
  31. }
复制代码
这时候,当我们在不同的组件中使用时,我们可以按需使用,假设我们现在有A和D两个组件
  1. //组件A
  2. import usePage from './usePage'
  3. const {a,actionA} = usePage()
  4. //组件D
  5. import usePage from './usePageD'
  6. const {actionD,resetD} = usePageD()
复制代码
上述两种,自然时封装组合后更好阅读。更方便的是,他有更好玩的用法。我目前这个项目是一个iOS混合开发的,这其中必不可少的需要用的jsBridge,由于iOS原生的限制,所有回调都是通过其他函数接收的。例如,下方是我调取原生A方法时的代码
  1. //jsBridge.js
  2. const callBridge = (msg)=>{
  3. try {
  4.      window.webkit.xxxHandler.postMessage(msg)
  5. }catch(e){
  6.      console.log(msg)
  7. }
  8. }
  9. export const bridgeA = (id,cb='')=>{
  10.     const msg = {
  11.      func:'A',
  12.      params:{id},
  13.      cb
  14.     }
  15.     callBridge(msg)
  16. }
复制代码
而原生则会这样告诉我结果(这块是伪代码,毕竟我不会iOS)
  1. evaluateJavaScript(cb(data))
复制代码
当我使用的时候,就会有这种逻辑
  1. //App.vue
  2. const store = useStore()
  3. window.test = function(data){
  4.     store.commit('saveA',data)
  5. }
  6. //其他组件中
  7. const handleClick = ()=>{
  8.     bridgeA('123','test')
  9. }
复制代码
而现在,我可以不需要通过vuex了,这样写不香吗?
  1. //useBridgeA.js
  2. export default ()=>{
  3. const id = ref('')
  4. const saved = reactive({})
  5. window.test = function(data){
  6.     saved.data = data   
  7. }
  8. const handleClick = ()=>{
  9.     bridgeA('123','test')
  10. }
  11. onBeforeUnmount(()=>{window.test = null})
  12. return {saved,handleClick,id}
  13. }
复制代码
最妙的是,这里实现当使用时注册回调,不使用时移除,通过reactive通信,而且可以把回调方法隐藏起来,我需要的只是结果,而不需要把所有代码都在外层。
当我写组件时,代码将更加简单
  1. <template>
  2.   <input v-model="id" />
  3.   <button @click="handleClick">
  4.     Action A
  5.   </button>
  6. </template>
复制代码
这里其实我也确立了一些我的vue3的写法吧。
组合不仅是功能点的组合,更是把一些关联性比较高的方法,变量放到一起。
在上面这个例子,其实我们可以把回调方法再抽离出来,放一个单独的文件中,我再import,但是这样只会让项目文件越来越多,每次查找的文件越来越多罢了。
思考setup

很少有人会去想,为什么这个新的生命周期叫setup,set up 有建立的意思,难道意思仅仅是这个App创建时吗,那么created显然更好理解一些。
我认为,setup是一个链接,是把数据和template连接起来的一个桥梁,因此才会使用这个动词,本质上这不是一个生命周期,是一个动作,是我们把数据和Vue连接起来。
我把你做的webApp比作一台机器,setup就好比电源线,你把你变量,逻辑作为电源,输入到电源线,机器就启动了。
最常见的问题,忘记写.value

其实在vue3中,我更喜欢用ref,ref结构简单,有着更可靠更方便的响应式。例如,当我们需要声明一个响应式的对象时,你可以有这两种写法
  1. const a = shallowRef({})
  2. const b = reactive({})
复制代码
但是,当你需要替换整个对象时怎么办?对于变量来说,直接修改value即可。
  1. a.value = {c:1}
复制代码
对于变量b,那就麻烦了,如果你的对象层级比较简单,我能想到的方法就是用Object.assign
  1. Object.assign(b,{c:1})
复制代码
如果只是删除这个c这属性,对于变量a,很简单
  1. a.value = {}
复制代码
对于变量b呢,使用了reactive的那个呢,显然更加麻烦
  1. b=reactive({}) // 报错
复制代码
能直接这样写吗,不行,这样会报错,因为b是一个const。于是乎,你简单的思考一下,把const 改为let
  1. let b = reactive({})
  2. b.c = 1
  3. b = reactive({})
复制代码
理论上这样没有问题,在b没有别的依赖或者是被别的变量依赖的时候。某种程度上讲,这样也会丢失响应性。你只能这样做,这也是我之前为什么要写reset的原因
  1. delete b.c
  2. //假设b这个变量中有很多属性,则需要遍历
  3. Object.keys(b).forEach(key=>delete b[key])
复制代码
上面这些其实都是一些容易被忽略的点,也是我为什么更推荐ref的原因,但是有利有弊,ref最大的问题是容易忘记写.value
  1. const a = ref(0)
  2. a=1 //报错
  3. //做判断的时候
  4. if(a){ //永远为true,因为a是一个对象,不是数字}
复制代码
这时候,我推荐你使用unref,上面的if判断应该这样写
  1. const a = ref(0)
  2. if(unref(a)>0){
  3.   // do sth
  4. } else {
  5.   // do another
  6. }
复制代码
你可以毫无心智负担的使用unref,哪怕这个变量不是ref
style v-bind 的优缺点

style v-bind可能很多人不熟悉,我把这称之为vue对css变量的hack。我项目中偶也也会使用一些css变量。
具体的css变量的教程,大家可以看一下这个链接www.ruanyifeng.com/blog/2017/05/css-variables.html
  1. <template>
  2.   <p>123</p>
  3. </template>
复制代码
这样是纯粹的原生css的写法,vue帮我们做了一个hack.这里需要注意,style中的v-bind里面是一个字符串。
  1. <template>
  2.   <p>123</p>
  3. </template>
复制代码
但是我发现一个问题,在某些情况下的伪元素中的content属性似乎不生效,依旧是上面那个模板,我多写几个p
  1.     <template>
  2.   <p>123</p>
  3. </template>  <template>
  4.   <p>123</p>
  5. </template>  <template>
  6.   <p>123</p>
  7. </template>  <template>
  8.   <p>123</p>
  9. </template>  
复制代码
这时候v-bind似乎没生效,这个伪元素不显示,也不知道是bug还是什么,这时候我建议你这样写
  1.     <template>
  2.   <p>123</p>
  3. </template>  <template>
  4.   <p>123</p>
  5. </template>  <template>
  6.   <p>123</p>
  7. </template>  <template>
  8.   <p>123</p>
  9. </template>  
复制代码
pinia or not

pinia约等于vuex5,使用起来和vuex稍有不同,我在项目中是这样使用的
  1. // store/user.js中定义具体的store
  2. export const UserStore =  defineStore('user', {
  3.   state:()=>({
  4.     name:'',
  5.     id:''
  6.   })
  7.   getters:{
  8.     nameId:state=>```{state.name}_``{state.id}`
  9.   }
  10. actions:{
  11.   async getUserInfo(){}
  12. }
  13. })
  14. //store/index.js
  15. //这样写的好处是,以后引用的时候可以直接from '@/store',并且当文件多了,可以用通过webpack的require.context或者vite的import blob来自动处理
  16. export {UserStore} from './user'
复制代码
比vuex来说少了一个mutation,也不能说没有,只是用$patch函数代替了,使用起来更灵活
  1. import UserStore from  '@/store'
  2. const user = UserStore()
  3. user.name = 'test'
  4. //or
  5. user.$patch({
  6.   name:'test',
  7.   id:123
  8. })
  9. //or
  10. user.$patch(state =>{
  11.   state.name = 'test'
  12.   state.id = 123
  13. })
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

tsx81428

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表