完成第一个 Vue3.2 项目后,这是我的技术总结

news/2024/7/10 1:31:13 标签: vue, js, java, python, javascript
js_content">

第一次Composition API

vue3.2中,正式支持了script setup的写法,这样可以大大简化组件的代码量,减少一些重复操作,我认为当你写vue3时,应该把这当作默认写法。在vue3.2之前,一般会这样写。

<script>
   export default {
     setup(props,ctx){
      const a = ref(0)
      //必须return才能在template中使用,这里就存在一个重复操作的问题,每次都得cv,万一忘记就得检查
      return {
          a
      }
     }
   }
</script>

那么现在,我们可以这样写,对比一下,减少了多少行代码呢

<script setup>
    const a = ref(0)
</script>

PS:之后的代码我会省略script setup,默认都在script setup标签下。

也许你会觉得这样就更简单了,其实恰恰相反,CompositionAPI其实要求你对逻辑处理有更清晰的认识,对于封装有更高的要求,否则,你一样会写成比以前更丑的代码。例如:

const a = ref(0)
   const b = ref('')
   const c = ref(true)
   const d = reactive({})
   const actionA = ()=>{a.value++}
   const actionC = ()=>{c.value=!c.value}
   const actionB = ()=>{b.value += 'test' }
   const actiond = async ( )=> {
       const res =  await ajax(`url`)
       d.a = res.a
       d.b = res.b
       d.c = res.c
   }
   const resetD = ()=>{
       Object.keys(d).forEach(key=>delete d[key])
   }

这一堆代码其实就是当你没有考虑逻辑,没有想过封装的时候,像流水账一样直接写出来的代码,这些代码真的比optionsApi更好阅读吗,当然不。

这里更加混乱,你很难一眼看出某个函数用的是哪个变量,顺序混乱,这时候需要封装,需要组合,这也是CompositionAPI的含义之一。

//usePage.js
export default ()=>{
    const a = ref(0)
   const b = ref('')
   const c = ref(true)
    const actionA = ()=>{a.value++}
   const actionC = ()=>{c.value=!c.value}
   const actionB = ()=>{b.value += 'test' }
   //这时候需要写return
   return {
       a,actionA,
       b,actionB,
       c,actionC
   }
}
// usePageD.js
export default ()=>{
const d = reactive({})
const actionD = async ( )=> {
       const res =  await ajax(`url`)
       d.a = res.a
       d.b = res.b
       d.c = res.c
   }
   const resetD = ()=>{
       Object.keys(d).forEach(key=>delete d[key])
   }
   return {
       d,actionD,resetD
   }
}

这时候,当我们在不同的组件中使用时,我们可以按需使用,假设我们现在有A和D两个组件

//组件A
import usePage from './usePage'
const {a,actionA} = usePage()

//组件D
import usePage from './usePageD'
const {actionD,resetD} = usePageD()

上述两种,自然时封装组合后更好阅读。更方便的是,他有更好玩的用法。我目前这个项目是一个iOS混合开发的,这其中必不可少的需要用的jsBridge,由于iOS原生的限制,所有回调都是通过其他函数接收的。例如,下方是我调取原生A方法时的代码

//jsBridge.js
const callBridge = (msg)=>{
 try {
     window.webkit.xxxHandler.postMessage(msg)
 }catch(e){
     console.log(msg)
 }
}
export const bridgeA = (id,cb='')=>{
    const msg = {
     func:'A',
     params:{id},
     cb
    }
    callBridge(msg)
}

而原生则会这样告诉我结果(这块是伪代码,毕竟我不会iOS)

evaluateJavaScript(cb(data))

当我使用的时候,就会有这种逻辑

//App.vue
const store = useStore()
window.test = function(data){
    store.commit('saveA',data)
} 
//其他组件中
const handleClick = ()=>{
    bridgeA('123','test')
}

而现在,我可以不需要通过vuex了,这样写不香吗?

//useBridgeA.js
export default ()=>{
const id = ref('')
const saved = reactive({})
window.test = function(data){
    saved.data = data    
}
const handleClick = ()=>{
    bridgeA('123','test')
}
onBeforeUnmount(()=>{window.test = null})
return {saved,handleClick,id}
}

