阅读 66

Vue3基本知识点

这是一份个人学习Vue3的笔记整理,不会去记录某些Api的原理,只记录这些API的一些基本用法,有写错的地方,希望包涵指正。

安装

要体验Vue3的话,需要安装最新版的VueCLi(当然使用Vite也行),安装之后,通过vue create demo即可选择创建Vue3的项目。

组合式API

CompositionAPI(组合式API)是Vue3新的写法,从官方文档可以看到它的特点:能够将同一个逻辑关注点相关的代码配置在一起,使得应用程序在可维护性和灵活性方面走得更远。

使用:

组合式API必须使用在setup函数里面,即setup函数是组合式API的入口函数。

setup

setup函数的第一个特点就是:由于setup在组件实例前先执行,所以除了props以外无法访问thiscomputed,methods等等,但作为代替我们可以以其他的书写方式来实现:

setup (props) {
    function greet () {
        console.log('Hellol')
    }
    watch(() => props.msg, (newVal, oldVal) => {
        console.log(newVal, oldVal)
    })
    const rMsg = computed(() => {
        return props.msg.split('').reverse().join('')
    })

    return {
        greet,
        rMsg
    }
}
复制代码

可以看到,在setup里面通过组合式API添加了greet方法,监听了propsmsg属性,以及添加了一个计算属性rMsg,这些新加的属性或方法必须返回之后才能在template正常使用。

setup里面使用props的时候,依然需要定义props对象,来规定传递过来的属性名称和默认值。

reactive

reactive是组合式API里面的响应式API,通过reactive可以返回一个具有响应式的副本对象(所有嵌套的对象都会被代理):

const state = reactive({
    msg: 'Hello.'
})
function reverseMsg () {
    state.msg = state.msg.split('').reverse().join('')
}
return {
    state,
    reverseMsg
}
复制代码

此时,如果执行reverseMsg方法的话,模板里含有的state.msg的UI也会跟着刷新,但是通过reactive定义的对象副本有两个特点:

  1. 必须是一个对象,否则UI不会更新,例如:num = reactive(0),这种是不会更新UI的;
  2. 里面定义的其他对象要修改时,必须重新赋值,否则也不会刷新UI界面,例如Date对象,不能通过setDate这样的API来刷新UI界面。

readonly

readonly类似于reactive,只是它定义的副本是只读的,类似const定义变量那种,他的所有嵌套也是只读的。

 const state = readonly({
     msg: 'Hello.'
 })
 function reverseMsg () {
     state.msg = state.msg.split('').reverse().join('')
 }
复制代码

上面代码会有警告:Set operation on key "msg" failed: target is readonly. {msg: "Hello."},并且所做的修改时无效的。

shallowRecative

reactive一样是创建一个响应式对象副本的,区别就是它只是第一层做了代理,里面的对象不做递归代理。

const state = reactive({
    msg: 'Hello.',
    info: {
        title: 'vue3'
    }
})
console.log(state, state.info)
复制代码

这是由reactive定义的对象副本,打印出来的是Proxy {msg: "Hello.", info: {…}} Proxy {title: "vue3"},可以看到info也是被Proxy代理了的,再看看shallowReactive创建的对象副本:

const state = shallowReactive({
    msg: 'Hello.',
    info: {
        title: 'vue3'
    }
})
console.log(state, state.info)
复制代码

打印出来的是:Proxy {msg: "Hello.", info: {…}} {title: "vue3"}

他们两个的区别就是,因为reactive是递归来代理了所有对象的,所以不管修改外面的对象还是里面的对象,也会让UI刷新;而shallowReactive只有修改最外层对象时,才会做UI刷新。

const state = shallowReactive({
    msg: 'Hello.',
    info: {
        title: 'vue3'
    }
})
function reverseMsg () {
    // 因为是shallowReactive定义的,所以不能直接通过修改info面的title来刷新UI,必须得重新引用一个对象副本
    state.info = { title: state.info.title.split('').reverse().join('') }
    // reactive定义的对象副本,则可以通过这样修改值来刷新UI
    // state.info.title = state.info.title.split('').reverse().join('')
}
复制代码

