Vue 之 vue3 的一些新特性的知识梳理(主要是在setup 语法糖中的语法编写,含vuex 4状态管理、vue-router 4路由管理)

前言

如果有对vue还不熟悉的小伙伴,建议先看Vue 之 Vue 的基础知识汇总 —— 总结一

基础语法几乎不变,例如:

  • 插值
  • 一系列的指令(v-text、v-html、v-if、v-show、v-for等)

下面是vue3的简单介绍:

特此说明,一切以vue官方文档为准,本文只是做新特性的知识梳理(含vuex 4状态管理、vue-router 4路由管理)。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

组合式API 以及 单文件组件组合式 API 语法糖 (<script setup>) 是我们关注的重点。


正文

setup

  setup语法糖是vue3新增的一大重点新特性,它将颠覆vue2的一些语法的写法,例如:定义响应式数据、定义方法、计算属性computed、监听属性watch、生命周期、组件通信等。

注:以下内容都是在setup 语法糖的前提下的实现方式。

主要是在以下两种方式:

  • 单文件组件组合式 API 语法糖 (<script setup>)
<script setup>
	
</script>
  • 组合式API

  这种方式可以延续使用vue2的写法,不受任何影响,关于setup新增的语法可以在setup()方法中编写:

<script>
	export default {
    
    
		name: '',
		data() {
    
     // 定义响应式数据
			return {
    
    }
		},
		setup(){
    
    
			// 编写关于setup新增的语法,最终需将被组件使用的属性和方法 给return 出去
			return {
    
    
				...
			}
		},
		watch: {
    
    }, // 监听属性
		computed: {
    
    }, // 计算属性
	    mounted() {
    
    }, // mounted生命周期
	    methods: {
    
    
	    	// 定义方法
		}		
	}
</script>



下面正式介绍在setup 语法糖中的新语法的代码编写。

开始之前

这里需要注意的是,在setup 语法中是没有this 的,这也就意味着:我们在使用或者赋值响应式数据、使用方法时,不能通过this.xxx的方式获取,而是通过xxx.value的方式获取以及赋值

定义响应式数据

具体请看官方文档

以下只是列了常用的定义响应式数据的方式:

  • ref、reactive 这两种好理解
  • 解释一下 toRef, toRefs
  • toRef:官方解释是可以用来为源响应式对象上的某个 property 新创建一个 ref。然后,ref 可以被传递,它会保持对其源 property 的响应式连接。
    大白话就是通过对象新创建了一个 ref,这个 ref 的值和原对象的 property 保持一致,也就是说,当对象中的 property 改变了,与这个property 通过 toRef 连接的新 ref 也会改变。
  • toRefs:官方解释是将响应式对象转换为普通对象,其中结果对象的每个 property 都是指向原始对象相应 property 的 ref。
    大白话就是通过对象新创建了一个 reactive,这个 reactive 的每一个property 和原对象对应的 property 保持一致,也就是说,当对象中的 property 改变了,与这个 property 通过 toRefs 连接的新 reactive 的 property 也会改变。

    注:toRef, toRefs可以用来解决props 组件通信时的响应式问题,详见下方的组件通信
<script setup>
	import {
    
     ref, reactive, toRef, toRefs } from 'vue'
	// 使用ref定义相关响应式数据,需先从vue中引入ref
	let str = ref('aa')
	let num = ref(3)
	let bool = ref(true)
	let arr1 = ref([])
	let arr2 = ref([1, 2, 3])
	// 使用reactive 定义对象响应式数据,需先从vue中引入reactive
	let obj1 = reactive({
    
    })
	let obj2 = reactive({
    
    
		id: 00202204240001,
		name: 'vue3'
	})
	let id = toRef(obj2, 'id')
	let obj3 = toRefs(obj2)
</script>


定义方法

<script setup>
	import {
    
     ref } from 'vue'
	let str = ref('aa')
	// 定义方法
	const changeStr = () => {
    
    
		str.value = 'bb' // 这里需要通过xxx.value的方式获取、赋值响应式数据
	}
