组合式API,更好的TypeScript支持
1. 重写diff算法;2. 模板编译优化;3. 更高效的组件初始化
1. 良好的TreeShaking;2. 按需引入
Proxy
Vue2选项式API
整个配置项中,有着一个一个的选项,data是一个选项,methods是一个选项,computed是一个选项等等。如果我们要实现一个功能,需要分散式的将代码散落到各个配置项当中。例如我们实现一个功能A,我们需要在data里面提供功能A的数据,在methods里面写功能A相关的方法,再加个计算属性computed。当要实现的功能越来越多,写的代码越来越多的时候,它们之间的互相对应就会使得将来项目非常难以维护。
选项式API(Options API)
export default {
data() {
return {
功能A
功能B
}
},
methods: {
功能A
功能B
},
computed: {
功能A
},
watch: {
功能B
}
}
Vue3组合式API
直接将同功能相关的所有内容进行集中式的管理
组合式API(Composition API)
功能A相关的数据的声明
功能A相关的方法的提供
功能A相关的计算属性
功能B相关的数据的声明
功能B相关的方法的提供
功能B相关的计算属性
举例:需求:点击按钮,让数字+1
// vue2中的写法
// vue3中的写法
create-vue是Vue官方新的脚手架工具,底层切换到了vite(下一代构建工具),为开发提供极速响应。
以前用Vue-cli创建项目,它的底层是webpack。
现在用create-vue创建项目,它的底层是vite。
1. 前提环境
已安装16.0或更高版本的Node.js
node -v
2. 创建一个Vue应用
npm init vue@latest
这一指令将会安装并执行create-vue
关键文件:
1. vite.config.js -项目的配置文件 基于vite的配置
2. package.json-项目包文件 核心依赖变成了3.x和vite
3. main.js-入口文件createApp函数创建应用实例
3. app.vue-根组件
变化一:脚本script和模板template顺序调整
变化二:模板template不再要求唯一根元素
变化三:脚本script添加setup标识支持组合式API
5. index.html-单页入口,提供id为app的挂载点
main.js文件
//1. 从vue中按需导入createApp函数
// createApp函数的作用:创建vue的“单页面应用程序实例”
import { createApp } from ‘vue’
//2. 导入待渲染的App组件
import App from ‘./App.vue’
//3. 调用createApp()函数,返回值是“单页面应用程序的实例”,用常量spa_app接收
//同时把App组件作为参数传给createApp函数,表示把App渲染到index.htnl页面上
const spa_app = createApp(App)
//4. 调用spa_app实例的mount方法,用来指定vue实际要控制的区域
spa_app.mount(‘#app’)
1. setup的执行时机,比beforeCreate还要早
2. 也正是因为执行时机太早,setup函数中拿不到this(this是undefined)
setup选项中写代码的特点 :提供的任何数据或函数,想要在模板中应用,必须return
{{ message }}
如果每次都要return,会很麻烦,所以提供了
setup语法糖原理
六. reactive和ref函数
reactive()
接受对象类型数据的参数传入并返回一个响应式的对象
// 举例
{{ state.count }}ref()
接收简单类型或者对象类型的数据传入并返回一个响应式的对象
ref()它其实是在原有传入数据的基础上,外层包了一层对象,包成了复杂类型,底层包成复杂类型之后,再借助reactive实现的响应式。
在脚本中通过.value访问数据
在template中不需要加.value就可以访问数据
// 在template中,.value不需要加(帮我们扒了一层)
{{ count }}对数据进行加一操作
{{ count }}七. computed
计算属性基本思想和Vue2的完全一致,组合式API下的计算属性只是修改了写法
原始数据:{{ list }}计算后的数据:{{ computedList }}当修改数据时,计算属性动态更新
原始数据:{{ list }}计算后的数据:{{ computedList }}注意:
1. 计算属性当中不应该有副作用:计算属性它整个函数当中应该只包含关于数据的计算过程,不应该包括其他的,比如异步请求,比如操作dom等等
2. 避免直接修改计算属性的值
八. watch
侦听一个或者多个数据的变化,数据变化时执行回调函数
监听单个数据的变化
监听多个数据的变化
举个例子:同时监听count和nickname的变化
{{ count }}{{ nickname }}额外参数1:immediate(立即执行)
在侦听器创建时立即触发回调,响应式数据变化之后继续执行回调
const count = ref(0) watch(count,()=>{ console.log('count发生了变化') },{ immediate: true })
额外参数2:deep(深度监听),默认watch进行的是浅层监视
const ref1 = ref(简单类型)→可以直接监视
const ref2 = ref(复杂类型)→监视不到复杂类型内部数据的变化
{{ userInfo }}精确监听对象的某个属性
// 需求:在不开启deep的前提下,监听age的变化,只有age变化时,才执行回调 const info = ref({ name: 'cp', age: 18 }) // 第一个参数写成函数的写法,返回要监听的具体属性 watch( () => info.value.age, (newVal, oldVal) => console.log('age发送变化了') )
九. Vue3的生命周期API
选项式API 组合式API beforeCreate/created setup beforeMount onBeforeMount mounted onMounted beforeUpdate onBeforeUnmount updated onUpdated beforeUnmount onBeforeUnmount unmounted onUnmounted 以前往created里面写的,现在都写到setup里面
vue3中销毁阶段就不叫destoryed了,就叫onUnmounted了
十. 父子通信
组合式API下的父传子
基本思想:父组件中给子组件绑定属性,子组件内部通过props选项接收
对于局部组件,导入进来就能用
// 父组件
// 子组件 {{ message }} defineProps原理:就是编译阶段的一个标识,实际编译器解析时,遇到后会进行编译转换
组合式API下的子传父
基本思想:父组件中,给子组件标签通过@绑定事件,子组件内部通过emit方法触发事件。
// 父组件
//子组件 十一. 模板引用
通过ref标识获取真实的dom对象或者组件实例对象
模板引用的时机是组件挂载完毕
如何使用:以获取dom为例
我是dom标签h1
例如点击按钮让光标聚焦
defineExpose()
默认情况下,
十二. provide和inject
顶层组件向任意的底层组件传递数据和方法,实现跨层级组件通信
1. 顶层组件通过provide函数提供数据
provide('key', 顶层组件中的数据)
2. 底层组件通过inject函数获取数据
const message = inject('key')
跨层传递响应式数据
// 顶层组件 provide('app-key', ref对象) // 底层组件 const message = inject('app-key')
跨层传递方法
顶层组件可以向底层组件传递方法,底层组件调用方法修改顶层组件中的数据
// 顶层组件 const setCount = () =>{ count.value++ } provide('setCount-key', setCount) // 底层组件 const setCount = inject('setCount-key')
十三. Vue3.3新特性defineOptions
defineOptions宏,主要用来定义Options API的选项。
可以用defineOptions定义任意的选项,props,emits,expose,slots除外,因为这些可以用defineXXX来做到。
十四. Vue3中的v-model和defineModel
在Vue3中,自定义组件上使用v-model,相当于传递一个modalValue属性,同时触发update:modelValue事件.
// 相当于 // 父组件
// 子组件 emit('update:modelValue',e.target.value)">defineModal(试验性质的特性)
// 使用defineModal需要在vite.config.js中配置 plugins:[ vue({ script:{ defineModal: true } }), ] // 开完记得重启项目
十五. Pinia
Pinia是Vue的最新状态管理工具,是Vuex的替代品
1. 提供更简单的API(去掉了mutation)
2. 提供符合,组合式的API(和Vue3新语法统一)
3. 去掉了modules的概念,每一个store都是一个独立的模块
4. 配合TypeScript更加友好,提供可靠的类型推断
手动添加Pinia到Vue项目
// 1. 使用Vite创建一个空的Vue3项目 npm create vue@latest // 2. 按照官方文档安装pinia到项目中
import { createApp } from 'vue' import {createPinia} from 'pinia' import App from './App.vue' // 创建pinia实例 const pinia = createPinia() // 可以这样写 // createApp(App).use(pinia).mount('#app') // 也可以这样写 const app = createApp(App) app.use(pinia).mount('#app')
Pinia基础使用-计数器案例
1. 定义store
2. 组件使用store
// 这里是store文件夹下的counter.js import { defineStore } from 'pinia' import { computed, ref } from 'vue' // 定义store defineStore(仓库的唯一标识,()=>{...}) export const useCounterStore=defineStore('counter', () => { // 声明数据 state-count const count =ref(0) // 声明操作数据的方法 action const addCount = () => count.value++ const subCount=()=>count.value-- //声明基于数据派生的计算属性getters const double=computed(()=>count.value*2) // 声明数据state-msg const msg = ref('hello pinia') return { count, addCount, subCount, double, msg } }) // 这里是components文件夹下的Son1Com.vue组件
我是Son1.vue-0-{{ counterStore.count }}-{{ counterStore.double }}Pinia-action异步实现
// 这里是store文件夹下的channel.js import { defineStore } from 'pinia' import { ref } from 'vue' import axios from 'axios' export const useChannelStore = defineStore('channel', () => { // 声明数据state const channerList = ref([]) // 声明操作数据的方法action const getList = async () => { const {data:{data}} = await axios.get('http://geek.itheima.net/v1_0/channels') channerList.value=data.channels } //声明基于数据派生的计算数据getters return { channerList, getList } })
Pinia-storeToRefs方法
import { storeToRefs } from 'pinia' // 使用storeToRefs()为每一个响应式属性创建引用 const { count , msg } = storeToRefs(counterStore) const { channelList } = storeToRefs(channelStore) // action可以直接解构 const { getList } = channelStore
Pinia持久化插件
// 使用前确保自己已经安装了Pinia // 1. 安装插件 npm i pinia-plugin-persistedstate // 2. main.js使用 import persist from 'pinia-plugin-persistedstate' ... app.use(createPinia().use(persist)) // 3. store仓库中,开启 // 在第三个参数里面加上 (第一个参数是唯一标识,第二个参数是里面的核心逻辑) persist: true // 可以自己配key persist:{ key:'xiaoxiong-counter' } // 可以自己配存储 persist:{ storage: sessionstorage } // 用path 指定哪些state中的哪些数据持久化 persist :{ paths:['count'] }
十六. 路由语法的不同
vue-Router3路由的初始化
import VueRouter from 'vue-router' // 初始化vue-router3.x(Vue2) const router = new VueRouter({ mode:'history', routes: [], }) export default router
vue-Router4路由的初始化
import { createRouter, createWebHistory } from 'vue-router' // 初始化 vue-router4.x(Vue3) const router = createRouter({ // 1. history模式:createWebHistory 地址栏不带# // 2. hash模式:createWebHashHistory 地址栏带# history: createWebHistory(import.meta.env.BASE_URL), routes: [] }) export default router
在Vue3的CompositionAPI中
1. 获取路由对象router useRouter
const router = useRouter()
2. 获取路由参数route useRoute
const route = useRoute()
我是App