快速上手 vue3

虛乄發表於2022-02-25

當前為vue3的基礎知識點,為總結b站某視訊的知識文章,在剛開始學習時自我儲存在語雀,現在分享到部落格。

目前找不到原視訊文章地址了!!!要有兄弟看到原文地址:歡迎在下面評論!

Vue3新的特性

  1. Composition API(組合API)
    1. setup配置
    2. ref與reactive
    3. watch與watchEffect
    4. provide與inject
  1. 新的內建元件
    1. Fragment
    2. Teleport
    3. Suspense
  1. 其他改變
    1. 新的生命週期鉤子
    2. data 選項應始終被宣告為一個函式
    3. 移除keyCode支援作為 v-on 的修飾符

建立Vue3.0工程

1.使用 vue-cli 建立

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

## 檢視@vue/cli版本,確保@vue/cli版本在4.5.0以上
vue --version
## 安裝或者升級你的@vue/cli
npm install -g @vue/cli
## 建立
vue create vue_test
## 啟動
cd vue_test
npm run serve

 

 常用 Composition API

官方文件: https://v3.cn.vuejs.org/guide/composition-api-introduction.html

1.拉開序幕的setup

  1. 理解:Vue3.0中一個新的配置項,值為一個函式。
  2. setup是所有Composition API(組合API)“ 表演的舞臺 ”。
  1. 元件中所用到的:資料、方法等等,均要配置在setup中。
  2. setup函式的兩種返回值
    1. 若返回一個物件,則物件中的屬性、方法, 在模板中均可以直接使用。(重點關注!)
    2. 若返回一個渲染函式:則可以自定義渲染內容。(瞭解)
快速上手 vue3
<template>
  <h1>測試setup,拿資料</h1>
  <h3>姓名:{{ name }}</h3>
  <h3>年齡:{{ age }}</h3>
  <button @click="sayHello">打招呼</button>
</template>

<script>
// 渲染函式 要匯入這個
import { h } from '@vue/runtime-core';
export default {
  name: "TestSetup",
  //此處只是測試setup,  不考慮響應式的問題
  setup() {
    //資料
    let name = "張三",
             age = 15;
    //方法
    function sayHello() {
      alert(`我叫${name},我${age}歲了,你好!`);
    }
    //返回一個物件 (常用)
    return {
      name,
      age,
      sayHello,
    };
    //返回一個函式(渲染函式--瞭解)
    // return ()=> h('h1','返回一個函式(渲染函式)')
  },
};
</script>

<style>
</style>
View Code

  5.注意點

    1. 儘量不要與Vue2.x配置混用
    2. Vue2.x配置(data、methos、computed...)中可以訪問到setup中的屬性、方法。
    3. 但在setup中不能訪問到Vue2.x配置(data、methos、computed...)。
    4. 如果有重名, setup優先。
    5. setup不能是一個async函式,因為返回值不再是return的物件, 而是promise, 模板看不到return物件中的屬性。(後期也可以返回一個Promise例項,但需要Suspense和非同步元件的配合)

2.ref函式

  1. 作用: 定義一個響應式的資料
  2. 語法: const xxx = ref(initValue)
    1. 建立一個包含響應式資料的引用物件(reference物件,簡稱ref物件)
    2. JS中運算元據: xxx.value
    3. 模板中讀取資料: 不需要.value,直接:<div>{{xxx}}</div>
  3. 備註:
    1. 接收的資料可以是:基本型別、也可以是物件型別。
    2. 基本型別的資料:響應式依然是靠Object.defineProperty()getset完成的。
    3. 物件型別的資料:內部 “ 求助 ” 了Vue3.0中的一個新函式—— reactive函式。
快速上手 vue3
<template>
  <h1>學習ref</h1>
  <h3>姓名:{{ name }}</h3>
  <h3>年齡:{{ age }}</h3>
  <button @click="alterName">修改姓名</button>
</template>

