Vue3---(setup,ref函数,reactive函数,Vue3.0的响应原理,计算属性computed)

516 阅读3分钟

setup

理解

1.Vue3.0中一个新的配置项,值为一个函数

2.setup是所有Composition API(组合API)表演的舞台

3.组件中所有用到的方法,变量,计算属性,数据等全部配置在里面

4.不要与vue2的配置混合使用,因为他们(data,methods,computed......)可以访问setup中的内容,而setup访问不到vue2的配置。如果配置了vue2的设置,重名了,setup的优先级更高

5.setup不能是一个async函数,因为async函数返回的是一个promis对象,不再是return的对象,因此模板看不到return对象中的东西

setup的两种写法

1.返回值为一个对象,将对象中的属性拿来使用

<template>
  <div class="home">
    <h1>显示vue3.0的数据和方法</h1>
    <h2>姓名:{{name}}</h2>
    <h2>年龄:{{age}}</h2>
    <button @click="sayName()">点击测试vue3.0的方法</button>
  </div>
</template>

<script>

export default {
  setup() {
    // 现在暂时还不考虑响应式数据的问题
    // 数据 
    let name = "李国栋";
    let age = 18;

    // 方法
    let sayName = function () {
      console.log(`我的名字是${name},我的年龄是${age}`);
    }

    return {
      name, age, sayName
    }
  }

}
</script>

2.返回值为一个渲染函数,可以自定义内容

//页面中会显示一个h1标签,标签的内容是"vue3返回渲染函数"
<script>
import {h} from 'vue'
export default {
  setup() {
    // 返回一个渲染函数
    // h相当于document.CreateElement()
    return ()=>{return h("h1","vue3返回渲染函数")}
  }
}
</script>

3.语法糖(最常用的方法),直接在script标签中加入setup属性,不用导出,直接写代码就能用

<script setup>
import {ref} from "vue"
let msg=ref(“666”)
</script>
<template>
  <div>
    
    <p>{{msg}}</p>

</template>

image.png

ref函数

作用:定义一个响应式数据

语法:const msg=ref("value")

创建一个包含响应式的数据的引用对象(reference对象)

js操作数据:msg.value

注意:可接收基本数据类型,应用数据类型

基本数据类型:响应式依然靠Object.Property()的set和get完成

引用数据类型:依靠reactive函数

<script setup>
import { computed, ref, reactive } from "vue"
import Box from "./components/Box.vue"
var msg = ref("666")
var arr1 = ref([123456798, 2, 3])

</script>

<template>
  <div>
    <p>{{arr[0]}}</p>
    <p>{{arr1[0]}}</p>
</template>

<style scoped lang="scss">

</style>

image.png

reactive函数

作用:定义一个对象类型的响应式数据(基本数据类型用ref函数)

语法:const 代理一个对象=reactive(被代理的对象)接收一个对象或者数组,返回一个代理对象(proxy对象)

注意

reactive定义的响应式数据是“深层次的”

内部基于ES6的Proxy实现,通过代理对象内部的数据都是响应式的

<script setup>
import { computed, ref, reactive } from "vue"
import Box from "./components/Box.vue"
var msg = ref("666")
var arr1 = ref([123456798, 2, 3])
function fn() {
  if (msg.value == "666") {
    msg.value = "gaibian";
    obj.a = "2222";
    arr[0] = "sfs"
    console.log("111");
  } else {
    msg.value = "666"
    obj.a = "1111"
    arr[0] = "a"
  }
}
const obj = reactive({
  a: "1111",
  b: "dassa"
})
const arr = reactive([{ title: "a", price: 10, count: 1 },
{ title: "b", price: 10, count: 2 },
{ title: "c", price: 10, count: 3 },
{ title: "d", price: 10, count: 4 },
])
//计算属性,和vue2不同的是,不再写到一块,而是分开放置 computed(n1,n2) n1计算的函数 n2(可写可不写)变的时候回调用这个函数
let tool = computed(() => {
  return arr.reduce((n1, n2) => {
    return n1 + n2.price * n2.count
  }, 0)
}, arr)
let fn1 = function (index) {
  arr[index].count++
}
</script>