</script>


计算属性 computed

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

	const num = ref(3)
	const newNum = computed(() => num.value * 2) // 使用了箭头函数省略return 的写法
	
	num.value++
	console.log(num.value) // 4
	console.log(newNum.value) // 8
</script>


监听属性 watch

<script setup>
	import {
    
     ref, watch } from 'vue'
	let num = ref(0)
	watch(num, (newValue, oldValue) => {
    
    
	  console.log('The new num value is: ' + num.value)
	})
</script>


生命周期

选项式 API Hook inside setup
beforeCreate Not needed*
created Not needed*
beforeMount onBeforeMount
mounted onMounted
beforeUpdate onBeforeUpdate
updated onUpdated
beforeUnmount onBeforeUnmount
unmounted onUnmounted
errorCaptured onErrorCaptured
renderTracked onRenderTracked
renderTriggered onRenderTriggered
activated onActivated
deactivated onDeactivated
<script setup>
	// 需先将生命周期函数引入
	import {
    
     onMounted } from 'vue'
	onMounted(() => {
    
    
		console.log('Component is mounted!')
		// 调接口
	})
</script>


组件通信

  • 父组件
<template>
	<!-- 父组件向子组件传参 -->
    <HelloWorld :msg="msg" @getMsg="getMessage" :isShow="isShow"/>
    <br>
    <button @click="changIsShow">changIsShow</button>
</template>
<script setup>
	// 将组件引入之后可以直接在 template 中使用
	import HelloWorld from "@/components/HelloWorld.vue"
    import {
    
     ref } from "vue"
    
    let msg = ref("父组件向子组件传参")
    let isShow = ref(true)
    
    const getMessage = emitMsg => {
    
    
        console.log('子组件向父组件传参', emitMsg) // 子组件向父组件传参
    }
    const changIsShow = () => {
    
    
        isShow.value = !isShow.value
    }
</script>
  • 子组件
<template>
	<h1>{
   
   { msg }}</h1>
    <h2>{
   
   { message }}</h2>
    <h2 v-show="isShow">{
   
   { isShow }}</h2>

    <button @click="changeMsg">change</button>
</template>
<script setup>
	import {
    
     ref, toRefs, toRef, watch } from "vue"
    let props = defineProps({
    
    
        msg: String,
        isShow: Boolean
    })
    console.log(1111, props.msg) // 打印的就是传过来的msg的值:父组件向子组件传参
    let message = ref(props.msg)
    // 1、toRefs时将props的每个property与新数据做响应式连接
    let {
    
     msg } = toRefs(props)
    // 2、而toRef则是将props的单个property与新数据做响应式连接
    let isShow  = toRef(props, 'isShow')

    const emit = defineEmits(["getMsg"])
    const changeMsg = () => {
    
    
        message.value = message.value + " ====> emit"
        emit("getMsg", message) // 然后向父组件传参
    }
    watch(isShow, (newVal) => {
    
    
        if(newVal) {
    
    
            console.log('true', isShow);
        } else {
    
    
            console.log('false', isShow);
        }
    })
</script>

在这里插入图片描述


ref(属性)

这个ref 是指属性ref,不是定义响应式数据的 ref,但是还是要依赖响应式数据的ref Api去实现。

  vue2ref 属性的写法,在js 代码中是通过 this.$refs.xxx 的方式获取,但是vue3 由于setup 语法糖中没有没有this,所以我们需要依赖ref Api 去实现。

<template>
	<div ref="divDom">divDom</div>
	<button	@click="getRef">获取ref属性</button>
</template>
<script setup>
	import {
    
     ref } from 'vue'
	let divDom = ref(null)
	const getRef = () => {
    
    
		console.log(divDom.value);
		divDom.value.style.color = 'red'
	}
</script>


router