<script>
// 響應式 ref
import { ref } from '@vue/reactivity';
export default {
  name: "testRef",
  setup() {
    //資料
    let name = ref("張三"),
      age = 15,
      obj = ref({
          type:'前端工程師',
          salary:'5K'
      });

    //方法
    function alterName() {
        //成功
        name.value = "修改姓名"
          //物件
        obj.value.type = "修改工作"
        obj.value.salary = "60k"
        //修改失敗
        age ="修改年齡"
    }

    //返回一個物件 (常用)
    return {
      name,
      age,
      alterName,
    };
  },
};
</script>

<style>
</style>
View Code

3.reactive函式

  1. 作用: 定義一個物件型別的響應式資料(基本型別不要用它,要用ref函式)
  2. 語法:const 代理物件= reactive(源物件)接收一個物件(或陣列),返回一個代理物件(Proxy的例項物件,簡稱proxy物件)
  3. reactive定義的響應式資料是“深層次的”。
  4. 內部基於 ES6 的 Proxy 實現,通過代理物件操作源物件內部資料進行操作。
快速上手 vue3
<template>
  <h1>學習reactive</h1>
  <h3>工作:{{ obj.type }}</h3>
  <h3>薪水:{{ obj.salary }}</h3>
     <h3>愛好:{{ list }}</h3>
  <button @click="alterName">修改姓名</button>
</template>

<script>
/*
 響應式 
    reactive 物件型別
*/
import { reactive } from "@vue/reactivity";
export default {
  name: "testRef",
  setup() {
    //資料
    let obj = reactive({
        type: "前端工程師",
        salary: "5K",
      }),
      list = reactive(['吃飯','睡覺','打豆豆']);
    //方法
    function alterName() {
      //物件
      obj.type = "修改工作";
      obj.salary = "60k";
      //陣列
      list[0] = '出去玩'
    }
    //返回一個物件 (常用)
    return {
      obj,
      list,
      alterName,
    };
  },
};
</script>

<style>
</style>
View Code

 4.reactive對比ref

  1. 從定義資料角度對比:
    1. ref用來定義:基本型別資料
    2. reactive用來定義:物件(或陣列)型別資料
    3. 備註:ref也可以用來定義物件(或陣列)型別資料, 它內部會自動通過reactive轉為代理物件
  2. 從原理角度對比:
    1. ref通過Object.defineProperty()getset來實現響應式(資料劫持)。
    2. reactive通過使用Proxy來實現響應式(資料劫持), 並通過Reflect操作源物件內部的資料。
  3. 從使用角度對比:
    1. ref定義的資料:運算元據需要.value,讀取資料時模板中直接讀取不需要.value
    2. reactive定義的資料:運算元據與讀取資料:均不需要.value

5.setup的兩個注意點

  1. setup執行的時機
    1. 在beforeCreate之前執行一次,this是undefined。
  2. setup的引數
    1. props:值為物件,包含:元件外部傳遞過來,且元件內部宣告接收了的屬性。
    2. context:上下文物件
    3. attrs: 值為物件,包含:元件外部傳遞過來,但沒有在props配置中宣告的屬性, 相當於 this.$attrs
    4. slots: 收到的插槽內容, 相當於 this.$slots
    5. emit: 分發自定義事件的函式, 相當於 this.$emit

6.元件傳值,插槽,自定義事件

程式碼例項

快速上手 vue3
//父頁面
<template>
    <Demo @hello="showHelloMsg" msg="你好啊" school="尚矽谷">
        <template v-slot:qwe>
            <span>尚矽谷</span>
        </template>
        <template v-slot:asd>
            <span>尚矽谷</span>
        </template>
    </Demo>
</template>

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

//元件
<template>
    <h1>一個人的資訊</h1>
    <h2>姓名:{{person.name}}</h2>
    <h2>年齡:{{person.age}}</h2>
    <button @click="test">測試觸發一下Demo元件的Hello事件</button>
</template>

