国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Vue3筆記——(尚硅谷張?zhí)煊鞻ue筆記)

這篇具有很好參考價值的文章主要介紹了Vue3筆記——(尚硅谷張?zhí)煊鞻ue筆記)。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

Vue3

Vue3簡介

1.Vue3簡介

? ? .2020年9月18日,Vue.js發(fā)布3.0版本,代號: One Piece(海賊王)。耗時2年多、2600+次提交、30+個RFC、600+次PR、99位貢獻者

? ? . github上的tags地址: https://github.com/vuejs/vue-next/releases/tag/v3.0.0

2.Vue3帶來了什么

? ? .性能的提升

? ? .打包大小減少41%

? ? .初次渲染快55%,更新渲染快133%。內(nèi)存減少54%

3.擁抱TypeScript

? ? . vue3可以更好的支持TypeScript

4.新的特性

? ? 1.Composition API(組合API)

? ? ? ? . setup配置

? ? ? ? . ref與reactive

? ? ? ? . watch與watchEffect

? ? ? ? . provide與inject

? ? ? ? . ...

? ? 2.新的內(nèi)置組件

? ? ? ? . Fragment

? ? ? ? . Teleport

? ? ? ? . suspense

? ? 3.其他改變

? ? ? ? . 新的生命周期鉤子

? ? ? ? . data選項應(yīng)始終被聲明為一個函數(shù)

? ? ? ? . 移除keyCode支持作為v-on的修飾符

? ? ? ? . ...

使用vue-cli創(chuàng)建工程

1.使用vue-cli 創(chuàng)建

官方文檔: https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-create

## 查看@vue/cli版本,確保@vue/cli版本在4.5.o以上

vue --version

## 安裝或者升級你的@vue/cli

npm install -g @vue/cli

## 創(chuàng)建

vue create vue_test

## 啟動

cd vue_test

npm run serve

使用vite創(chuàng)建工程

⒉使用vite 創(chuàng)建

官方文檔: https://v3.cn.vuejs.org/guide/installation.html#vite

vite官網(wǎng): https://vitejs.cn

.什么是vite? ——相對于webpack,新一代前端構(gòu)建工具。

.優(yōu)勢如下:

? ? 。開發(fā)環(huán)境中,無需打包操作,可快速的冷啟動。

? ? 。輕量快速的熱重載(HMR)。

? ? 。真正的按需編譯,不再等待整個應(yīng)用編譯完成。

##創(chuàng)建工程

npm init vite-app <project-name>

npm init vite-app vue3_test_vite

##進入工程目錄

cd <project-name>

##安裝依賴

npm install

##運行

npm run dev

分析Vue3的工程結(jié)構(gòu)

分析vue-cli所創(chuàng)建出的vue3工程

關(guān)閉語法檢查:vue3自帶的vue.config.js中的內(nèi)容直接替換為vue2的寫法也行,如下:
module.exports = {
? lintOnSave:false,//關(guān)閉語法檢查
}

App.vue中vue3中template標(biāo)簽中可以沒有根標(biāo)簽括起來

main.js

// 引入的不再是Vue構(gòu)造函數(shù)了,引入的是一個名為createApp的工廠函數(shù)
import { createApp } from 'vue'
//引入App組件
import App from './App.vue'

// createApp(App).mount('#app')
// 創(chuàng)建應(yīng)用實例對象--app(類似于之前Vue2中的vm,但app比vm更“輕”)
const app = createApp(App)

app.mount('#app')

setTimeout(() => {    
    app.unmount('#app')
}, 1000);

/* 類似vue2中的如下方式的創(chuàng)建vm掛載Vue到app掛載點,但main.js中不兼容vue2的寫法,把vue2的main.js拿來替換不能用,因為無法引入Vue
const vm = new VueElement({
    render:h =>h(App)
})
vm.$mount('app') */

vue3的開發(fā)者工具

Vue3開發(fā)者工具,可在極簡插件中下載,選那個vue圖標(biāo)右下角帶圓角矩形的

極簡插件_Chrome擴展插件商店_優(yōu)質(zhì)crx應(yīng)用下載

別使用谷歌瀏覽器下載,會自動刪除下載的文件

初識setup

是常用Composition API? ?組合式API

拉開序幕的setup

? ? 1.理解: vue3.0中一個新的配置項,值為一個函數(shù)。

? ? 2.setup是所有Composition API(組合API)“表演的舞臺”。

? ? 3.組件中所用到的:數(shù)據(jù)、方法等等,均要配置在setup中。

? ? 4.setup函數(shù)的兩種返回值:

? ? ? ? 1.若返回一個對象,則對象中的屬性、方法,在模板中均可以直接使用。(重點關(guān)注! )

? ? ? ? 2.若返回一個渲染函數(shù):則可以自定義渲染內(nèi)容。(了解)

? ? 5.注意點:

? ? ? ? 1.盡量不要與Vue2.x配置混用

? ? ? ? ? ? . Vue2.x配置(data、methos、computed...)中可以訪問到setup中的屬性、方法。

? ? ? ? ? ? ·但在setup中不能訪問到Vue2.x配置(data、methos、computed...)。

? ? ? ? ? ? ·如果有重名, setup優(yōu)先。

? ? ? ? 2.setup不能是一個async函數(shù),因為返回值不再是return的對象,而是promise,模板看不到return對象中的屬性。(后期也可以返回一個Promise實例,但需要Suspense和異步組件的配合)

App.vue

<template>
  <h1>一個人的信息</h1>
  <h2>姓名:{{name}}</h2>
  <h2>年齡:{{age}}</h2>
  <h2>性別:{{sex}}</h2>
  <h2>vue2和vue3的數(shù)據(jù)a沖突的時候的以vue3的setup為主{{a}}</h2>
  <button @click="sayHello">說話(Vue3配置的sayHello方法)</button><br/><br/>
  <button @click="sayWelcome">說話(Vue2配置的sayWelcome方法)</button><br/><br/>
  <button @click="test1">測試一下在vue2中讀取vue3中的數(shù)據(jù)和方法</button><br/><br/>
  <button @click="test2">測試一下在vue3中讀取vue2中的數(shù)據(jù)和方法</button>
</template>

<script>
import {h} from "vue"
export default {
  name: 'App',
  data() {
    return {
      sex:"男"  ,
      a:100
    }
  },
  methods:{
    sayWelcome(){
      alert('歡迎來到尚硅谷學(xué)習(xí)'); 
    },
    test1(){//在vue2中讀取vue3是可以的
      console.log(this.sex)
      console.log(this.name)
      console.log(this.age)
      console.log(this.sayHello)
    }
  },
  setup(){  // setup是所有Composition API(組合API)“表演的舞臺”。組件中所用到的:數(shù)據(jù)、方法等等,均要配置在setup中。
    //data直接往這里面寫 ,變量用let,常量用const
    let name = "張三";
    let age = 18;
    let a = 200;
    //方法也直接寫function
    function sayHello(){
      alert(`我叫${name},我${age}歲了,你好啊`)//使用``加${}傳數(shù)據(jù)
    };

    function test2(){//在vue3中讀取vue2,讀取不到
      console.log(this.name)
      console.log(this.age)
      console.log(this.sex)  // undefined
      console.log(this.sayWelcome)  // undefined
    }

    //setup的return若返回一個對象,則對象中的屬性、方法,在模板中均可以直接使用。(重點關(guān)注! )
    return{
      name,
      age,
      sayHello,
      test2,
      a,
    }
    // 若返回一個渲染函數(shù):則可以自定義渲染內(nèi)容。(了解)  會覆蓋掉template中的所有內(nèi)容
    // return()=>{ return h("h1","尚硅谷")}
    /* return()=> h("h1","尚硅谷") */

  }
}
</script>

ref函數(shù)處理基本數(shù)據(jù)類型

?除了html中標(biāo)簽中ref屬性,vue3多了一個ref函數(shù)。
ref加工后的數(shù)據(jù)就是一個對象RefImpl,reference implement引用實現(xiàn),引用實現(xiàn)的對象簡稱引用對象。里面有個value屬性,為實現(xiàn)數(shù)據(jù)響應(yīng)式的,通過還是get和set做的響應(yīng)式在__proto__原型對象中的。像vue2中的_data中的東西放在了vm上。

App.vue

<template>
  <h1>一個人的信息</h1>
  <!-- ref引用對象,在模板中不用name.value,模板自動會解析加上.value -->
  <h2>姓名:{{name}}</h2>
  <h2>年齡:{{age}}</h2>
  <button @click="changeInfo">修改人的信息</button>
</template>

