VUE 3.0 初體驗之路

Echoyya、發表於2021-02-09

碼文不易啊,轉載請帶上本文連結呀,感謝感謝 https://www.cnblogs.com/echoyya/p/14394057.html

在2020年9月中旬,vue.js釋出了3.0正式版,在不久的將來,VUE3.0 也終將成為大前端的必然趨勢,

環境搭建

  1. node 版本要求: Node.js8.9 或更高版本 ,輸入 node -v 檢視node版本

  2. vue-cli 版本:達到 vue-cli4.5.0 以上,可建立vue3.0的專案,支援體驗vue3.0的新特性,(3.x Preview),vue -V 檢視腳手架版本

  3. 終端輸入: vue create project_name

核心知識


一 、元件的定義和使用

元件:是維護單一功能,可複用的單個個體,相同的樣式及邏輯即可抽離成元件,方便維護,複用性增強。也是vue3.0專案中,最核心的概念

defineComponent:vue3.0中提供了一個函式返回傳遞給它的物件,最重要的是:在TypeScript下,給予了元件 正確的引數型別推斷 。此處先不展開介紹,後續會總結 vue3.0 + ts。

setup:元件的啟動函式,兩個引數: props(父元件傳遞的資料)content ( 上下文物件),最後return 定義的資料,方法,鉤子函式等,且setup中 沒有this,不能訪問this

<script>

    import { defineComponent } from 'vue'
    
    export default defineComponent ({
      setup (props, content) {
        // TODO 資料,方法,鉤子函式等
        return { }
      }
    })

</script>

二、資料的定義和使用

  1. ref定義單個資料,接受一個引數值並返回一個響應式且可改變的 ref 物件。ref 物件擁有一個指向內部值的單一屬性 .value
import { ref } from 'vue'

export default {
  setup () {
    let num1 =  ref(10)  // Number
    let name1 =  ref('Echoyya')  // String
    let arr1 =  ref(['a','d','c','d'])  // Array 
    let obj1 =  ref({age:20})  // Object 

    // 獲取及改變 ref物件的值,獲取內部值的單一屬性 value
    console.log(num1.value) // 10

    num1.value++
    console.log(num1.value) // 11
    
    return {
      //使用 ref 定義的資料,需要直接 return
      num1,name1,arr1,obj1
    }
  }
}

  1. reactive: 用於建立響應式資料,接收一個普通物件然後返回該普通物件的響應式代理,即雙向資料繫結,
    • 使用 reactive 定義的資料,不需要逐一 return,可以使用 ES6 的擴充套件運算子。

    • 解構會破壞雙向資料繫結的特性, 變更為單向資料繫結

    • 解決:vue3.0中新增了新特性,可對當前的資料進行轉換。將其轉換為響應式資料,toRefs將資料包裹即可轉換為響應式資料

import { reactive, toRefs } from 'vue'

export default {
  setup () {
    let data = reactive ({
      num:33,
      arr:['a','d','c','d'],
      obj:{age:20},
    })
     // 獲取及改變:reactive 定義的資料,呼叫時直接 reactive變數名.資料名,
    console.log(data.num) // 33

    data.num++
    console.log(data.num) // 34
    
    return {
      ...toRefs(data) 
    }
  }
}

三、方式的定義和使用

建立的方法仍然需要 return

<template>
  <div>
    <p><button @click="clickNum">{{num}}</button></p>
    <p><button @click="clickNum1">{{num1}}</button></p>
    <p><button @click="singleMethod">{{name}}</button></p>
  </div>
</template>

<script>

import { reactive, ref, toRefs } from 'vue'
export default {
  setup () {
    let num1 =  ref(10)
    let name =  ref('Echoyya')
    let data = reactive({
      num:33,
    })

    // 定義多個方法,不需要逐一 return
    let methods  = {
      clickNum1: () => {
        num1.value++ 
        console.log(num1.value);
      },
      clickNum : () => {
        data.num ++ 
        console.log(data.num);
      }
    }
     // 定義單個方法,需要return
    let singleMethod = () => {
      console.log(name.value)
    }
    return {
      num1,
      name,
      singleMethod,
      ...toRefs(data)
      ...methods,
    }
  }
}