<script>
    import {reactive} from 'vue'
    export default {
        name: 'Demo',
    //接收引數
        props:['msg','school'],
    //宣告接收 自定義事件
        emits:['hello'],
    //setup 的引數
        setup(props,context){
            // console.log('---setup---',props) //接收引數
            // console.log('---setup---',context) //上下文
            // console.log('---setup---',context.attrs) //相當與Vue2中的$attrs
            // console.log('---setup---',context.emit) //觸發自定義事件的。
            console.log('---setup---',context.slots) //插槽
            //資料
            let person = reactive({
                name:'張三',
                age:18
            })

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

            //返回一個物件(常用)
            return {
                person,
                test
            }
        }
    }
</script>
View Code

7.計算屬性與監視

computed函式

  1. 與Vue2.x中computed配置功能一致
  2. 寫法 
快速上手 vue3
<template>
    <h1>一個人的資訊</h1>
    姓:<input type="text" v-model="person.firstName">
    <br>
    名:<input type="text" v-model="person.lastName">
    <br>
    <span>全名:{{person.fullName}}</span>
    <br>
    全名:<input type="text" v-model="person.fullName">
</template>

<script>
   //匯入 computed 計算屬性
    import {reactive,computed} from 'vue'
    export default {
        name: 'Demo',
        setup(){
            //資料
            let person = reactive({
                firstName:'張',
                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>
View Code

watch函式

  1. 與Vue2.x中watch配置功能一致
  2. 兩個小“坑”:
    1. 監視reactive定義的響應式資料時:oldValue無法正確獲取、強制開啟了深度監視(deep配置失效)。
    2. 監視reactive定義的響應式資料中某個屬性時:deep配置有效。
快速上手 vue3
<template>
    <h2>當前求和為:{{sum}}</h2>
    <button @click="sum++">點我+1</button>
    <hr>
    <h2>當前的資訊為:{{msg}}</h2>
    <button @click="msg+='!'">修改資訊</button>
    <hr>
    <h2>姓名:{{person.name}}</h2>
    <h2>年齡:{{person.age}}</h2>
    <h2>薪資:{{person.job.j1.salary}}K</h2>
    <button @click="person.name+='~'">修改姓名</button>
    <button @click="person.age++">增長年齡</button>
    <button @click="person.job.j1.salary++">漲薪</button>
</template>

<script>
    import {ref,reactive,watch} from 'vue'
    export default {
        name: 'Demo',
        setup(){
            //資料
            let sum = ref(0)
            let msg = ref('你好啊')
            let person = reactive({
                name:'張三',
                age:18,
                job:{
                    j1:{
                        salary:20
                    }
                }
            })

            //情況一:監視ref所定義的一個響應式資料
            /* watch(sum,(newValue,oldValue)=>{
                console.log('sum變了',newValue,oldValue)
            },{immediate:true}) */

            //情況二:監視ref所定義的多個響應式資料
            /* watch([sum,msg],(newValue,oldValue)=>{
                console.log('sum或msg變了',newValue,oldValue)
            },{immediate:true}) */

            /* 
                情況三:監視reactive所定義的一個響應式資料的全部屬性
                        1.注意:此處無法正確的獲取oldValue
                        2.注意:強制開啟了深度監視(deep配置無效)
            */
            /* watch(person,(newValue,oldValue)=>{
                console.log('person變化了',newValue,oldValue)
            },{deep:false}) //此處的deep配置無效 */

            //情況四:監視reactive所定義的一個響應式資料中的某個屬性
            /* watch(()=>person.name,(newValue,oldValue)=>{
                console.log('person的name變化了',newValue,oldValue)
            })  */

            //情況五:監視reactive所定義的一個響應式資料中的某些屬性
            /* watch([()=>person.name,()=>person.age],(newValue,oldValue)=>{
                console.log('person的name或age變化了',newValue,oldValue)
            })  */

            //特殊情況
            /* watch(()=>person.job,(newValue,oldValue)=>{
                console.log('person的job變化了',newValue,oldValue)
            },{deep:true}) //此處由於監視的是reactive素定義的物件中的某個屬性,所以deep配置有效 */


            //返回一個物件(常用)
            return {
                sum,
                msg,
                person
            }
        }
    }
</script>
View Code

watch監視ref資料的說明

快速上手 vue3
<template>
    <h2>當前求和為:{{sum}}</h2>
    <button @click="sum++">點我+1</button>
    <hr>
    <h2>當前的資訊為:{{msg}}</h2>
    <button @click="msg+='!'">修改資訊</button>
    <hr>
    <h2>姓名:{{person.name}}</h2>
    <h2>年齡:{{person.age}}</h2>
    <h2>薪資:{{person.job.j1.salary}}K</h2>
    <button @click="person.name+='~'">修改姓名</button>
    <button @click="person.age++">增長年齡</button>
    <button @click="person.job.j1.salary++">漲薪</button>
</template>

<script>
    import {ref,reactive,watch} from 'vue'
    export default {
        name: 'Demo',
        setup(){
            //資料
            let sum = ref(0)
            let msg = ref('你好啊')
            let person = ref({
                name:'張三',
                age:18,
                job:{
                    j1:{
                        salary:20
                    }
                }
            })

            console.log(person)

            watch(sum,(newValue,oldValue)=>{
                console.log('sum的值變化了',newValue,oldValue)
            })

      /*
          person 為 reactive 函式的物件 
        deep:true 需要開啟深度監視
        
        person.value 直接監視 reactive 函式的物件 
        可以參考上面 情況三
      */ 
            watch(person,(newValue,oldValue)=>{
                console.log('person的值變化了',newValue,oldValue)
            },{deep:true})


            //返回一個物件(常用)
            return {
                sum,
                msg,
                person
            }
        }
    }
</script>
View Code

watchEffect函式

  1. watch的套路是:既要指明監視的屬性,也要指明監視的回撥。
  2. watchEffect的套路是:不用指明監視哪個屬性,監視的回撥中用到哪個屬性,那就監視哪個屬性。
  3. watchEffect有點像computed:
    1. 但computed注重的計算出來的值(回撥函式的返回值),所以必須要寫返回值。
    2. 而watchEffect更注重的是過程(回撥函式的函式體),所以不用寫返回值。
快速上手 vue3
<template>
    <h2>當前求和為:{{sum}}</h2>
    <button @click="sum++">點我+1</button>
    <hr>
    <h2>當前的資訊為:{{msg}}</h2>
    <button @click="msg+='!'">修改資訊</button>
    <hr>
    <h2>姓名:{{person.name}}</h2>
    <h2>年齡:{{person.age}}</h2>
    <h2>薪資:{{person.job.j1.salary}}K</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('監視屬性','回撥','配置')
            /* watch(sum,(newValue,oldValue)=>{
                console.log('sum的值變化了',newValue,oldValue)
            },{immediate:true}) */
            
      //不用指明監視哪個屬性,監視的回撥中用到哪個屬性,那就監視哪個屬性
            watchEffect(()=>{
                const x1 = sum.value
                const x2 = person.job.j1.salary
                console.log('watchEffect所指定的回撥執行了')
            })

            //返回一個物件(常用)
            return {
                sum,
                msg,
                person
            }
        }
    }
</script>
View Code

8.生命週期

2.0與3.0對比

vue2 vue3

beforeCreate

setup()

created

setup()

beforeMount

onBeforeMount

mounted

onMounted

beforeUpdate

onBeforeUpdate

updated

onUpdated

beforeUnmount 

onBeforeUnmount

unmounted

onUnmounted

 程式碼例項

快速上手 vue3
<template>
    <h2>當前求和為:{{sum}}</h2>
    <button @click="sum++">點我+1</button>
</template>

<script>
  //匯入生命週期
    import {ref,onBeforeMount,onMounted,
          onBeforeUpdate,onUpdated,
          onBeforeUnmount,onUnmounted} from 'vue'
    export default {
        name: 'Demo',
        setup(){
            console.log('---setup---')
            //資料
            let sum = ref(0)
      
            //通過組合式API的形式去使用生命週期鉤子 
      
      //先執行組合式 之後 配置項的形式  生命週期
            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>
View Code

 

 

 

相關文章