<script>
import {h} from "vue"
import {ref} from 'vue'
export default {
  name: 'App',
  setup(){
    /* let name = "張三";
    let age = 18; */
    // 把普通數(shù)據(jù)變成一個響應(yīng)式的數(shù)據(jù)
    let name = ref("張三")
    let age = ref(18)

    function changeInfo(){
      /* name = '李四'
      age = 48 */
      // 由于name和age為ref函數(shù)得到的引用對象,通過get和set做的響應(yīng)式,所以我們要通過.vaue
      name.value = '李四'
      age.value = 48
    }

    return{
      name,
      age,
      changeInfo
    }


  }
}
</script>

ref函數(shù)處理對象類型的數(shù)據(jù)

對于ref函數(shù)處理的對象類型,沒有直接變?yōu)镽efIMpl應(yīng)用對象,而是變?yōu)榱薖roxy代理對象。是內(nèi)部求助的reactive函數(shù),這個函數(shù)封裝了proxy。

App.vue

<template>
  <h1>一個人的信息</h1>
  <!-- ref引用對象,在模板中不用name.value,模板自動會解析加上.value -->
  <h2>姓名:{{name}}</h2>
  <h2>年齡:{{age}}</h2>
  <h3>手機品牌:{{phone.brand}}</h3>
  <h3>手機顏色:{{phone.color}}</h3>
  <button @click="changeInfo">修改人的信息</button>
</template>

<script>
import {h} from "vue"
import {ref} from 'vue'
export default {
  name: 'App',
  setup(){
    /* let name = "張三";
    let age = 18; */
    // 把普通數(shù)據(jù)變成一個響應(yīng)式的數(shù)據(jù)
    let name = ref("張三")
    let age = ref(18)
    // ref函數(shù)處理對象類型
    let phone = ref({
      brand:"redmi", 
      color:"red"
    })

    function changeInfo(){
      /* name = '李四'
      age = 48 */
      // 由于name和age為ref函數(shù)得到的引用對象,通過get和set做的響應(yīng)式,所以我們要通過.vaue
      name.value = '李四'
      age.value = 48
      phone.value.brand="xiaomi" //ref函數(shù)對象類型的屬性修改數(shù)據(jù)
      phone.value.color="green"
    }

    return{
      name,
      age,
      changeInfo,
      phone
    }


  }
}
</script>

reactive函數(shù)

reactive函數(shù)
。作用:定義一個對象類型的響應(yīng)式數(shù)據(jù)(基本類型不要用它,要用ref函數(shù))
。語法: const 代理對象= reactive(源對象)接收一個對象(或數(shù)組),返回一個代理對象〈Proxy的實例對象,簡稱proxy對象)
。 reactive定義的響應(yīng)式數(shù)據(jù)是"深層次的”。
。內(nèi)部基于ES6的Proxy實現(xiàn),通過代理對象操作源對象內(nèi)部數(shù)據(jù)進行操作。

App.vue

<template>
  <h1>一個人的信息</h1>
  <!-- ref引用對象,在模板中不用name.value,模板自動會解析加上.value -->
  <h2>姓名:{{name}}</h2>
  <h2>年齡:{{age}}</h2>
  <h3>手機品牌:{{phone.brand}}</h3>
  <h3>手機顏色:{{phone.color}}</h3>
  <h3>hobby:{{hobby}}</h3>
  <h3>測試的數(shù)據(jù)d:{{a.b.c.d}}</h3>
  <button @click="changeInfo">修改數(shù)據(jù)</button>
</template>

<script>
import {h} from "vue"
import {ref,reactive} from 'vue'
export default {
  name: 'App',
  setup(){
    // 把普通數(shù)據(jù)變成一個響應(yīng)式的數(shù)據(jù)
    let name = ref("張三")
    let age = ref(18)
    // reactive將對象變?yōu)轫憫?yīng)式的
    let phone = reactive({
      brand:"redmi", 
      color:"red"
    })
    let a = reactive({
      b:{
        c:{
          d:666
        }
      }
    })
    let hobby = reactive(['看喜羊羊','看灰太狼','看光頭強'])

    function changeInfo(){
      name.value = '李四'
      age.value = 48
      phone.brand="xiaomi" //active函數(shù)對象類型的屬性修改數(shù)據(jù)
      phone.color="green"
      a.b.c.d=999
      hobby[0] = '看熊出沒'
    }

    return{
      name,
      age,
      changeInfo,
      phone,
      a,
      hobby
    }


  }
}
</script>

Vue2的響應(yīng)式原理的回顧

vue2.x的響應(yīng)式

. 實現(xiàn)原理:

? ? 。對象類型:通過object.defineProperty()對屬性的讀取、修改進行攔截(數(shù)據(jù)劫持)。

? ? 。數(shù)組類型:通過重寫更新數(shù)組的一系列方法來實現(xiàn)攔截。(對數(shù)組的變更方法進行了包裹)。

? ? ? ? object.defineProperty(data, 'count ', {

? ? ? ? ? ? get(){},

? ? ? ? ? ? set(){}

? ? ? ? })

. 存在問題:

? ? 。新增屬性、刪除屬性,界面不會更新。

? ? 。直接通過下標(biāo)修改數(shù)組,界面不會自動更新。

Vue2項目中的App.vue,來看vue2的響應(yīng)式存在的問題

<template>
  <div>
      <h1>我是Vue2的寫法</h1>
      <h2 v-show="person.name">姓名:{{person.name}}</h2>
      <h2>年齡:{{person.age}}</h2>
      <h2>愛好:{{person.hobby}}</h2>
      <h2 v-show="person.sex">性別:{{person.sex}}</h2>
      <button @click="addSex">添加一個sex屬性</button>
      <button @click="deleteName">添加一個name屬性</button>
      <button @click="updateHobby">修改第一個愛好的名字</button>
  </div>
</template>
<script>
import Vue from 'vue'
export default {
  name:"App",
  data() {
    return {
      person:{
        name:'張三',
        age:18,
        hobby:["看喜羊羊",'看灰太狼','看光頭強']
      }
    }
  },
  methods:{
    addSex(){
      /* console.log(this.person.sex) //undefined
      this.person.sex='女'
      console.log(this.person.sex) //'女'  確實新增了sex屬性了,但頁面不更新,defineProperties監(jiān)測不到 */
      this.$set(this.person,"sex",'女') //可通過這種和下面這種方式加上這個屬性 
      // Vue.set(this.person,"sex",'女')
    },
    deleteName(){
      /* console.log(this.person.name) // '張三'
      delete this.person.name
      console.log(this.person.name)// undefined 確實刪除了name,但頁面中監(jiān)測不到,頁面還是不變 */
      //this.$delete(this.person,"name")
      Vue.delete(this.person,"name")
    },
     updateHobby(){
      // this.person.hobby[0] = '看大大怪' // 這樣修改確實能修改,但頁面監(jiān)測不到,頁面上的數(shù)據(jù)不變
      //this.$set(this.person.hobby,0,"看大大怪")
      // 或使用數(shù)組的方法,如push shift splice等,這些方法為vue對普通方法的封裝,可以監(jiān)測到
      this.person.hobby.splice(0,1,'看小小怪')
     }
  }
}
</script>

Vue3的響應(yīng)式原理Proxy

Vue3中不存在vue2中的添加或?qū)傩曰蛐薷臄?shù)組元素的不是響應(yīng)式的頁面不變的問題

Vue3中的App.vue

<template>
  <h1>一個人的信息</h1>
  <!-- ref引用對象,在模板中不用name.value,模板自動會解析加上.value -->
  <h2 v-show="person.name">姓名:{{person.name}}</h2>
  <h2>年齡:{{person.age}}</h2>
  <h2 v-show="person.sex">性別:{{person.sex}}</h2>
  <h3>手機品牌:{{person.phone.brand}}</h3>
  <h3>手機顏色:{{person.phone.color}}</h3>
  <h3>hobby:{{person.hobby}}</h3>
  <button @click="changeInfo">修改數(shù)據(jù)</button>
  <button @click="addSex">添加一個sex屬性</button>
  <button @click="deleteName">刪除一個name屬性</button>

</template>

