第一次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
})

完成第一个 Vue3.2 项目后,使用体会的更多相关文章

  1. 如何启动一个Vue3.x项目

    1. 安装node.js 2. cd到项目目录下 3. npm run serve Node.js下载与安装(npm) Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运 ...

  2. gitbash 本地文件提交为一个新的项目 到 gitlab

    此篇操作的环境: 已经配置好一个本地仓库,且可成功的将本地项目提交到gitlab上的对应的远程仓库. 这意味着此时你的电脑已经安装好git,有一个本地仓库存放你的项目,成功配置好一个对应的远程仓库,且 ...

  3. Vue3+Vue-cli4项目中使用腾讯滑块验证码

    Vue3+Vue-cli4项目中使用腾讯滑块验证码 简介: 滑块验证码相比于传统的图片验证码具有以下优点: 验证码的具体验证不需要服务端去验证,服务端只需要核验验证结果即可. 验证码的实现不需要我们去 ...

  4. vue3介绍-vue3创建项目-setup函数-ref和reactive-计算属性和监听-生命周期-toRefs-script setup的作用和lang=ts-vue后台管理模板

    目录 vue3介绍-vue3创建项目-setup函数-ref和reactive-计算属性和监听-生命周期-toRefs-script setup的作用和lang=ts-vue后台管理模板 昨日内容回顾 ...

  5. 如何参与一个 GitHub 开源项目?

    最近一年开源项目特别的热,很多技术大会或论坛都以开源项目作为主题进行探讨,可见这是一种趋势.而Github作为开源项目的著名托管地,可谓无 人不知,越来越多的个人和公司纷纷加入到Github的大家族里 ...

  6. 解决Eclipse建立Maven项目后无法建立src/main/java资源文件夹的办法

      建立好一个Maven项目后,如果Java Resources资源文件下没有src/main/java文件夹,并且在手动创建这个文件时提示“已存在文件”. 这说明,在这个项目配置中已经有了src/m ...

  7. eclipse中导入项目后中文成乱码解决办法

    转自:http://blog.163.com/lang_zi_ming/blog/static/1140161762010412112650774/ 编程时在往eclipse中导入项目后 项目中的中文 ...

  8. 转: maven进阶:一个多模块项目

    一个多模块项目通过一个父POM 引用一个或多个子模块来定义.父项目,通过以下配置,将子项目关联. <packaging>pom</packaging> <modules& ...

  9. Intellij IDEA采用Maven+Spring MVC+Hibernate的架构搭建一个java web项目

    原文:Java web 项目搭建 Java web 项目搭建 简介 在上一节java web环境搭建中,我们配置了开发java web项目最基本的环境,现在我们将采用Spring MVC+Spring ...

  10. 如何用Maven创建一个普通Java项目

    一下内容包括:用Maven创建一个普通Java项目,并把该项目转成IDEA项目,导入到IDEA,最后把这个项目打包成一个jar文件. 有时候运行mvn命令失败,重复运行几次就OK了,无解(可能因为网络 ...

随机推荐

  1. 安装Windows10后电脑整体速度变慢

    是不是觉得从旧版本Windows系统比如(Windows 7)升级到Windows10以后,感觉什么操作都变慢了.譬如打开文件夹,游戏加载速度变缓慢.尤其是腾讯WeGame软件进入游戏前的检测速度明显 ...

  2. [ACM]TL-Kruskal

    #include<iostream> #include<cstdio> using namespace std; struct edge { int u; int v; int ...

  3. Excel或数据库快速生成GUID

    一般一些开发软件或者网站可以直接生成guid, 比如:https://www.iamwawa.cn/guid.html 但是在某些场景下,经常在一些excel或者数据库操作需要快速生成指定格式的gui ...

  4. 教你如何通过CodeArts IDE插件调用API,高效合成语音

    摘要:本实验基于华为云自研CodeArts IDE,指导用户通过使用华为云API,来实现一个文字合成语音的应用. 本文分享自华为云社区<通过CodeArts IDE插件调用API,高效合成语音! ...

  5. 数据挖掘关联分析—R实现

    关联分析 关联分析又称关联挖掘,就是在交易数据.关系数据或其他信息载体中,查找存在于项目集合或对象集合之间的频繁模式.关联.相关性或因果结构.或者说,关联分析是发现交易数据库中不同商品(项)之间的联系 ...

  6. Nginx主要功能

    Nginx主要功能: 1.反向代理2.负载均衡3.HTTP服务器(包含动静分离)4.正向代理 一.反向代理 反向代理应该是 Nginx 做的最多的一件事了,什么是反向代理呢,以下是百度百科的说法:反向 ...

  7. 如何优雅的使用ipv6穿透内网

    背景 随着ipv6的普及,家庭宽带已经全面支持ipv6,通过简单的设置就可以让自己的内网设备获取到ipv6地址.不过这里的ipv6地址也不是固定,会定期的变化,不过通过DDNS可以解决这个问题.但是这 ...

  8. day128:MySQL进阶:MySQL安装&用户/权限/连接/配置管理&MySQL的体系结构&SQL&MySQL索引和执行计划

    目录 1.介绍和安装 2.基础管理 2.1 用户管理 2.2 权限管理 2.3 连接管理 2.4 配置管理 3.MySQL的体系结构 4.SQL 5.索引和执行计划 1.介绍和安装 1.1 数据库分类 ...

  9. MySQL(十)表空间结构:区、段与碎片区

    表空间结构:区.段与碎片区 为什么要有区? ​ B+树中的每一层的页都会形成一个双向链表,双向链表之间的物理位置可能会离得非常远,当遇到范围查询的适用场景的时候,就会定位到最左边和最右边的记录,然后沿 ...

  10. 【深度学习】【图像分类网络】(一)残差神经网络ResNet以及组卷积ResNeXt

    ResNet网络 论文:Deep Residual Learning for Image Recognition 网络中的亮点: 1 超深的网络结构(突破了1000层) 上图为简单堆叠卷积层和池化层的 ...