<template>
  <div>
    <p>{{arr[0]}}</p>
    <p>{{arr1[0]}}</p>
    <p>{{msg}}</p>
    <p>{{obj.a}}</p>


    <button @click="fn">dianji</button>
    <div v-for="(el,index) in arr">
      <p>{{el.title}}</p>
      <p>{{el.price}}</p>
      <p>{{el.count}}</p>
      <button @click="fn1(index)">+</button>
    </div>
    <p>总价:{{tool}}</p>
  </div>
  <Box></Box>

</template>

<style scoped lang="scss">

</style>

image.png

Vue3.0的响应原理

vue2.0的响应式

  • 实现原理

    • 对象类型:通过Object.definedProperty()对属性的读取、修改进行拦截(数据劫持)

    • 数组类型:通过重写更新数据的一系列方法来实现拦截。(对数组的方法进行了包裹)

      Object.defineProperty(data,"count",{
          get(){},
          set(){}
      })
      

    存在问题:

    • 新增属性,删除属性都不会刷新界面
    • 直接通过下标修改数组,界面不会自动更新
            let person = {
                name:"李国栋",
                age:18
            }
    ​
            let p = {};
    ​
            Object.defineProperty(p,"name",{
                get(){
                    console.log("有人读取数据时调用");
                    return person.name
                },
    ​
                set(value){
                    console.log("有人修改了数据,我要去更新页面");
                    person.name = value
                }
            })
    

vue3.0的响应式

        let person = {
            name:"李国栋",
            age:18
        }
​
        let p = new Proxy(person,{
            // 读取
            get(target,proname){
                // target表示原对象  proname表示对象名
                console.log("有人读取了person上的属性",target);
                return target[proname]
            },
            // 修改或者增加
            set(target,proname,value){
                console.log("有人修改了person上的属性,我要去更新了");
                target[proname] = value
            },
            // 删除
            deleteProperty(target,proname){
                console.log("有人删除了person上面的属性,我要去调用了");
                return delete target[proname]
            },
            
        });

计算属性computed()

计算属性:和vue2不同的是,不再写到一块,而是分开放置 computed(n1,n2) n1计算的函数 n2(可写可不写)变化的时候会调用这个函数。功能和vue2相同,会缓存计算结果

写法

let 计算的属性 = computed(计算的函数,监听的变量)


let tool = computed(()=>{})

案列

<script setup>
import { computed, ref, reactive } from "vue"
import Box from "./components/Box.vue"
var msg = ref("666")
var arr1 = ref([123456798, 2, 3])
function fn() {
  if (msg.value == "666") {
    msg.value = "gaibian";
    obj.a = "2222";
    arr[0] = "sfs"
    console.log("111");
  } else {
    msg.value = "666"
    obj.a = "1111"
    arr[0] = "a"
  }
}
const obj = reactive({
  a: "1111",
  b: "dassa"
})
const arr = reactive([{ title: "a", price: 10, count: 1 },
{ title: "b", price: 10, count: 2 },
{ title: "c", price: 10, count: 3 },
{ title: "d", price: 10, count: 4 },
])
//计算属性,和vue2不同的是,不再写到一块,而是分开放置 computed(n1,n2) n1计算的函数 n2(可写可不写)变的时候回调用这个函数
let tool = computed(() => {
  return arr.reduce((n1, n2) => {
    return n1 + n2.price * n2.count
  }, 0)
}, arr)
let fn1 = function (index) {
  arr[index].count++
}
</script>

<template>
  <div>
    <p>{{arr[0]}}</p>
    <p>{{arr1[0]}}</p>
    <p>{{msg}}</p>
    <p>{{obj.a}}</p>


    <button @click="fn">dianji</button>
    <div v-for="(el,index) in arr">
      <p>{{el.title}}</p>
      <p>{{el.price}}</p>
      <p>{{el.count}}</p>
      <button @click="fn1(index)">+</button>
    </div>
    <p>总价:{{tool}}</p>
  </div>
  <Box></Box>

</template>

<style scoped lang="scss">

</style>

image.png