<script>
import {ref,reactive} from 'vue'
export default {
  name: 'App',
  setup(){
    let person = reactive({
      name:"張三",
      age:18,
      phone:{
        brand:"redmi", 
        color:"red"
      },
      hobby:['看喜羊羊','看灰太狼','看光頭強']
    })

    function changeInfo(){
      person.name = '李四'
      person.age = 48
      person.phone.brand="xiaomi" //active函數(shù)對象類型的屬性修改數(shù)據(jù)
      person.phone.color="green"
      person.hobby[0] = '看熊出沒'   //直接通過數(shù)組下標(biāo)修改元素也是可以響應(yīng)式的,頁面也會發(fā)生變化
    }
    function addSex(){
      person.sex = '男' // 添加一個不存在的屬性,頁面可以發(fā)生變化,做了響應(yīng)式,reactive的原因。
    }
    function deleteName(){
      delete person.name
    }

    return{
      person,
      changeInfo,
      addSex,
      deleteName
    }


  }
}
</script>

Object.defineProperties、new Proxy()模擬vue2和vue3的響應(yīng)式原理

響應(yīng)式原理.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script type="text/javascript">
        //源數(shù)據(jù)
        let person = {
            name : "張三",
            age : 18
        }
        //模擬vue2中實現(xiàn)響應(yīng)式
        //#region
        /* let p = {}
        Object.defineProperties(p,"name",{
            configurable:true, //聲明為可配置的,就允許被刪除了
            get(){ //有人讀取的時候調(diào)用
                return person.name
            },
            set(value){
                console.log("有人修改了name屬性,發(fā)現(xiàn)了,要去更新界面!")
                person.name = value
            }
        })
        Object.defineProperties(p,"age",{
            get(){ //有人讀取的時候調(diào)用
                return person.age
            },
            set(value){
                console.log("有人修改了age屬性,發(fā)現(xiàn)了,要去更新界面!")
                person.age = value
            }
        })
        // 然后再f12控制臺中,person.name = '李四' person.sex = '男' delete person.name 之類操作查看結(jié)果 */
        //#endregion


        //模擬vue3中實現(xiàn)響應(yīng)式
        const p = new Proxy(person,{ //就會進行代理,person中的屬性都會有g(shù)et和set了,下面代碼可以里面的api做響應(yīng)式
            //有人讀取p的某個屬性式調(diào)用
            get(target,propName){
                console.log(`有人讀取了p身上的${propName}屬性`)
                return target[propName]
            },
            // 有人修改了p的某個屬性,或給p追加某個屬性時調(diào)用
            set(target,propName,value){
                console.log(`有人修改了p身上的${propName}屬性,我要去更新頁面了!`)
                target[propName] = value
            },
            //有人刪除p的某個屬性時調(diào)用
            deleteProperty(target,propName){
                console.log(`有人刪除了p身上的${propName}屬性,我要去更新頁面了!`)
                return delete target[propName]
            }

        })
        // f12中person.name='李四'等操作即可
    </script>
</body>
</html>

Vue3響應(yīng)式原理Reflect

?Reflect反射的方式,容錯性更好,我們修改上面的Vue3的模擬中的操作

Vue3的響應(yīng)式.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script type="text/javascript">
        //源數(shù)據(jù)
        let person = {
            name : "張三",
            age : 18
        }
        //模擬vue2中實現(xiàn)響應(yīng)式
        //#region
        /* let p = {}
        Object.defineProperties(p,"name",{
            configurable:true, //聲明為可配置的,就允許被刪除了
            get(){ //有人讀取的時候調(diào)用
                return person.name
            },
            set(value){
                console.log("有人修改了name屬性,發(fā)現(xiàn)了,要去更新界面!")
                person.name = value
            }
        })
        Object.defineProperties(p,"age",{
            get(){ //有人讀取的時候調(diào)用
                return person.age
            },
            set(value){
                console.log("有人修改了age屬性,發(fā)現(xiàn)了,要去更新界面!")
                person.age = value
            }
        })
        // 然后再f12控制臺中,person.name = '李四' person.sex = '男' delete person.name 之類操作查看結(jié)果 */
        //#endregion


        //模擬vue3中實現(xiàn)響應(yīng)式
        //#region
        const p = new Proxy(person,{ //就會進行代理,person中的屬性都會有g(shù)et和set了,下面代碼可以里面的api做響應(yīng)式
            //有人讀取p的某個屬性式調(diào)用
            get(target,propName){
                console.log(`有人讀取了p身上的${propName}屬性`)
                // return target[propName]
                return Reflect.get(target,propName)
            },
            // 有人修改了p的某個屬性,或給p追加某個屬性時調(diào)用
            set(target,propName,value){
                console.log(`有人修改了p身上的${propName}屬性,我要去更新頁面了!`)
                // target[propName] = value
                Reflect.set(target,propName,value)
            },
            //有人刪除p的某個屬性時調(diào)用
            deleteProperty(target,propName){
                console.log(`有人刪除了p身上的${propName}屬性,我要去更新頁面了!`)
                // return delete target[propName]
                return Reflect.deleteProperty(target,propName)
            }
        })
        //#endregion

        //#region
        /* //Reflect.definedProperty反射對象去操作
        let obj = {a:1,b:2}
        //除了obj.a = 666 還能Reflect.set(obj,'a',666)的方式修改a Reflect.deleteProperty(obj,'a')的方式刪除a
        //通過Object.defineProperty去操作
        Object.defineProperty(obj,'c',{
            get(){
                return 3
            }
        })
        Object.defineProperty(obj,'c',{
            get(){
                return 4
            }
        })
        //如上Object.defineProperty對obj定義追加了c重復(fù)了,就會報錯,這樣容錯性不太好,需要try-catch包裹起來
        //但使用如下Reflect.definedProperty反射對象去操作后,重復(fù)后就不會報錯
        const x1 = Reflect.defineProperty(obj,'c',{
            get(){
                return 3
            }
        })
        const x2 = Reflect.defineProperty(obj,'c',{
            get(){
                return 4
            }
        })
        //可通過if-else判斷
        if(x2){
            console.log("某某操作成功了")
        }else{
            console.log("某某操作失敗了")
        } */
        //#endregion

    </script>
</body>
</html>

實現(xiàn)原理:

? ? 。通過Proxy(代理)︰攔截對象中任意屬性的變化,包括:屬性值的讀寫、屬性的添加、屬性的刪除等。

? ? 。通過Reflect(反射)︰對源對象的屬性進行操作。

? ? 。MDN文檔中描述的Proxy與Reflect:

? ? ? ? .Proxy: https:/ldeveloper.mozilla.org/zh-CN/docs/WeblJavaScript/Reference/Global_Objects/Proxy

? ? ? ? .Reflect: https:/ldeveloper.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Reflect

reactive和ref的對比

. 從定義數(shù)據(jù)角度對比:

? ? 。ref用來定義:基本類型數(shù)據(jù)。

? ? 。 reactive用來定義:對象(或數(shù)組)類型數(shù)據(jù)。

? ? 。備注: ref也可以用來定義對象(或數(shù)組)類型數(shù)據(jù),它內(nèi)部會自動通過reactive轉(zhuǎn)為代理對象。

. 從原理角度對比:

? ? 。ref通過 object.definePropertv()的get與set來實現(xiàn)響應(yīng)式(數(shù)據(jù)劫持)。

? ? 。reactive通過使用Proxy來實現(xiàn)響應(yīng)式(數(shù)據(jù)劫持)﹐并通過Reflect操作源對象內(nèi)部的數(shù)據(jù)。

. 從使用角度對比:

? ? 。ref定義的數(shù)據(jù):操作數(shù)據(jù)需要.value,讀取數(shù)據(jù)時模板中直接讀取不需要.value 。

? ? 。reactive定義的數(shù)據(jù):操作數(shù)據(jù)與讀取數(shù)據(jù):均不需要.value。

setup的兩個注意點

?setup的兩個注意點

. setup執(zhí)行的時機

? ? 。在beforeCreate之前執(zhí)行一次,this是undefined。

. setup的參數(shù)

? ? 。props:值為對象,包含:組件外部傳遞過來,且組件內(nèi)部聲明接收了的屬性。

? ? 。context: 上下文對象

? ? ? ? ` attrs:值為對象,包含:組件外部傳遞過來,但沒有在props配置中聲明的屬性,相當(dāng)于[this .$attrs 。

? ? ? ? ` slots: 收到的插槽內(nèi)容,相當(dāng)于this.$slots 。