shallowReadonly

标记自身的对象为可读,内部的对象则可以做修改,这是官方例子:

const state = shallowReadonly({
  foo: 1,
  nested: {
    bar: 2
  }
})

// 改变状态本身的property将失败
state.foo++
// ...但适用于嵌套对象
isReadonly(state.nested) // false
state.nested.bar++ // 适用
复制代码

ref

refreactive类似,但是它可以接收基本变量,并且使用的时候需要加上.value

const name = ref('lihua')
console.log(name.value)	// lihua
复制代码

ref定义的属性还有一个特点,就是在template里面使用的话,不需要加上.value,模板会自动解析出对应的value值。

toRef

可以将源对象的某个属性创建一个对应的响应式副本ref并返回回去:

const msg = toRef(state, 'msg')
msg.value = '.olleH'
console.log(state.msg)	// .olleH
复制代码

可以看到,创建的副本修改的值会影响到原来的reactive创建的对象,并且也会刷新UI。

toRefs

可以将源对象创建为一个普通对象,并且里面的属性都通过了ref的包装,来指向原对象。

const state = reactive({
    msg: 'Hello.',
    info: {
        title: 'vue3'
    }
})

const state = toRefs(state)
console.log(state)
复制代码

可以看到打印出:{msg: ObjectRefImpl, info: ObjectRefImpl}。这个API可以在解构等方面的时候起到非常有用的地方:

// 这种用法,在template的话需要通过state.msg来使用
return {
    state
}
// 这样使用扩展运算符的话,基本属性的修改会无效
return {
    ...state
}
// 通过toRefs来使用的话,因为基本属性也通过ref来包装了一层,所以可以直接使用msg
return {
    ...toRefs(state)
}
复制代码

在传递props的时候也非常有用:

// 某个子组件,接收了父组件传过来的title
const myTitle = props.title
watch(() => props.title, newVal => {
    console.log(newVal)
})
return {
    myTitle
}
复制代码

上述代码,父组件修改title时,子组件是会监听到title的变化的,但是myTitle不会改变,UI并不会刷新(可是我看文档上说的是,通过.的方式也是响应式的额,奇怪了!)。

改成使用toRefs的方式:

const { title: myTitle } = toRefs(props)
watch(() => props.title, newVal => {
    console.log(myTitle.value, newVal)
})
return {
    myTitle
}
复制代码

这样的话,当修改父组件的title时,子组件也会跟着刷新UI,但是使用的时候要记得加.value,模板上不加。

路由

在Vue3里面使用路由的话,需要安装最新版本的(4.x):

yarn add vue-router@next
npm isntall --save vue-router@next
复制代码

官方例子:

import { createRouter, createWebHashHistory } from 'vue-router'
import Home from '../views/Home.vue'

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  }
]

const router = createRouter({
  history: createWebHashHistory(),
  routes
})
复制代码

除了通过new改成了函数创建路由的方式,其他的配置还是没什么变化,如果要在setup里面使用路由对象的话,需要单独引入:

import { useRouter, useRoute } from 'vue-router'
setup () {
    const router = useRouter()
    const route = useRoute()
}
复制代码
// main.js
import router from '@/src/router/index'
...
app.use(router)
复制代码

其他用法可以参考官方的文档:导航守卫Vue Router 和 组合式 API

Vuex

和路由一样,Vuex需要安装最新版本的:

yarn add vuex@next
npm install --save vuex@next
复制代码

官方例子:

import { createStore } from 'vuex'

export default createStore({
  state: {
  },
  mutations: {
  },
  actions: {
  },
  modules: {
  }
})
复制代码
// main.js
import store from '@/src/store/index'
...
app.use(store)
复制代码

setup里面使用的话,也需要单独引入(我没找到其他方法o(╥﹏╥)o)。

Over,暂时就记录到这儿吧,有问题还请指正,Tanks.

文章分类
前端
文章标签