Vue3核心语法:选项式API和组合式API的区别(Vue2和Vue3的区别)+ref、reactive、shallowReactive、readonly、shallowReadonly、watch等

选项式API和组合式API的区别/Vue2和Vue3的区别/为什么需要Vue3?

Vue2和Vue3的最大的区别其实就是前者是选项式API,后者是组合式API。
那么我们为什么需要组合式API呢?对此,官方作者其实已经做出了回答。
我们可以打开Vue3的官网,点击侧栏最下方的“组合式API常见问答”见到如下图:
在这里插入图片描述
可以看到左边的选项式API,因为data、methods等选项是分离的,那么对于一个业务功能可能需要数据放在上面data里,方法放在下面的methods里。那么当一个组件里面有多个业务功能时,就会如左图一样,一个业务功能是一种颜色,我们可以看到,颜色分散在了各处。
而组合式API实际上更偏向于原生js的写法,让相同业务功能的代码更加聚集。

下载vscode相关插件vue-official

setup省去声明子组件(components选项)和命名当前组件(name选项)

一段vue2的代码如下:
App.vue

<template>
  <div id="app">
    <Movie></Movie>
  </div>
</template>

<script>
import Movie from './components/Movie.vue';

export default {
  name: 'App',
  components: {
    Movie
  },

}
</script>

Movie.vue

<template>
    <div>
        <h1>{{ title }}</h1>
    </div>
</template>

<script>
export default {
    name: "Movie",
    data: function () {
        return {
            title: "金刚狼"
        }
    }
}
</script>
</script>

但是在vue3中就变为了:
App.vue

<template>
  <div id="app">
    <Movie></Movie>
  </div>
</template>

<script setup>
import Movie from './components/Movie.vue';

</script>

<style>

可以看到只要在script标签中加上setup,整段export都在报错。于是我们去掉export的内容。刷新后运行发现页面仍然显示数据。
意味着我们用了setup后就不再需要申明当前组件的子组件,即不再需要components选项。但凡是import了的都会自动变为当前组件的子组件。
而且不再需要命名当前组件,即不再需要name选项。

响应式数据的声明

那么对于Movie.vue又该怎么修改呢?如果我们用了setup,就没有export,那么也就没有了data选项。没有data选项又该怎么申明响应式数据呢?
实际上vue3中的响应式数据非常像原生js的声明,分为以下几种。

reactive和shallowreactive(对象)

reative适用于声明类型是对象的响应式数据。
注意数组也是个对象,所以我们这里以数组为例

<template>
    <div>
        <h1>{{ myData }}</h1>
        <button @click="clickHandler">修改</button>
    </div>
</template>

<script setup>
import { reactive } from 'vue';

const myData = reactive([1, 2, 3])
function clickHandler() {
    myData.push(4)    
}
</script>

可以看到点击按钮后页面显示的数组就会在末尾增加4

注意,reactive申明的对象里面所有嵌套的属性或者说对象都是响应式的,只要修改就会被监听到。
譬如如下:

<template>
    <div>
        <h1>{{ myData }}</h1>
        <button @click="clickHandler">修改</button>
    </div>
</template>

<script setup>
import { reactive } from 'vue';

const myData = reactive({
    name: "shanshan",
    age: 20,
    scope: [10, 20]
})
function clickHandler() {
    myData.scope.push(30) 
}
</script>

可以发现我们修改的是第二维结构scope,也能被监听并且反向渲染到页面上。

而有时候我们的对象有比较复杂的数据结构,我们并不需要或者并不希望每一层都被监听,因为这样性能消耗会比较多,那么我们只希望第一层是响应式的,被监听,那么我们就可以使用shallowReactive
我们将myData的申明改为