vue-router4官网

  • router/index.js

    • vue-router 4

      import {
              
               createRouter, createWebHashHistory } from "vue-router"
      const router = createRouter({
              
              
          // 内部提供了 history 模式的实现。为了简单起见,我们在这里使用 hash 模式。
          history: createWebHashHistory(),
          routes: [...] // 路由数组
      })
      export default router
      
    • vue-router 3

      import Vue from "vue"
      import VueRouter from "vue-router"
      
      Vue.use(VueRouter)
      
      const router = new VueRouter({
              
              
          mode: "hash",
          routes: [...], // 路由数组
      })
      export default router
      
  • 某列表组件

<script setup>
	import {
    
     ref, watch } from 'vue'
	import {
    
     useRouter, useRoute } from 'vue-router'
	const router = useRouter() // 和 vue2中的this.$router 是一样的
	const toDetail = (id) => {
    
    
		router.push({
    
     
			path: `/detail`
			query: {
    
    
				id: id
			}
		})
	}
	
	const route = useRoute() // 和 vue2中的this.$route 是一样的
	watch(route, () => {
    
    
	    // ...
	})
</script>
  • detail.vue
<script setup>
	import {
    
     ref, onMounted } from 'vue'
	import {
    
     useRoute } from 'vue-router'
	const route = useRoute() // 和 vue2中的this.$route 是一样的
	let currentId = ref('')
	onMounted( () => {
    
    
		currentId.value = route.query.id
	})
</script>


vuex

vuex4官网

  • tabsView.js modules

注:statevuex3 中是一个对象的命名方式,而在vuex4 中是一个函数的命名方式。

/**
 * 顶部页签栏
 */
// vuex3命名state
// const state = {
    
    
//     tabList: [], // 页签数组
// }

// vuex4命名state
const state = () => {
    
    
    return {
    
    
        tabList: [], // 页签数组
    }
}

const getters = {
    
    
	navList: (state) => {
    
    
      return state.tabList.filter(item => item.isNav)
    }
}

const mutations = {
    
    
	ADDTAB() {
    
    }
}

const actions = {
    
    
	removeTab() {
    
    }
}

export default {
    
    
    namespaced: true, // 开启命名空间
    state,
    getters,
    mutations,
    actions,
}

  • store 出口文件 index.js

  此代码是使用了 vuex-persistedstatestate 进行了持久化处理,详见Vue 之 vuex 解决刷新页面 state 数据丢失的问题,使用vuex-persistedstate进行state持久化

import {
    
     createStore } from "vuex"

import createPersistedState from "vuex-persistedstate"

import tabsView from "./modules/tabsView"

const tabListState = createPersistedState({
    
    
    storage: window.sessionStorage,
    paths: ["tabsView.tabList"],
})

const store = createStore({
    
    
    modules: {
    
    
        tabsView,
    },
    plugins: [tabListState],
})

export default store
  • 某组件中
<script setup>
	import {
    
     ref } from 'vue'
	import {
    
     useStore } from 'vuex'
	let store = useStore() // 和vue2中的this.$store是一样的
	// 只不过需要注意的是:
	// state、getter 是在 computed 计算属性中获取
	// 使用 state
	let tabList = computed(() => store.state.tabsView.tabList)
	// 使用 getter 
	let navList = computed(() => store.getters.tabsView.navList)
	
	// mutations、actions 则直接使用箭头函数return即可
	// 使用 mutation
    const ADDTAB = () => store.commit('tabsList/ADDTAB', 123),
    // 使用 action
    const removeTab = () => store.dispatch('tabsList/removeTab', 321)
</script>



写在末尾

一切以官方文档为准,本文只是就 vue3vuex 4状态管理vue-router 4路由管理的一些新特性做了简单的知识梳理;


如有错误,欢迎指出。谢谢。


如有不足,望大家多多指点! 谢谢!

猜你喜欢

转载自blog.csdn.net/Zhuangvi/article/details/124374598
今日推荐