? ? ? ? ` emit:分發(fā)自定義事件的函數(shù),相當(dāng)于this.$emit 。

vue2中的props傳參,父組件寫的參數(shù),子組件props:[]沒聲明的參數(shù),就會被$atts撿漏。vue2中slots父組件中寫的額插槽的內(nèi)容,會放在$slot中作為虛擬節(jié)點。
set第一個參數(shù)需要props聲明,第二個參數(shù)用到的emit需要在上面聲明給emits
vue3中使用具名插槽盡量用v-slot

App.vue

<template>
  <Demo msg='你好' school='尚硅谷' @hello='showHelloMsg'>
    <span>尚硅谷</span>
  </Demo>
</template>

<script>
import Demo from "./components/Demo.vue"
export default {
  name: 'App',
  components:{
    Demo
  },
  setup(){
  function showHelloMsg(value){
    alert(`你好啊,你觸發(fā)了hello事件,我收到的參數(shù)是:${value}`)
  }
  return {
    showHelloMsg
  }
  }
}
</script>

Demo.vue

<template>
  <h1>一個人的信息</h1>
  <h2>姓名:{{person.name}}</h2>
  <h2>年齡:{{person.age}}</h2>
  <button @click="test">測試觸發(fā)一下Demo組件的Hello事件</button>
</template>

<script>
import { reactive } from 'vue'
export default {
    name:'Demo',
    props:['msg','school'],
    emits:['hello'],
    setup(props,context) {
        // console.log("-----setup-----",props)
        // console.log("---setup---",context)
        // console.log("---setup---",context.attrs)//相當(dāng)于vue2中的$attrs
        // console.log("---setup---",context.emit) // 觸發(fā)自定義事件的
        console.log("---setup---",context.slots) //插槽
        //數(shù)據(jù)
        let person = reactive({
            name:'張三',
            age:18
        })

        function test(){
            context.emit('hello',666)
        }

        return {
            person,
            test
        }
    } 
}
</script>

<style>

</style>

Vue3computed計算屬性

App.vue

<template>
  <Demo/>
</template>

<script>
import Demo from "./components/Demo.vue"
export default {
  name: 'App',
  components:{
    Demo
  },
}
</script>

Demo.vue

<template>
  <h1>一個人的信息</h1>
  姓:<input type="text" v-model="person.firstName">
  <br/>
  名:<input type="text" v-model="person.lastName">
  <br/>
  <!-- <span>全名:{{fullName}}</span> -->
  <span>全名:{{person.fullName}}</span>
  <br/>
  全名:<input type="text" v-model="person.fullName">
</template>

<script>
import { reactive ,computed} from 'vue'
export default {
    name:'Demo',
    /* computed:{ // 在vue3中是可以像vue2中寫計算屬性的。但不推薦。
        fullName(){
            return this.person.firstName + '-' + this.person.lastName
        }
    }, */
    setup() {
        let person = reactive({
            firstName:'張',
            lastName:"三"
        })
        // 計算屬性-簡寫(沒有考慮計算屬性被修改的情況)
        /* let fullName = computed(()=>{
            return person.firstName + "-" + person.lastName
        }) */
        /* person.fullName = computed(()=>{
            return person.firstName + "-" + person.lastName
        }) */
        // 計算屬性的完整寫法(考慮讀和寫)
        person.fullName = computed({
            get(){
                return person.firstName + '-' +person.lastName
            },
            set(value){
                const nameArr = value.split('-')
                person.firstName=nameArr[0],
                person.lastName=nameArr[1]
            }
        })
        

        return {
            person
        }
    } 
}
</script>

<style>

</style>

watch監(jiān)視ref定義的數(shù)據(jù)

Demo.vue

<template>
  <h2>當(dāng)前求和為:{{sum}}</h2>
  <button @click="sum++">點我+1</button>
  <hr>
  <h2>當(dāng)前的信息為:{{msg}}</h2>
  <button @click="msg+='!'">修改信息</button>
</template>

<script>
import { ref, watch } from 'vue'
export default {
    name:'Demo',
    /* watch:{// vue3中也可使用vue2中的watch,不過不推薦
        sum(newValue,oldValue){//簡寫的方式,詳細寫法見vue2中的watch
            console.log('sum的值變化了',newValue,oldValue)
        }
    }, */
    setup() {
        let sum = ref(0)
        let msg = ref('你好啊')

        //情況1,監(jiān)視ref所定義的一個響應(yīng)式數(shù)據(jù)
        /* watch(sum,(newValue,oldValue)=>{
            console.log("sum變化了",newValue,oldValue)
        }) */

        //情況2,監(jiān)視ref所定義的多個響應(yīng)式數(shù)據(jù)  可寫多個watch在vue3中
        /* watch(sum,(newValue,oldValue)=>{
            console.log("sum變化了",newValue,oldValue)
        })
        watch(msg,(newValue,oldValue)=>{
            console.log("msg變化了",newValue,oldValue)
        }) */
        /* watch([sum,msg],(newValue,oldValue)=>{ // newValue,oldValue分別為數(shù)組
            console.log("sum或msg變化了",newValue,oldValue)
        }) */

        watch(sum,(newValue,oldValue)=>{
            console.log("sum變化了",newValue,oldValue)
        },{immediate:true})//可加第三個參數(shù)為配置 但deep:true在vue3中有小問題

        return {
            sum,
            msg
        }
    } 
}
</script>

<style>

</style>

App.vue中引用注冊并渲染這個Demo.vue

watch監(jiān)視reactive定義的數(shù)據(jù)

watch函數(shù)

? ? 。與Vue2.x中watch配置功能一致。

兩個小“坑":

? ? 。監(jiān)視reactive定義的響應(yīng)式數(shù)據(jù)時: oldValue無法正確獲取、強制開啟了深度監(jiān)視(deep配置失效)。

? ? 。監(jiān)視reactive定義的響應(yīng)式數(shù)據(jù)中某個屬性時: deep配置有效。

Demo.vue

<template>
  <h2>姓名:{{person.name}}</h2>
  <h2>年齡:{{person.age}}</h2>
  <h2>薪水:{{person.job.j1.salary}}</h2>
  <button @click="person.name+='~'">修改姓名</button>
  <button @click="person.age++">增長年齡</button>
  <button @click="person.job.j1.salary++">增長薪資</button>
</template>

<script>
import { reactive, ref, watch } from 'vue'
export default {
    name:'Demo',
    setup() {
        let person = reactive({
            name:'張三',
            age:18,
            job:{
                j1:{
                    salary:20
                }
            }
        })
        
        //情況三:監(jiān)視reactive所定義的一個響應(yīng)式數(shù)據(jù)的全部屬性,注意,此處無法正確的獲取oldValue,這是vue3的小bug
        watch(person,(newValue,oldValue)=>{   //vue3中默認就開啟了深度監(jiān)視了,所以salary修改也能顯示,且關(guān)不掉這個深度監(jiān)視
            console.log('person發(fā)生變化了',newValue,oldValue);
        })
        
        //情況四:監(jiān)視reactive所定義的一個響應(yīng)式數(shù)據(jù)中的某個屬性
        watch(()=>person.age,(newValue,oldValue)=>{   //vue3中默認就開啟了深度監(jiān)視了,所以salary修改也能顯示,且關(guān)不掉這個深度監(jiān)視
            console.log('person的age發(fā)生變化了',newValue,oldValue);
        })

        //情況五:監(jiān)視reactive所定義的一個響應(yīng)式數(shù)據(jù)中的某些屬性
        watch([()=>person.age,()=>person.name],(newValue,oldValue)=>{   //vue3中默認就開啟了深度監(jiān)視了,所以salary修改也能顯示,且關(guān)不掉這個深度監(jiān)視
            console.log('person的age或name發(fā)生變化了',newValue,oldValue);
        })

        //特殊情況  ()=>person.job 如果改job下的子屬性,需要開啟深度監(jiān)視deep:true
        watch(()=>person.job,(newValue,oldValue)=>{   //vue3中默認就開啟了深度監(jiān)視了,所以salary修改也能顯示,且關(guān)不掉這個深度監(jiān)視
            console.log('person的job發(fā)生變化了',newValue,oldValue);
        },{deep:true})


        return {
            person
        }
    } 
}
</script>

<style>

</style>

App.vue中引用注冊并渲染這個Demo.vue

watch時的value問題

ref()對基本類型,.value就是基本類型,但ref對對象類型,.value的是proxy代理對象。
所以watch為ref普通屬性直接寫,但watch為ref的對象時,修改person里面的屬性,用person.value,還可在后面加上deep:true屬性

watchEffect函數(shù)

watchEffect函數(shù)

. watch的套路是:既要指明監(jiān)視的屬性,也要指明監(jiān)視的回調(diào)。

. watchEffect的套路是:不用指明監(jiān)視哪個屬性,監(jiān)視的回調(diào)中用到哪個屬性,那就監(jiān)視哪個屬性。

. watchEffect有點像computed:

? ? 。但computed注重的計算出來的值(回調(diào)函數(shù)的返回值),所以必須要寫返回值。

? ? 。而watchEffect更注重的是過程(回調(diào)函數(shù)的函數(shù)體),所以不用寫返回值。

Demo.vue

<template>
  <h2>當(dāng)前求和為:{{sum}}</h2>
  <button @click="sum++">點我+1</button>
  <hr>
  <h2>當(dāng)前的信息為:{{msg}}</h2>
  <button @click="msg+='!'">修改信息</button>
  <hr>
    <h2>姓名:{{person.name}}</h2>
  <h2>年齡:{{person.age}}</h2>
  <h2>薪水:{{person.job.j1.salary}}</h2>
  <button @click="person.name+='~'">修改姓名</button>
  <button @click="person.age++">增長年齡</button>
  <button @click="person.job.j1.salary++">增長薪資</button>
</template>

<script>
import { ref, reactive, watch, watchEffect } from 'vue'
export default {
    name:'Demo',
    setup() {
        let sum = ref(0)
        let msg = ref('你好啊')
        let person = reactive({
            name:'張三',
            age:18,
            job:{
                j1:{
                    salary:20
                }
            }
        })
        /* watch(sum,(newValue,oldValue)=>{
            console.log("sum變化了",newValue,oldValue)
        },{immediate:true}) */

        watchEffect(()=>{//里面用到了哪些屬性就監(jiān)視誰,而且還默認第一次就加載
            const x1  = sum.value
            const x2 = person.job.j1.salary
            console.log("watchEffect所指定的回調(diào)執(zhí)行了");
        })

        return {
            sum,
            msg,
            person
        }
    } 
}
</script>

<style>

</style>

App.vue中引用注冊并渲染這個Demo.vue

Vue3生命周期鉤子

vue2生命周期鉤子前6個都一樣,最后beforeDestroy和destroyed與vue3的beforeUnmount和unmounted不一樣.vue2中即使沒寫el,也能執(zhí)行beforeCreate和created這兩步,但vue3得都有才能開始執(zhí)行beforeCreate。vue3也能通過配置項的形式引用生命周期鉤子,也可通過組合式api的形式去使用生命周期鉤子

Vue3.0也提供了Composition API形式的生命周期鉤子,與Vue2.x中鉤子對應(yīng)關(guān)系如下:

? ? 。beforeCreate ===> setup()

? ? 。created =======> setup()

? ? 。beforeMount =======> onBeforeMount

? ? 。mounted =======> onMounted

? ? 。beforeUpdate ===> onBeforeUpdate

? ? 。updated =======> onUpdated

? ? 。beforeUnmount ==> onBeforeUnmount

? ? 。unmounted =====> onUnmounted

Demo.vue

<template>
  <h2>當(dāng)前求和為:{{sum}}</h2>
  <button @click="sum++">點我+1</button>
</template>

<script>
import { ref,onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted} from 'vue'
export default {
    name:'Demo',
    setup() {
        let sum = ref(0)
        
        //通過組合式api的形式去使用生命周期鉤子 優(yōu)先級setup的高于配置項的
        onBeforeMount(()=>{
            console.log("---onBeforeMount---");
        })
        onMounted(()=>{
            console.log("---onMounted---");
        })
        onBeforeUpdate(()=>{
            console.log("---onBeforeUpdate---");
        })
        onUpdated(()=>{
            console.log("---onUpdated---");
        })
        onBeforeUnmount(()=>{
            console.log("---onBeforeUnmount---");
        })
        onUnmounted(()=>{
            console.log("---onUnmounted---");
        })

        return {
            sum,
        }
    },
    //#region 
    // 通過配置項的形式引用生命周期鉤子
/*     beforeCreate() {
        console.log('beforeCreate')
    },
    created() {
        console.log('created')
    },
    beforeMount() {
        console.log('beforeMount')
    },
    mounted() {
        console.log('mounted')
    },
    beforeUpdate() {
        console.log('beforeUpdate')
    },
    updated() {
        console.log('updated')
    },
    beforeUnmount() {
        console.log("beforeUnmount")
    },
    unmounted() {
        console.log("unmounted")
    },  */
    //#endregion
}
</script>

<style>

</style>

App.vue

<template>
  <button @click="isShowDemo = !isShowDemo">切換隱場顯示</button>
  <Demo v-if="isShowDemo"/>
</template>

<script>
import { ref } from 'vue'
import Demo from "./components/Demo.vue"
export default {
  name: 'App',
  components:{
    Demo
  },
  setup(){
    let isShowDemo = ref(true)
    return {
      isShowDemo
    }
  },
}
</script>

自定義hook

.什么是hook?——本質(zhì)是一個函數(shù),把setup函數(shù)中使用的Composition APlI進行了封裝。
·類似于vue2.x中的mixin。
·自定義hook的優(yōu)勢:復(fù)用代碼,讓setup中的邏輯更清楚易懂。

本來在Demo.vue中寫的鼠標(biāo)打點的方法,但可能其他組件也需要使用改鼠標(biāo)打點的功能,要么將這段代碼復(fù)制粘貼,或者我們可以在src下建一個hooks文件夾,創(chuàng)建userPoint.js文件,然后在這里寫那些代碼,然后返回出去,然后Demo.vue中再引入

usePoint.js

import {reactive,onMounted, onBeforeUnmount} from 'vue'

// function savePoint(){
export default function (){

    //實現(xiàn)鼠標(biāo)打點的數(shù)據(jù)
    let point = reactive({
        x:0,
        y:0
    })

    //實現(xiàn)鼠標(biāo)打點的方法
    function savePoint(event){
            point.x = event.pageX
            point.y = event.pageY
            console.log(event.pageX,event.pageY);
    }

    //實現(xiàn)鼠標(biāo)打點相關(guān)的生命周期鉤子
    onMounted(()=>{
        window.addEventListener("click",savePoint)
    })

    onBeforeUnmount(()=>{
        window.removeEventListener("click",savePoint)
    })

    return point
}

// export default savePoint

Demo.vue

<template>
  <h2>當(dāng)前求和為:{{sum}}</h2>
  <button @click="sum++">點我+1</button>
  <hr>
  <h2>當(dāng)前點擊時鼠標(biāo)的坐標(biāo)為:x:{{point.x}},y:{{point.y}}</h2>
</template>

<script>
import usePoint from '../hooks/usePoint'
import { ref,reactive,onMounted, onBeforeUnmount} from 'vue'
export default {
    name:'Demo',
    setup() {
        let sum = ref(0)


        /* let point = reactive({
            x:0,
            y:0
        })

        function savePoint(event){
                point.x = event.pageX
                point.y = event.pageY
                console.log(event.pageX,event.pageY);
        }

        onMounted(()=>{
            window.addEventListener("click",savePoint)
        })

        onBeforeUnmount(()=>{
            window.removeEventListener("click",savePoint)
        }) */
        

        //然后復(fù)用
        let point = usePoint()

        return {
            sum,point
        }
    },
    
}
</script>

<style>

</style>

toRef與toRefs

toRef:將一個不是ref的變成ref

. 作用:創(chuàng)建一個ref對象,其value值指向另一個對象中的某個屬性。

· 語法:const name = toRef(person , ' name ')

. 應(yīng)用:要將響應(yīng)式對象中的某個屬性單獨提供給外部使用時。

. 擴展: toRefs 與toRef功能一致,但可以批量創(chuàng)建多個ref對象,語法: toRefs(person)

Demo.vue

<template>
  <h2>姓名:{{name}}</h2>
  <h2>年齡:{{age}}</h2>
  <h2>薪水:{{job.j1.salary}}</h2>
  <button @click="name+='~'">修改姓名</button>
  <button @click="person.age++">增長年齡</button>
  <button @click="job.j1.salary++">增長薪資</button>
</template>

<script>
import {reactive, toRef, toRefs} from 'vue'
export default {
    name:'Demo',
    setup() {
        let person = reactive({
            name:'張三',
            age:18,
            job:{
                j1:{
                    salary:20
                }
            }
        })

        /* const name1 = person.name
        console.log('%%%%%%',name1);
        const name2 = toRef(person,'name')  // 這里并不是又復(fù)制了一份,而是這里讀取的指向的還是上面的let person里面的
        console.log('@@@@@',name2);  */

        const x = toRefs(person)  //將person中所有屬性變成ref引用對象
        console.log(x);
        
        return {
            /* person,
            name:toRef(person,'name'),
            age:toRef(person,'age'),
            salary:toRef(person.job.j1,'salary'), */
            //name:ref(person.name)  //用ref的話,之后修改的就不是上面的person中的name了,而是新的ref,所以不能這么寫

            ...toRefs(person)
        }
    } 
}
</script>

<style>

</style>

?App.vue中引入即可

其他組合式API

?不常用

shallowReactive與shallowRef

??App.vue中導(dǎo)入注冊渲染Demo.vue. shallowReactive:只處理對象最外層屬性的響應(yīng)式(淺響應(yīng)式)。

. shallowRef:只處理基本數(shù)據(jù)類型的響應(yīng)式,不進行對象的響應(yīng)式處理。

. 什么時候使用?

? ? 。如果有一個對象數(shù)據(jù),結(jié)構(gòu)比較深,但變化時只是外層屬性變化===> shallowReactive。

? ? 。如果有一個對象數(shù)據(jù),后續(xù)功能不會修改該對象中的屬性,而是生新的對象來替換===>shallowRef。

Demo.vue

<template>
    <h4>當(dāng)前x的值是:{{x.y}}</h4>
    <button @click="x.y++">點我x+1</button>
  <h2>姓名:{{name}}</h2>
  <h2>年齡:{{age}}</h2>
  <h2>薪水:{{job.j1.salary}}</h2>
  <button @click="name+='~'">修改姓名</button>
  <button @click="person.age++">增長年齡</button>
  <button @click="job.j1.salary++">增長薪資</button>
</template>

<script>
import {ref,reactive, toRef, toRefs,shallowReactive,shallowRef} from 'vue'
export default {
    name:'Demo',
    setup() {
        //let person = shallowReactive({   //淺層次的reactive,只有第一層可響應(yīng)式,即下面的name和age有響應(yīng)式,但salary沒有響應(yīng)式
        let person = reactive({
            name:'張三',
            age:18,
            job:{
                j1:{
                    salary:20
                }
            }
        })
        // let x = shallowRef({ //shallowRef和ref區(qū)別為,當(dāng)值為對象時,shallowRef只能修改一層,如下x的y屬性就沒有響應(yīng)式
        let x = ref({
            y:0
        })
        return {
            ...toRefs(person),
            x
        }
    } 
}
</script>

<style>

</style>

readOnly與shallowReadOny

readonly:讓一個響應(yīng)式數(shù)據(jù)變?yōu)橹蛔x的(深只讀)。

shallowReadonly:讓一個響應(yīng)式數(shù)據(jù)變?yōu)橹蛔x的(淺只讀)

應(yīng)用場景:不希望數(shù)據(jù)被修改時。

Demo.vue

<template>
    <h4>當(dāng)前求和為:{{sum}}</h4>
    <button @click="sum++">點我+1</button>
  <h2>姓名:{{name}}</h2>
  <h2>年齡:{{age}}</h2>
  <h2>薪水:{{job.j1.salary}}</h2>
  <button @click="name+='~'">修改姓名</button>
  <button @click="age++">增長年齡</button>
  <button @click="job.j1.salary++">增長薪資</button>
</template>

<script>
import {ref,reactive, toRef, toRefs,shallowReactive,shallowRef, readonly, shallowReadonly} from 'vue'
export default {
    name:'Demo',
    setup() {
        let person = reactive({
            name:'張三',
            age:18,
            job:{
                j1:{
                    salary:20
                }
            }
        })
        let sum = ref(0)

        // person = readonly(person) //不讓任何人修改這個數(shù)據(jù),就可以用readonly,并且用person接收覆蓋了原來的person
        person = shallowReadonly(person) //底有第一層年齡和姓名改不了,但薪資可改的

        // sum = readonly(sum)
        // sum = shallowReadonly(sum)


        return {
            ...toRefs(person),
            sum
        }
    } 
}
</script>

<style>

</style>

toRaw與markRaw

. toRaw:

? ? 。作用:將一個由reactive生成的響應(yīng)式對象轉(zhuǎn)為普通對象。

? ? 。使用場景:用于讀取響應(yīng)式對象對應(yīng)的普通對象,對這個普通對象的所有操作,不會引起頁面更新.

. markRaw":

? ? 。作用:標(biāo)記一個對象,使其永遠不會再成為響應(yīng)式對象。

? ? 。應(yīng)用場景:

? ? ? ? 1.有些值不應(yīng)被設(shè)置為響應(yīng)式的,例如復(fù)雜的第三方類庫等。

? ? ? ? 2.當(dāng)渲染具有不可變數(shù)據(jù)源的大列表時,跳過響應(yīng)式轉(zhuǎn)換可以提高性能。

Demo.vue

<template>
    <h4>當(dāng)前求和為:{{sum}}</h4>
    <button @click="sum++">點我+1</button>
  <h2>姓名:{{name}}</h2>
  <h2>年齡:{{age}}</h2>
  <h2>薪水:{{job.j1.salary}}</h2>
  <h2>手機:{{person.phone}}</h2>
  <button @click="name+='~'">修改姓名</button>
  <button @click="age++">增長年齡</button>
  <button @click="job.j1.salary++">增長薪資</button>
  <button @click="showRawPerson">輸出最原始的person</button>
  <button @click="addPhone">給人添加一個手機</button>
  <button @click="person.phone.brand+='!'">換手機品牌</button>
  <button @click="person.phone.color+='@'">換手機顏色</button>
</template>

<script>
import {markRaw,ref,reactive, toRef, toRefs,shallowReactive,shallowRef, toRaw} from 'vue'
export default {
    name:'Demo',
    setup() {
        let person = reactive({
            name:'張三',
            age:18,
            job:{
                j1:{
                    salary:20
                }
            }
        })
        let sum = ref(0)

        function showRawPerson(){
            const p  = toRaw(person)  // 將將一個由reactive生成的響應(yīng)式對象轉(zhuǎn)為普通對象。ref的行不通。
            console.log(person);
            console.log(p);
        }
 
        function addPhone(){
            /* let phone = {brand:"小米",color:"red"}
            person.phone = phone //追加的內(nèi)容為響應(yīng)式的 */

            let phone = {brand:"小米",color:"red"}
            person.phone = markRaw(phone) //使用markRaw標(biāo)記后這個數(shù)據(jù)永遠不做響應(yīng)式了,修改時數(shù)據(jù)確實改了,但頁面不變化
        }

        return {
            ...toRefs(person),
            sum,
            person,//把person也交出去,后期添加person屬性可直接用person.的方式獲取值
            showRawPerson,
            addPhone
        }
    } 
}
</script>

<style>

</style>

App.vue中引用Demo.vue

customRef自定義ref

作用:創(chuàng)建一個自定義的ref,并對其依賴項跟蹤和更新觸發(fā)進行顯式控制。

通過一個防抖的案例:即輸入框中輸入內(nèi)容,顯示的h4標(biāo)簽過1秒再顯示。

App.vue

<template>
  <input type="text" v-model="keyWord">
  <h3>{{keyWord}}</h3>
</template>

<script>
import { ref ,customRef} from 'vue'
export default {
  name: 'App', 
  setup(){
    //自定義一個ref—名為:myRef
    function myRef(value,delay){
      let timer;
      return customRef((track,trigger)=>{ //要返回一個對象
        return{
          get(){
            console.log(`有人從myRef這個容器中讀取數(shù)據(jù)了,我把${value}給他了`);
            track()  // 2 通知vue追蹤value的變化,(提前和get商量一下,讓他認為這個value是有用的)
            return value
          },
          set(newValue){
            console.log(`有人把myRef這個容器中數(shù)據(jù)改為了${newValue}`);
            clearTimeout(timer)  //防抖
            //value = newValue
            // trigger()  // 1 通知vue去重新解析模板
            timer = setTimeout(() => {
            value = newValue
              trigger()  // 1 通知vue去重新解析模板
            }, delay);
          }
        }
      })
    }
    // let keyWord = ref("hello")// 使用vue提供的ref
    let keyWord = myRef("hello",500)// 使用vue提供的ref

    return {
      keyWord
    }
  },
}
</script>

provide與inject

。作用:實現(xiàn)祖與后代組件間通信

。套路:父組件有一個provide選項來提供數(shù)據(jù),后代組件有一個inject選項來開始使用這些數(shù)據(jù) ?

App.vue

<template>
  <div class="app">
    <h3>我是App組件(祖)</h3>
    <Child/>
  </div>
</template>

<script>
import { provide, reactive, toRefs } from 'vue'
import Child from "./components/Child.vue"
export default {
  name: 'App', 
  components:{
    Child
  },
  setup(){
    let phone = reactive({brand:"小米",color:"red"})
    provide('phone',phone)
    return {...toRefs(phone)}
  }
}
</script>
<style>
.app{
  background-color: grey;
  padding: 10px;
}
</style>

Child.vue

<template>
  <div class="child">
    <h3>我是Child組件(子),{{phone.brand}}--{{phone.color}}</h3>
    <Sun/>
  </div>
</template>

<script>
import { inject } from 'vue'
import Sun from './Sun.vue'
export default {
  name: 'Child', 
  components:{
    Sun
  },
  setup(){
    let phone = inject('phone')
    return{phone}
  }
}
</script>
<style>
.child{
  background-color: skyblue;
  padding: 10px;
}
</style>

Sun.vue

<template>
  <div class="sun">
    <h3>我是Sun組件(孫),{{phone.brand}}--{{phone.color}}</h3>
  </div>
</template>

<script>
import { inject } from 'vue'
export default {
  name: 'Sun', 
  setup(){
    let phone = inject('phone')
    return{phone}
  }
}
</script>
<style>
.sun{
  background-color: orange;
  padding: 10px;
}
</style>

響應(yīng)式數(shù)據(jù)的判斷

響應(yīng)式數(shù)據(jù)的判斷API

? ? isRef:檢查一個值是否為一個ref 對象

? ? isReactive:檢查一個對象是否是由reactive創(chuàng)建的響應(yīng)式代理

? ? isReadonly:檢查一個對象是否是由readonly 創(chuàng)建的只讀代理

? ? isProxy:檢查一個對象是否是由reactive或者readonly方法創(chuàng)建的代理

App.vue

<template>
    <h3>我是App組件(祖)</h3>
</template>

<script>
import { isProxy, isReactive, isReadonly, isRef, provide, reactive, readonly, ref, toRefs } from 'vue'
export default {
  name: 'App', 
  setup(){
    let phone = reactive({brand:"小米",color:"red"})
    let sum = ref(0)
    let phone2 = readonly(phone)

    console.log(isRef(sum));//true
    console.log(isReactive(phone));//true
    console.log(isReadonly(phone2));//true
    console.log(isProxy(phone));//true
    console.log(isProxy(phone2));//true readOnly處理后的也是proxy


    provide('phone',phone)
    return {...toRefs(phone)}
  }
}
</script>
<style>
</style>

組合式API的優(yōu)勢

Composition API組合式API,Options API配置式API

Options API存在的問題:使用傳統(tǒng)OptionsAPI中,新增或者修改一個需求,就需要分別在data,methods,computed里修改。

2.Composition API的優(yōu)勢:我們可以更加優(yōu)雅的組織我們的代碼,函數(shù)。讓相關(guān)功能的代碼更加有序的組織在一起。還可借助hook函數(shù)發(fā)揮組合式API的威力。

新的組件

Fragment與Teleport

1.Fragment

? ? 。在Vue2中:組件必須有一個根標(biāo)簽

? ? 。在Vue3中:組件可以沒有根標(biāo)簽,內(nèi)部會將多個標(biāo)簽包含在一個Fragment虛擬元素中。好處:減少標(biāo)簽層級,減小內(nèi)存占用

2.Teleport。什么是Teleport?

? ? Teleport是一種能夠?qū)⑽覀兊慕M件html結(jié)構(gòu)移動到指定位置的技術(shù)。

? ? 案例:傳統(tǒng)的方式寫彈窗會將外幾層的組件全都撐開。使用teleport指定to='html'或to='body'就可將這段代碼的東西傳送到html標(biāo)簽或body標(biāo)簽中,也可加遮罩層

?App.vue

<template>
  <div class="app">
    <h3>我是App組件</h3>
    <Child/>
  </div>
</template>

<script>
import Child from "./components/Child.vue"
export default {
  name: 'App', 
  components:{
    Child
  }
}
</script>
<style>
.app{
  background-color: grey;
  padding: 10px;
}
</style>

Child.vue

<template>
  <div class="child">
    <h3>我是Child組件</h3>
    <Sun/>
  </div>
</template>

<script>
import Sun from './Sun.vue'
export default {
  name: 'Child', 
  components:{
    Sun
  },
}
</script>
<style>
.child{
  background-color: skyblue;
  padding: 10px;
}
</style>

Son.vue

<template>
  <div class="sun">
    <h3>我是Sun組件</h3>
    <Dialog/>
  </div>
</template>

<script>
import Dialog from './Dialog.vue'
export default {
  name: 'Sun', 
  components:{Dialog}
}
</script>
<style>
.sun{
  background-color: orange; 
  padding: 10px;
}
</style>

Dialog.vue

<template>
  <div>
    <button @click="isShow = true">點我彈個窗</button>
<!--     <div v-if="isShow" class="dialog">
        <h3>我是一個彈窗</h3>
        <h4>一些內(nèi)容</h4>
        <h4>一些內(nèi)容</h4>
        <h4>一些內(nèi)容</h4>
        <button @click="isShow = false">關(guān)閉彈窗</button>
    </div> -->
        <teleport to="body">
            <div v-if="isShow" class="mask">
                <div class="dialog">
                    <h3>我是一個彈窗</h3>
                    <h4>一些內(nèi)容</h4>
                    <h4>一些內(nèi)容</h4>
                    <h4>一些內(nèi)容</h4>
                    <button @click="isShow = false">關(guān)閉彈窗</button>
                </div>                
            </div>

        </teleport>
    
  </div>
</template>

<script>
import { ref } from 'vue'

export default {
    name:"Dialog",
    setup(){
        let isShow = ref(false)
        return {isShow}
    }
}
</script>

<style>
.dialog{
    width: 300px;
    height: 300px;
    background-color: green;
    
    position: absolute;
    top:50%;
    left:50%;
    transform: translate(-50%,-50%);
}
.mask{/* 遮罩層樣式,點被其遮住的元素的點不了 */
    position: absolute;
    top: 0 ;bottom: 0;left: 0;right: 0;
    background-color: rgba(0, 0, 0, 0.5);
}
</style>

Suspense組件

網(wǎng)速快的時候,靜態(tài)引入和動態(tài)引入一樣,但網(wǎng)速慢的時候,靜態(tài)引入是App和Child組件一起出來(最后引入取決于組件套娃中最后出來的那個組件出來后才顯示),動態(tài)引入是App和Child誰加載完誰出來。但動態(tài)引入當(dāng)某個先出來展示,某個組件加載慢1秒中后才出來就會用戶體驗不好,頁面有抖動,可以用Suspense將子標(biāo)簽Child標(biāo)簽包起來,然后再Child組件還未加載好的時候先用一個loading替換

?App.vue

<template>
  <div class="app">
    <h3>我是App組件</h3>
    <!-- <Child/> -->
    <Suspense>
      <template v-slot:default>
        <Child/>
      </template>
      <template v-slot:fallback>
        <h3>稍等,加載中......</h3>
      </template>
    </Suspense>
  </div>
</template>

<script>
// import Child from "./components/Child.vue"  //靜態(tài)引入
import {defineAsyncComponent} from 'vue'
const Child = defineAsyncComponent(()=>import('./components/Child.vue'))  //動態(tài)引入  異步引入
export default {
  name: 'App', 
  components:{
    Child
  }
}
</script>
<style>
.app{
  background-color: grey;
  padding: 10px;
}
</style>

Child.vue

<template>
  <div class="child">
    <h3>我是Child組件</h3>
    {{sum}}
  </div>
</template>

<script>
import { ref } from 'vue';
export default {
  name: 'Child', 
  async setup(){ //因為App.vue中使用了Suspense,且引入Child組件時為異步引入,所以這里的setup可返回Promise對象
    let sum = ref(0)
    let p = new Promise((resolve,reject)=>{
        setTimeout(() => {
            resolve({sum})
        }, 3000);
    })
    return await p
  }
}
</script>
<style>
.child{
  background-color: skyblue;
  padding: 10px;
}
</style>

其他

全局API的轉(zhuǎn)移

. Vue 2.x有許多全局API和配置。

? ? 。例如:注冊全局組件、注冊全局指令等。

? ? ? ? //注冊全局組件

? ? ? ? Vue. component( ' MyButton ', {

? ? ? ? ? ? data: () =>({

? ? ? ? ? ? count: 0}),

? ? ? ? ? ? template: '<button @click="count++">clicked {{ count }} times.</button>'

? ? ? ? ? ? })

? ? ? ? //注冊全局指令

? ? ? ? Vue.directive( 'focus ', {

? ? ? ? ? ? inserted : el => el.focus()

? ? ? ? ? ? }

. Vue3.0中對這些API做出了調(diào)整:

? ? 。將全局的API,即:Vue.xxx調(diào)整到應(yīng)用實例(app ) 上

????????2.x全局APl (vue ) ?=> ? 3.x 實例APl( app)

????????Vue.config.xxxX ?=> ?app.config.xxXx

? ? ? ? Vue.config.productionTip ?=> ?移除

????????Vue.component ?=> ?app.component

????????Vue.directive ?=> ?app.directive

? ? ? ? Vue.mixin ?=> ?app.mixin????????

????????Vue.use ?=> ?app.use

????????Vue.prototype ?=> ?app.config.globalProperties

2.其他改變

? ? . data選項應(yīng)始終被聲明為一個函數(shù)。

? ? 。過度類名的更改:

? ? ? ? o Vue2.x寫法

? ? ? ? .v-enter,

? ? ? ? .v-leave-to {

? ? ? ? ? ? opacity: 0;

? ? ? ? ? ? }

? ? ? ? .v-leave,

? ? ? ? .v-enter-to {

? ? ? ? ? ? opacity: 1;

? ? ? ? ? ? }

? ? ? ? o Vue3.x寫法

? ? ? ? .v-enter-from,

? ? ? ? .v-leave-to {

? ? ? ? ? ? opacity: 0;

? ? ? ? ? ? }

? ? ? ? .v-leave-from,

? ? ? ? .v-enter-to {

? ? ? ? ? ? opacity: 1;

? ? ? ? ? ? }

? ? 移除keyCode作為v-on 的修飾符,同時也不再支持config.keyCodes

? ? 移除v-on.native修飾符

? ? 移除了過濾器filter

? ? . . . . . .?文章來源地址http://www.zghlxwxcb.cn/news/detail-675371.html

到了這里,關(guān)于Vue3筆記——(尚硅谷張?zhí)煊鞻ue筆記)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費用

相關(guān)文章

  • [Vue]Vue3學(xué)習(xí)筆記(尚硅谷)

    [Vue]Vue3學(xué)習(xí)筆記(尚硅谷)

    本筆記根據(jù)如下筆記和視頻進行整理 老師的課件筆記,不含視頻 https://www.aliyundrive.com/s/B8sDe5u56BU 筆記在線版: https://note.youdao.com/s/5vP46EPC 視頻:尚硅谷Vue2.0+Vue3.0全套教程丨vuejs從入門到精通 使用vue-cli創(chuàng)建Vue3項目,需要確保vue-cli版本在4.5.0以上。 使用vue-cli創(chuàng)建Vue3項目 vit

    2024年02月01日
    瀏覽(21)
  • 前端學(xué)習(xí)筆記(14)-Vue3組件傳參

    前端學(xué)習(xí)筆記(14)-Vue3組件傳參

    1.props(父組件傳遞給子組件) 1.1 實現(xiàn) 如果你沒有使用 script setup,props 必須以 props 選項的方式聲明,props 對象會作為 setup() 函數(shù)的第一個參數(shù)被傳入: 在子組件中: 在父組件中: 一個組件可以有任意多的 props,默認情況下,所有 prop 都接受任意類型的值。 這種情況下,我

    2024年01月21日
    瀏覽(32)
  • Vue | (一)Vue核心(上) | 尚硅谷Vue2.0+Vue3.0全套教程

    Vue | (一)Vue核心(上) | 尚硅谷Vue2.0+Vue3.0全套教程

    學(xué)習(xí)鏈接:尚硅谷Vue2.0+Vue3.0全套教程丨vuejs從入門到精通,本文對應(yīng)p1-p25,博客參考尚硅谷公開筆記,補充記錄實操。 英文官網(wǎng) 中文官網(wǎng) 關(guān)于官網(wǎng)(與視頻p3已略有出入):文檔指南,API查字典,互動指南,示例… Vue開發(fā)者工具安裝 vscode插件安裝,提效 想讓Vue工作,就必

    2024年02月20日
    瀏覽(46)
  • Vue | (一)Vue核心(下) | 尚硅谷Vue2.0+Vue3.0全套教程

    Vue | (一)Vue核心(下) | 尚硅谷Vue2.0+Vue3.0全套教程

    學(xué)習(xí)鏈接:尚硅谷Vue2.0+Vue3.0全套教程丨vuejs從入門到精通,本文對應(yīng)p26-p52,博客參考尚硅谷公開筆記,補充記錄實操。 在應(yīng)用界面中, 某個(些)元素的樣式是變化的。 class/style 綁定就是專門用來實現(xiàn)動態(tài)樣式效果的技術(shù)。 class樣式 寫法: class=\\\"xxx\\\" ,xxx可以是字符串、對象、數(shù)

    2024年02月19日
    瀏覽(28)
  • Vue | (三)使用Vue腳手架(上) | 尚硅谷Vue2.0+Vue3.0全套教程

    Vue | (三)使用Vue腳手架(上) | 尚硅谷Vue2.0+Vue3.0全套教程

    學(xué)習(xí)鏈接:尚硅谷Vue2.0+Vue3.0全套教程丨vuejs從入門到精通,本文對應(yīng)p61-p69,博客參考尚硅谷公開筆記,補充記錄實操。 Vue 腳手架是 Vue 官方提供的標(biāo)準(zhǔn)化開發(fā)工具(開發(fā)平臺)。 CLI :command line interface(目前已經(jīng)維護了,但也試一試) 全局安裝 : npm config set registry https:/

    2024年02月20日
    瀏覽(59)
  • Vue | (三)使用Vue腳手架(下)| 尚硅谷Vue2.0+Vue3.0全套教程

    Vue | (三)使用Vue腳手架(下)| 尚硅谷Vue2.0+Vue3.0全套教程

    學(xué)習(xí)鏈接:尚硅谷Vue2.0+Vue3.0全套教程丨vuejs從入門到精通,本文對應(yīng)p79-p95,博客參考尚硅谷公開筆記,補充記錄實操。 區(qū)別于JS里的內(nèi)置事件。 一種 組件間通信 的方式,適用于: 子組件 === 父組件 使用場景 :A是父組件,B是子組件,B想給A傳數(shù)據(jù),那么就要在A中給B綁定自

    2024年02月22日
    瀏覽(45)
  • 前端筆記之vue3 之 render函數(shù)和createVNode函數(shù)使用

    前端筆記之vue3 之 render函數(shù)和createVNode函數(shù)使用

    初學(xué)vue3的時候倒是扒了一點點源碼,似是而非,而且一直做的工作都是很簡單的功能,怎么說呢,ui框架也幾乎讓我很容易的就可以寫出一個成型的頁面,有時就忘了初學(xué)的時候的一些心得。 本內(nèi)容只說createVNode函數(shù)的用法,不做源碼探究 效果圖: 雖然在日常中這么寫特別

    2024年02月07日
    瀏覽(27)
  • 前端筆記(4) Vue3 全局屬性 app.config.globalProperties 使用案例

    前端筆記(4) Vue3 全局屬性 app.config.globalProperties 使用案例

    學(xué)習(xí)Vue3有個把月了,記錄下學(xué)習(xí)中的小知識點。 首先很多同學(xué)還沒找到Vue3真正的官方文檔,下面給出Vue3的文檔網(wǎng)站 Vue3官網(wǎng)文檔 Vue3API文檔 官方解釋:一個用于注冊能夠被應(yīng)用內(nèi)所有組件實例訪問到的全局 property 的對象。 案例: 首先有一個請求后端接口的方法 在main.ts文

    2024年02月12日
    瀏覽(23)
  • Vue項目環(huán)境配置(尚硅谷筆記)

    3.1集成element-plus 硅谷甄選運營平臺,UI組件庫采用的element-plus,因此需要集成element-plus插件?。?! 官網(wǎng)地址:https://element-plus.gitee.io/zh-CN/ 入口文件main.ts全局安裝element-plus,element-plus默認支持語言英語設(shè)置為中文 Element Plus全局組件類型聲明 配置完畢可以測試element-plus組件與圖標(biāo)

    2024年02月06日
    瀏覽(14)
  • 前端筆記(11) Vue3 Router 編程式導(dǎo)航 router.push router.replace

    前端筆記(11) Vue3 Router 編程式導(dǎo)航 router.push router.replace

    在上篇博客Vue3 Router 監(jiān)聽路由參數(shù)變化中,我們使用 router-link 創(chuàng)建 a 標(biāo)簽來定義導(dǎo)航鏈接: 除了 router-link ,我們還可以借助 router 的實例方法,通過編寫代碼來實現(xiàn): router.push 方法會向 history 棧添加一個新的記錄,所以,當(dāng)用戶點擊瀏覽器后退按鈕時,會回到之前的 URL。

    2024年02月07日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包