const myData = shallowReactive({

此时再次运行并测试,发现scope的修改并不会渲染到页面上了。
但是如果我们继续将函数内改为

    myData.age++ 

因为属于第一层的数据,是响应式的,那么就能看到修改效果。

ref(基本数据类型)

ref适用于类型是基本数据类型的响应式数据。譬如这里

<template>
    <div>
        <h1>{{ myData }}</h1>
        <button @click="clickHandler">修改</button>
    </div>
</template>

<script setup>
import { ref } from 'vue';

const myData = ref(0)
function clickHandler() {
    myData.value++ 
}
</script>

可以看到我们在函数内修改myData的值用的是myData.value而不是myData本身。
这是因为上面的reactive是基于ES6的proxy实现的,而proxy支持的参数只有对象。而我们现在想对于一个基本类型做处理,vue3便通过ref在内部创建了一个空的对象,并且将我们初始化的基本类型数据挂载到了这个空对象的value属性上,从而达到支持声明响应式的基本数据类型的效果。

readonly

被readonly申明的变量都相当于一个常量,本身及内部属性或者对象都是只读的,不可以被修改的,且不会响应。

<template>
    <div>
        <h1>{{ myData }}</h1>
        <button @click="clickHandler1">修改1</button>
        <h2>{{ yourData }}</h2>
        <button @click="clickHandler2">修改2</button>
    </div>
</template>

<script setup>
import { readonly} from 'vue';

const myData = readonly(0)
function clickHandler1() {
    myData++ 
}

const yourData = readonly({
    name: "shanshan",
    age: 20,
    scope: [10, 20]
})
function clickHandler2() {
    yourData.scope.push(30) 
}

</script>

注意这里如果点击修改1的按钮,那么可以发现整个页面会报错。但是如果点击修改2的按钮,就不会报错。
这是因为readonly声明的变量相当于一个常量,我们是不支持修改常量的本身,所以函数1的操作会直接引发报错。
但是我们可以试图修改常量的内部属性,所以函数2的操作不会引发报错,只是并不会修改成功而已。

同样的,如果我们希望一个对象只有根属性是只读的,但是内部属性是非只读的,可修改的,那么我们可以使用shallowReadonly
将变量的申明改为如下:

const yourData = shallowReadonly({

然后打开控制台测试,可以发现控制台内的scope是会增加数据的,只不过依旧无法响应。

computed

<script setup>
import { computed, ref} from 'vue';

const myData = ref('this is a test')
const getLen = computed(() =>{
    console.log("计算属性执行了");
    return myData.value.length
})
function clickHandler1() {
    myData.value+='!'
}

</script>

watch

watch支持基本数据类型,所以传入直接写ref本身即可

<script setup>
import { ref, watch} from 'vue';

const myData = ref('this is a test')
watch(myData, (newValue, oldValue)=>{
    console.log(newValue, oldValue);
})
function clickHandler1() {
    myData.value+='!'
}

</script>

如果想要watch监听一个对象的某个属性值,那么需要用函数包裹起来,如下

<script setup>
import { reactive, watch} from 'vue';

const myData = reactive({
    name: "shanshan",
    age: 20,
    scope: [10, 20]
})
function clickHandler1() {
    myData.scope.push(30) 
}
watch(() => myData.friends, (newValue, oldValue)=>{
    console.log(newValue, oldValue);
})


</script>

watchEffect

自动监听传入的数据中所有响应式数据的变化(可以传入非响应式数据)

<template>
    <div>
        <h1>{{ myData }}</h1>
        <button @click="clickHandler1">修改1</button>
        <h2>{{ yourData }}</h2>
        <button @click="clickHandler2">修改2</button>
    </div>
</template>

<script setup>
import { readonly, ref, watch, watchEffect} from 'vue';

const myData = readonly({
    name: "shanshan",
    age: 20,
    scope: [10, 20]
})
function clickHandler1() {
    myData.age++ 
}

const yourData = ref(0)
function clickHandler2() {
    yourData.value++
}

watchEffect(()=>{
    console.log("myData.age:"+myData.age+"  yourData"+yourData.value);
})
</script>
  • 27
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

鸡鸭扣

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值