LiuJinTao:2024年4月10日
文章目录
- Vue3 框架
- 一、Vue3的优势
- 二、、Vue3 和 Vue2 的区别
- 三、创建 Vue3 项目 (create-vue)
- 四、setup原始写法
- 五、setup 语法糖
- 六、setup 小结
- 七、组合式 API - reactive 和 ref 函数
- 八、computed计算属性函数
- 九、 组合式 API - watch
- 十、watch - 参数
- 十一、watch - 精确监听
- 十二、 watch 总结
- 十三、组合式 API - 生命周期函数
- 十四、组合式 API- 组件通信
- 十五、组件通信总结
- 十六、模板引用
- 十七、组合式 API - provide 和 inject
- 十八、Vue3 新特性 defineOptions
- 十九、Vue3 新特性 - defindModel
- 二十、Pinia
- 二十一、Pinia 总结
Vue3 框架
一、Vue3的优势
二、、Vue3 和 Vue2 的区别
三、创建 Vue3 项目 (create-vue)
1. 改变创建项目的方式
2. 创建项目的前提条件
- 创建完毕后,运行项目后看到下图,那么恭喜你,成功创建了最新的Vue3项目
四、setup原始写法
1. 执行时机
2. 代码书写特点
- 这样书写代码每次都得return,太麻烦了,解决方案如下。
五、setup 语法糖
- 注意: 这里语法糖就是底层帮我们进行了return。
语法糖底层原理
六、setup 小结
七、组合式 API - reactive 和 ref 函数
1. reactive 函数
<script setup>
import { reactive } from 'vue'
const state = reactive({
count: 100
})
const HandleAddCount = () => {
state.count++
}
const HandleRemoveCount = () => {
state.count = 0
}
</script>
<template>
<div>
<div>{{ state.count }}</div>
<button @click="HandleAddCount">+1</button>
<button @click="HandleRemoveCount">重置</button>
</div>
</template>
<style scoped>
</style>
2. ref 函数
- 推荐使用 ref
ref()用法
在组合式 API 中,推荐使用 ref() 函数来声明响应式状态:
import { ref } from 'vue'
const count = ref(0)
ref() 接收参数,并将其包裹在一个带有 .value 属性的 ref 对象中返回:
const count = ref(0)
console.log(count) // { value: 0 }
console.log(count.value) // 0
count.value++
console.log(count.value) // 1
参考:为 refs 标注类型
要在组件模板中访问 ref,请从组件的 setup() 函数中声明并返回它们:
js
import { ref } from 'vue'
export default {
// `setup` 是一个特殊的钩子,专门用于组合式 API。
setup() {
const count = ref(0)
// 将 ref 暴露给模板
return {
count
}
}
}
<div>{{ count }}</div>
注意,在模板中使用 ref 时,我们不需要附加 .value。为了方便起见,当在模板中使用时,ref 会自动解包 (有一些注意事项)。
你也可以直接在事件监听器中改变一个 ref:
<button @click="count++">
{{ count }}
</button>
对于更复杂的逻辑,我们可以在同一作用域内声明更改 ref 的函数,并将它们作为方法与状态一起公开:
import { ref } from 'vue'
export default {
setup() {
const count = ref(0)
function increment() {
// 在 JavaScript 中需要 .value
count.value++
}
// 不要忘记同时暴露 increment 函数
return {
count,
increment
}
}
}
然后,暴露的方法可以被用作事件监听器:
<button @click="increment">
{{ count }}
</button>
这里是 Codepen 上的例子,没有使用任何构建工具。
3. 小结
八、computed计算属性函数
<script setup>
import { ref, computed } from 'vue'
const list = ref([1, 2, 3, 4, 5, 6, 7, 8, 9])
const computedList = computed(()=> {
return list.value.filter( item => item > 2 ) // item 表示每一个数组元素,然后通过回调函数return item > 2 的元素
})
</script>
九、 组合式 API - watch
1. 单个监视
<script setup>
import { ref, watch } from 'vue'
const count = ref(0)
const name = ref('zhangsan')
const changeCount = () => {
count.value++
}
const changeName = () => {
name.value = 'lisi'
}
// 监听单个数据 - > 语法: watch(ref对象, 回调函数)
watch(count, (newValue, oldValue) => {
console.log('newValue', newValue, 'oldValue', oldValue)
})
watch(name, (newValue, oldValue) => {
console.log('新名字', newValue, '旧名字', oldValue)
})
</script>
<template>
<div>
<div>{{ count }}</div>
<button @click="changeCount">修改 count </button>
<div>{{ name }}</div>
<button @click="changeName">修改 name</button>
</div>
</template>
2. 多个监视
<script setup>
import { ref, watch } from 'vue'
const count = ref(0)
const name = ref('zhangsan')
const changeCount = () => {
count.value++
}
const changeName = () => {
name.value = 'lisi'
}
// 监听单个数据 - > 语法: watch(ref对象, 回调函数)
watch(count, (newValue, oldValue) => {
console.log('newValue', newValue, 'oldValue', oldValue)
})
watch(name, (newValue, oldValue) => {
console.log('新名字', newValue, '旧名字', oldValue)
})
// 监听多个数据 - > 语法: watch([ref对象数据], 回调函数)
watch([count, name], (newValue, oldValue) => {
console.log('新值', newValue, '旧值', oldValue)
})
</script>
<template>
<div>
<div>{{ count }}</div>
<button @click="changeCount">修改 count </button>
<div>{{ name }}</div>
<button @click="changeName">修改 name</button>
</div>
</template>
十、watch - 参数
-
浅层监视
开启后,可以说是页面加载就进行监听了,然后后续在执行回调函数。 -
深层监视: 监视复杂数据类型的地址,表面的数据我们监视并不会触发
-
deep 深度监视, 由于 watch 默认是进行的 浅层监视,所以我们监视的复杂数据类型是无法进行对内容进行深度监视。所以我们这里就需要开启深度监视。
const info = ref({
name: '张三',
age: 23
}, {
deep: true // 开启深度监视
})
十一、watch - 精确监听
十二、 watch 总结
十三、组合式 API - 生命周期函数
<script setup>
import { onMounted } from 'vue';
// 生命周期函数
const getList = () => {
setTimeout(() => {
console.log('请求数据列表!')
}, 2000)
}
getList()
onMounted(() => {
console.log('onMounted生命周期函数执行逻辑 - 1')
})
onMounted(() => {
console.log('onMounted生命周期函数执行逻辑 - 2')
})
</script>
- 组合式API 中,还支持重复 调用生命周期函数。
十四、组合式 API- 组件通信
1. 父传子
2. 编译器宏defindProps 底层原理
3. 子传父
十五、组件通信总结
十六、模板引用
- 但需要注意的是,我们获取了组件对象,自然是需要拿到组件内部的属性数据的。但是需要注意的是,需要在组件中进行配置 编译宏 进行处理。避免引用失败。方法如下:
十七、组合式 API - provide 和 inject
1. 跨层传递 - 普通数据
2 跨层传递 - 响应式数据
3. 跨层传递 - 方法
- 因此就可以如下处理数据:
十八、Vue3 新特性 defineOptions
- 用法:
十九、Vue3 新特性 - defindModel
二十、Pinia
1. 什么是 Pinia
Pinia官网:Pinia
2. 手动添加 Pinia
安装
用你喜欢的包管理器安装 pinia:
yarn add pinia
或者使用 npm
npm install pinia
TIP
如果你的应用使用的 Vue 版本低于 2.7,你还需要安装组合式 API 包:@vue/composition-api。如果你使用的是 Nuxt,你应该参考这篇指南。
如果你正在使用 Vue CLI,你可以试试这个非官方插件。
创建一个 pinia 实例 (根 store) 并将其传递给应用:
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
app.mount('#app')
如果你使用的是 Vue 2,你还需要安装一个插件,并在应用的根部注入创建的 pinia:
import { createPinia, PiniaVuePlugin } from 'pinia'
Vue.use(PiniaVuePlugin)
const pinia = createPinia()
new Vue({
el: '#app',
// 其他配置...
// ...
// 请注意,同一个`pinia'实例
// 可以在同一个页面的多个 Vue 应用中使用。
pinia,
})
这样才能提供 devtools 的支持。在 Vue 3 中,一些功能仍然不被支持,如 time traveling 和编辑,这是因为 vue-devtools 还没有相关的 API,但 devtools 也有很多针对 Vue 3 的专属功能,而且就开发者的体验来说,Vue 3 整体上要好得多。在 Vue 2 中,Pinia 使用的是 Vuex 的现有接口 (因此不能与 Vuex 一起使用) 。
3. Pinia 的基本使用
1. 创建仓库store
// Pinia 仓库
/**
* 定义 store仓库语法:
* - defineStore(仓库的名称, () => {数据逻辑....})
*
*/
import { defineStore } from 'pinia'
import { ref, computed} from 'vue'
export const userCounterStore = defineStore('counter', () => {
// 声明仓库数据
const count = ref(100)
// 仓库处理函数actions(就相当于普通函数)
const handleAdd = () => count.value++
const handleSub = () => count.value--
// 计算属性
const number = computed(() => count.value * 2)
// 声明仓库数据
const message = ref('Pinia 仓库')
// return 仓库数据,外部调用
return {
count,
handleAdd,
handleSub,
number,
message,
}
})
2. 组件中使用
<script setup>
import Son1Com from "./components/Son1Com.vue";
import Son2Com from "./components/Son2Com.vue";
// 导入仓库暴露出来的对象引用
import { userCounterStore } from '@/store/counter'
const counterStore = userCounterStore()
// const count = ref(0)
</script>
<template>
<div>
<h3>我是 APP 根组件 - {{ counterStore.count }} </h3> <span>{{ counterStore.message }}</span>
<Son1Com></Son1Com>
<Son2Com></Son2Com>
</div>
</template>
<style scoped>
</style>
console.log('--------------------------------------')
<script setup>
// 导入仓库方法
import { userCounterStore } from '@/store/counter'
// 通过方法创建对象
const counterStore = userCounterStore()
</script>
<template>
<div>
<div>我是 Son1Com - {{ counterStore.count }} --- {{ counterStore.number }}</div>
<button @click="counterStore.handleAdd">+</button>
</div>
</template>
<style scoped>
</style>
console.log('--------------------------------------')
<script setup>
// 1. 导入仓库方法
import { userCounterStore } from '@/store/counter'
// 2. 使用方法创建对象
const counterStore = userCounterStore()
</script>
<template>
<div>我是 Son2Com - {{ counterStore.count }}</div>
<button @click="counterStore.handleSub">-</button>
</template>
<style scoped>
</style>
这样就能够实现数据同步共享了。
4. action 异步实现
- 在项目中安装一下 axios 库
yarn add axios
- 创建仓库进行代码编写
import { defineStore } from 'pinia'
import { ref } from 'vue'
import axios from 'axios'
export const useChannelStore = defineStore( 'channel', () => {
// 仓库数据
const channelList = ref([])
// action 操作数据的方法 (支持异步)
const getList = async () => {
const {data: { data }} = await axios.get('http://geek.itheima.net/v1_0/channels')
channelList.value = data.channels
console.log(data.channels)
}
// getters
return {
channelList,
getList
}
})
5. store 解构的响应式问题
- 我们通过实例调用数据也行。当我们数据太多了,就可以使用解构的方法进行处理数据。但是需要注意响应式的问题。(方法可以直接解构,因为我们只是调用方法,没有其他修改等操作)。
6. Pinia 持久化存储
【官网地址】: Pinia插件官网
快速开始
- 概述
本插件兼容 pinia^2.0.0,在使用之前请确保你已经 安装 Pinia。 pinia-plugin-persistedstate 丰富的功能可以使 Pinia Store 的持久化更易配置:
与 vuex-persistedstate 相似的 API
所有 Store 均可单独配置
自定义 storage 和数据序列化
恢复持久化数据前后的 hook
每个 Store 具有丰富的配置
兼容 Vue 2 和 3
无任何外部依赖
- 安装
包管理器安装依赖:
npm
npm i pinia-plugin-persistedstate
将插件添加到 pinia 实例上
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
用法
创建 Store 时,将 persist 选项设置为 true。
选项式语法
import { defineStore } from 'pinia'
export const useStore = defineStore('main', {
state: () => {
return {
someState: '你好 pinia',
}
},
persist: true,
})
组合式语法
import { defineStore } from 'pinia'
export const useStore = defineStore(
'main',
() => {
const someState = ref('你好 pinia')
return { someState }
},
{
persist: true,
},
)
现在,你的整个 Store 将使用默认持久化配置保存。
- 将上面创建的两个仓库进行持久化,我们本地就能进行存储数据了。
7. 配置 本地存储的 key 名字
配置
该插件的默认配置如下:
使用 localStorage 进行存储
store.$id 作为 storage 默认的 key
使用 JSON.stringify/JSON.parse 进行序列化/反序列化
整个 state 默认将被持久化
如何你不想使用默认的配置,那么你可以将一个对象传递给 Store 的 persist 属性来配置持久化。
import { defineStore } from 'pinia'
export const useStore = defineStore('main', {
state: () => ({
someState: '你好 pinia',
}),
persist: {
// 在这里进行自定义配置
},
})
key
类型:string
默认值:store.$id
Key 用于引用 storage 中的数据
例如
import { defineStore } from 'pinia'
export const useStore = defineStore('store', {
state: () => ({
someState: '你好 pinia',
}),
persist: {
key: 'my-custom-key',
},
})
这个 Store 将被持久化存储在 localStorage 中的 my-custom-key key 中。
8. 指定仓库中某些数据进行持久化
paths
类型:string[]
默认值:undefined
用于指定 state 中哪些数据需要被持久化。[] 表示不持久化任何状态,undefined 或 null 表示持久化整个 state。
例如
import { defineStore } from 'pinia'
export const useStore = defineStore('store', {
state: () => ({
save: {
me: 'saved',
notMe: 'not-saved',
},
saveMeToo: 'saved',
}),
persist: {
paths: ['save.me', 'saveMeToo'],
},
})
该 store 中, 只有 save.me 和 saveMeToo 被持久化,而 save.notMe 不会被持久化。
- Pinia 的使用:总而言之,参考官网文档进行使用配置即可。