</script>

四、路由的定義、使用和傳參

  1. /src/router/index.js:在路由檔案中使用了createRouter方法
import { createRouter } from 'vue-router'
const routes = [
  {
    path: '/',
    name: 'Home',
    component: () => import('../views/Home.vue')
  },
  {
    path: '/about',
    name: 'About',
    component: () => import('../views/About.vue')
  }
]
const router = createRouter({
  routes
})

export default router

  1. home元件中使用,路由跳轉及傳遞引數
<template>
  <div>
    <p><button @click="gotoQuery">query跳轉</button></p>
    <p><button @click="gotoParams">params跳轉</button></p>
  </div>
</template>

<script>

import { useRouter } from 'vue-router'
export default {
  setup (){
    // router物件是全域性路由的例項。
    let router = useRouter()

    // 跳轉路由用push: 跳轉時可使用name 和 path,傳遞引數可使用query 和 params

    let gotoQuery = () => {
      // query: 可以使用name和path,引數顯示在位址列中, 且頁面重新整理引數仍在
      router.push({
        // name:'About',
        path:'/about',
        query:{
          name:'Echoyya',
          age: 25,
          obj:JSON.stringify({gender:"f"})
        },
      })
    }
    let gotoParams = () => {
       // params:只能使用name ,不顯示在位址列中,且頁面重新整理,引數清空 console.log(route.params); 列印空物件
       router.push({
        name:'Home',
        params:{
          name:'Echoyya',
          age: 25,
          obj:JSON.stringify({gender:"f"})
        }
      })
    }

    return {
      gotoQuery,
      gotoParams
    }
  }
}
  1. about元件中使用,接收路由引數
import { useRoute } from 'vue-router'
export default {
  setup (){
    // route物件表示當前的路由資訊,包含了當前 URL 解析得到的資訊。包含當前的路徑,引數,query物件等。
    let route = useRoute() 
    
    console.log(typeof route.query.age) //string, query傳遞的引數都是string型別
    console.log(route.query);    //獲取query傳參
    console.log(route.params);    //獲取params傳參
    return {}
  }
}

五、父子元件傳值

  1. 父 to 子:通過動態繫結屬性的方式,子元件在props 中去接收,

  2. 子 to 父:通過ctx.emit('事件名稱', 傳遞的引數)事件分發的方式, 父元件當中,呼叫子元件標籤上繫結自定義事件,其中包含一個引數,即子元件傳遞過來的資料

    • ctx.emit('事件名稱', 傳遞的引數)事件分發, ctx是 setup 函式的第二個引數,上下文物件

    • emit 只能接受兩個引數,其餘不生效,第一個引數:事件名稱,第二個: 傳遞的資料

    • 事件分發,不一定要通過點選事件,也可使用鉤子函式等

    • 需要傳遞多個引數時,emit第二個引數可選擇陣列或是物件

father.vue

<template>
  <div class="wrapper">
    <p>this is father components</p>
    <p> 子元件傳遞的值:{{childMsg}}</p>
    <!-- msg 自定義屬性,send 自定義監聽事件-->
    <p><child :msg="msg" @send="getChildData"></child></p>
  </div>
</template>

<script>
import { ref } from 'vue'
import child from '../components/child'
export default {
  components:{
    child
  },
  setup() {
    let msg = ref('father元件資料')
    let childMsg = ref('')
    let getChildData = (data)=>{
      childMsg.value = data
    }
    return {
      msg,
      childMsg,
      getChildData
    }
  },
}
</script>

child.vue

<template>
  <div>
    this is child components
    <p>父元件傳遞過來的值:{{msg}}</p>
    <p><button @click="send">傳值給父元件</button></p>
  </div>
</template>