最妙的是,这里实现当使用时注册回调,不使用时移除,通过reactive通信,而且可以把回调方法隐藏起来,我需要的只是结果,而不需要把所有代码都在外层。

当我写组件时,代码将更加简单

<template>
<input v-model="id" />
<button @click="handleClick">
Action A
</button>
</template>
<script setup>
import useBridgeA from './useBridgeA'
const {id,handleClick} = useBridgeA()
</script>

这里其实我也确立了一些我的vue3的写法吧。

组合不仅是功能点的组合,更是把一些关联性比较高的方法,变量放到一起。

在上面这个例子,其实我们可以把回调方法再抽离出来,放一个单独的文件中,我再import,但是这样只会让项目文件越来越多,每次查找的文件越来越多罢了。

思考setup

很少有人会去想,为什么这个新的生命周期叫setup,set up 有建立的意思,难道意思仅仅是这个App创建时吗,那么created显然更好理解一些。

我认为,setup是一个链接,是把数据和template连接起来的一个桥梁,因此才会使用这个动词,本质上这不是一个生命周期,是一个动作,是我们把数据和Vue连接起来。

我把你做的webApp比作一台机器,setup就好比电源线,你把你变量,逻辑作为电源,输入到电源线,机器就启动了。

最常见的问题,忘记写.value

其实在vue3中,我更喜欢用ref,ref结构简单,有着更可靠更方便的响应式。例如,当我们需要声明一个响应式的对象时,你可以有这两种写法

const a = shallowRef({})
const b = reactive({})

但是,当你需要替换整个对象时怎么办?对于变量来说,直接修改value即可。

a.value = {c:1}

对于变量b,那就麻烦了,如果你的对象层级比较简单,我能想到的方法就是用Object.assign

Object.assign(b,{c:1})

如果只是删除这个c这属性,对于变量a,很简单

a.value = {}

对于变量b呢,使用了reactive的那个呢,显然更加麻烦

b=reactive({}) // 报错

能直接这样写吗,不行,这样会报错,因为b是一个const。于是乎,你简单的思考一下,把const 改为let

let b = reactive({})
b.c = 1
b = reactive({})

理论上这样没有问题,在b没有别的依赖或者是被别的变量依赖的时候。某种程度上讲,这样也会丢失响应性。你只能这样做,这也是我之前为什么要写reset的原因

delete b.c
//假设b这个变量中有很多属性,则需要遍历
Object.keys(b).forEach(key=>delete b[key])

上面这些其实都是一些容易被忽略的点,也是我为什么更推荐ref的原因,但是有利有弊,ref最大的问题是容易忘记写.value

const a = ref(0)
a=1 //报错
//做判断的时候
if(a){ //永远为true,因为a是一个对象,不是数字}

这时候,我推荐你使用unref,上面的if判断应该这样写

const a = ref(0)
if(unref(a)>0){
 // do sth
} else {
 // do another
}

你可以毫无心智负担的使用unref,哪怕这个变量不是ref

style v-bind 的优缺点

style v-bind可能很多人不熟悉,我把这称之为vue对css变量的hack。我项目中偶也也会使用一些css变量。

具体的css变量的教程,大家可以看一下这个链接www.ruanyifeng.com/blog/2017/05/css-variables.html

<template>
<p>123</p>
</template>
<style scoped>
p{
 color:var(--pcolor)
}
</style>

这样是纯粹的原生css的写法,vue帮我们做了一个hack.这里需要注意,style中的v-bind里面是一个字符串。

<template>
<p>123</p>
</template>
<script setup>
const pcolor = ref('#000')
</script>
<style scoped>
p{
 color:v-bind('pcolor')
}
</style>

但是我发现一个问题,在某些情况下的伪元素中的content属性似乎不生效,依旧是上面那个模板,我多写几个p

<template>
<div>
    <p>123</p>
    <p>123</p>
    <p>123</p>
    <p>123</p>
</div>
</template>
<script setup>
const text = ref('hello')
</script>
<style scoped>
div p:first-of-type:before{
 content:v-bind('text')
}
</style>

这时候v-bind似乎没生效,这个伪元素不显示,也不知道是bug还是什么,这时候我建议你这样写

<template>
<div>
    <p :data-text="text">123</p>
    <p>123</p>
    <p>123</p>
    <p>123</p>
</div>
</template>
<script setup>
const text = ref('hello')
</script>
<style scoped>
div p:first-of-type:before{
 content:attr(data-text)
}
</style>

pinia or not

pinia约等于vuex5,使用起来和vuex稍有不同,我在项目中是这样使用的

// store/user.js中定义具体的store
export const UserStore =  defineStore('user', {

state:()=>({
    name:'',
    id:''
})
getters:{
nameId:state=>`${state.name}_${state.id}`
}
actions:{
    async getUserInfo(){}
}
})

//store/index.js
//这样写的好处是,以后引用的时候可以直接from '@/store',并且当文件多了,可以用通过webpack的require.context或者vite的import blob来自动处理
export {UserStore} from './user'

vuex来说少了一个mutation,也不能说没有,只是用$patch函数代替了,使用起来更灵活

import UserStore from  '@/store'
const user = UserStore()
user.name = 'test'
//or
user.$patch({
name:'test',
id:123
})
//or 
user.$patch(state =>{
    state.name = 'test'
    state.id = 123
})

问题是在js环境下,Webstorm似乎没有代码提示?

完全升级你的项目依赖吧

既然都已经使用vue3了,意味着你本来就不再去兼容ie8,ie9这些,什么你可以把你的依赖完成升级到es8,es9,毫无保留的使用fetch、?. 、?? 这些最新的语法,获取更好的编程体验。

作者:冒菜师

https://juejin.cn/post/7083685762092236830


http://www.niftyadmin.cn/n/1250831.html

相关文章

java集合------概述

一.概述 Java Collection Framework (JCF) 提供给我们一系列的类和接口,方便开发者处理集合对象. 在Java 2之前&#xff0c;Java是没有完整的集合框架的。它只有一些简单的可以自扩展的容器类&#xff0c;比如Vector&#xff0c;Stack&#xff0c;Hashtable等。这些容器类在使用…

java集合------Iterable接口

Iterable接口是java 集合框架的顶级接口,实现此接口使集合对象可以通过迭代器遍历自身元素,我们可以看下它的成员方法 修饰符和返回值方法名描述Iterator<T>iterator()返回一个内部元素为T类型的迭代器default voidforEach(Consumer<? super T> action)对内部元素…

如何把前端项目写成一座屎山?

前言最近几年前端发展的非常快&#xff0c;SPA的繁荣让前端的工程化也越来越重。在很多场景下&#xff0c;前端的复杂度和难度也早已经超过了后端。但快速的发展下&#xff0c;前端也逐渐暴露出了许多问题。众所周知&#xff0c;前端从业人员很少谈程序的设计原则或设计思想。设…

java集合------Collection

一.概述 Collection是集合框架的根接口.不同的集合具有不同的特性,比如有的集合可以有重复元素,有的不可以,有的可以排序,有的不可排序,如此等等,而Collection作为集合的根接口,它规范定义了集合的通用方法,一个集合我们可以看作一个在内存中的小型数据库,而数据库的常用操作无…

一个好玩的 VSCode 插件

Svg Preview插件名&#xff1a;Svg Preview功能&#xff1a;显示 SVG 图片&#xff0c;并且可以自由编辑

java集合------Set

一.概述 Set是一种没有重复元素的集合,Set 注重独一无二的性质,该体系集合用于存储无序(存入和取出的顺序不一定相同)元素&#xff0c;值不能重 复。它所有的方法都是直接继承自Collection接口,并且添加了一个对重复元素的限制.Set要求强化了equals和hashCode两个方法,以使Set集…

浏览器 DevTools 你真的会用吗?

Start本文将会介绍浏览器devtool的一些常用工具方法&#xff0c;这些工具能够能够以可视化的方式展现当前网页情况&#xff0c;我们也能快速定位代码问题&#xff0c;如果我们能很好的利用起来&#xff0c;那就能写出高质量代码。Performance(重点)强大的性能监控工具工具栏ima…

java集合------List

一.概述 List是一种有序集合,有时也被称为序列,可以有重复的元素.List集合相比Collection,除了直接继承的方法外,有以下拓展的操作方法 位置访问---可以基于元素索引来操作元素,比如get,set,add,addAll和remove方法都支持这一点搜索---在集合中搜索一个特定对象,并返回它的索引…