<script>
import {ref,onMounted, reactive} from  'vue'
export default {
  name:'child',
  // props 接收的資料,不能直接修改,如props.xxx = yy
  props:{
    msg:{
      type:String , // 資料型別校驗
      require:true ,  // 是否必傳 預設false
      default:'預設值' // require和default 有些衝突,即必填時,可不設定預設值
    }
  },
  setup(props,ctx){
    console.log(props.msg);   // 父元件傳遞的資料:father元件資料

    let childMsg = ref('child元件資料')
    let data = reactive({
      childNum:10
    })
    
    let send = ()=>{
       ctx.emit('send',childMsg.value)
       // ctx.emit('send',[childMsg.value,data.childNum])  // 陣列
       // ctx.emit('send',{  // 物件
       //   msg:childMsg.value,
       //   num:data.childNum
      })  
    }
    return {
     childMsg,
     send,
     ...data
    }
  }
})
</script>

六、狀態管理的定義和使用

狀態管理即 VUEX,為達到資料共享的目的

  1. /src/store/index.js:在狀態管理檔案中使用了createStore方法
import { createStore } from 'vuex'

export default createStore({
  // 定義所需要的狀態
  state: {
    name: 'Echoyya',
  },

  // 同步修改state ,是方法,不能操作非同步操作(包括髮送請求及定時器等)
  mutations: {
    // 可接收兩個引數:一:state,二:需修改的值,payload(可選)
    setName(state, payload) {
      state.name = payload
    },
  },
  // 提交 mutations
  actions: {
    // 可接收兩個引數 一:store, 二 要修改的值
    asyncSetName(store, params) {
      setTimeout(() => {
        // commit 是提交mutation, 提交非同步的mutations方法
        store.commit('setName', params)
        console.log(store.state.name) 
      }, 2000)
    }
  },
  // 模組化
  modules: {}
})

  1. 元件中呼叫,VUEX運算元據
<template>
  <div>
    {{name}}===={{name1}}===={{name2}}
    <p><button @click="setName">設定 name</button></p>
    <p><button @click="asyncSetName">非同步設定 name</button></p>
  </div>
</template>

<script>
import { reactive, ref, toRefs, computed } from 'vue'
import { useStore } from 'vuex'

export default {
  setup (){
    //通過 ref 方式
    let name = ref(store.state.name)
   
    // 計算屬性 方式
    let name1 = computed(()=>{
      return store.state.name + 'computed'
    })
    
    //reactive 方式
    let data = reactive({
       name2:store.state.name + '_reactive'
    })
    
    // 觸發 mutations
    let setName = ()=>{
       console.log(store.state.name)  // Echoyya
       store.commit('setName','nhyya') 
       console.log(store.state.name)  // nhyya
    }
    // 觸發 action
    let asyncSetName = ()=>{
        store.dispatch('asyncSetName','nhyya1212') 
    }
    return {
      name,
      name1,
      ...toRefs(data),
      setName,
      asyncSetName
    }
  }
})
</script>

七、常用的生命週期

  1. setup:不需要引入的生命週期 ,表示元件建立的過程,且沒有this

  2. onMounted:比setup 稍微晚一些執行,表示元件掛載的過程,包括資料, dom元素等,是一個函式,需要傳入一個回撥函式執行,無引數。

    • 常用於:傳送請求、資料初始化的操作、接受路由傳遞的引數
  3. onUnmounted:與 onMounted 相對應,元件解除安裝或銷燬(路由跳轉),常用於清除定時器等操作

較 VUE2.0 另有哪些改變?

  • 3.0去掉了filter, 沒有beforeCreate created,用setup取代

  • setup裡沒有this

  • 3.0相容IE12以上

  • 可直接監聽陣列型別的資料變化

  • 監聽的目標為物件本身,不需要像Object.defineProperty一樣遍歷每個屬性,有一定的效能提升

  • 直接實現物件屬性的新增/刪除

  • 重構 Virtual DOM:模板編譯時的優化,將一些靜態節點編譯成常量

  • 另附上vue3.0 文件地址: https://v3.cn.vuejs.org/

上述內容並非全部 VUE3 內容,只是我通過一段時間的學習,做的自我總結,以便學習和複習,寫的不準確之處還望大神們能留言指正