vue3前置

🐵Vue3基础 - 图1

为什么学vue3

目标:了解vue3现状,以及它的优点,展望它的未来

  1. Vue3现状:
  • vue-next 2020年09月18日,正式发布vue3.0版本。但由于刚发布周边生态不支持,大多数开发者处于观望。
  • 现在主流组件库都已经发布了支持vue3.0的版本,其他生态也在不断地完善中,这是趋势。
    • element-plus 基于 Vue 3.0 的桌面端组件库
    • vant vant3.0版本,有赞前端团队开源移动端组件库
    • ant-design-vue Ant Design Vue 2.0版本,社区根据蚂蚁 ant design 开发
  1. Vue3优点:
  • 最火框架,它是国内最火的前端框架之一,官方文档 中文文档
  • 性能提升,运行速度事vue2.x的1.5倍左右
  • 体积更小,按需编译体积比vue2.x要更小
  • 类型推断,更好的支持Ts(typescript)这个也是趋势
  • 高级给予,暴露了更底层的API和提供更先进的内置组件
  • ★组合API (composition api) ,能够更好的组织逻辑,封装逻辑,复用逻辑
  1. Vue3展望:
  • 这是趋势,越来越多的企业将来肯定会升级到Vue3.0
  • 大型项目,由于对Ts的友好越来越多大型项目可以用Vue3.0

总结: 为什么要学 vue3 ? 适应市场学习流行的技术提高提升自己竞争力,给自己加薪。

创建vue应用

目标:掌握如何创建vue3应用实例

🐵Vue3基础 - 图2

  1. 基于Vue脚手架创建项目
  2. 项目代码结构分析

落地代码:

  • 跟组件App.vue
  1. <template>
  2. <div class="container">
  3. 我是根组件
  4. </div>
  5. </template>
  6. <script>
  7. export default {
  8. name: 'App'
  9. }
  10. </script>
  • 入口文件main.js
  1. // 创建一个vue应用
  2. // 1. 导入createApp函数
  3. // 2. 编写一个根组件App.vue,导入进来
  4. // 3. 基于根组件创建应用实例
  5. // 4. 挂载到index.html的#app容器
  6. import {createApp} from 'vue'
  7. import App from './App.vue'
  8. const app = createApp(App)
  9. app.mount('#app')

总结: 如何创建vue应用实例? 通过createApp创建应用实例—->扩展功能将来都是在app上进行。

选项API和组合API

目标:理解什么是选项API写法,什么是组合API写法。

  • 选项API与组合API对比分析

image-20210716210942387.png

什么是选项API写法:Options ApI

  • 咱们在vue2.x项目中使用的就是 选项API 写法
    • 代码风格:data选项写数据,methods选项写函数…,一个功能逻辑的代码分散。
    • 优点:易于学习和使用,写代码的位置已经约定好
    • 缺点:代码组织性差,相似的逻辑代码不便于复用,逻辑复杂代码多了不好阅读。

总结: 知道选项API和组合API的写法区别,建议大家使用组合API在vue3.0项目中。

组合API-setup函数

目标:掌握setup函数的基本使用

使用细节:

  • setup 是一个新的组件选项,作为组件中使用组合API的起点。
  • 从组件生命周期来看,它的执行在组件实例创建之前vue2.x的beforeCreate执行。
  • 这就意味着在setup函数中 this 还不是组件实例,this 此时是 undefined
  • 在模版中需要使用的数据和函数,需要在 setup 返回。

演示代码:

  1. <template>
  2. <div class="container">
  3. <h1 @click="say()">{{msg}}</h1>
  4. </div>
  5. </template>
  6. <script>
  7. export default {
  8. setup () {
  9. console.log('setup执行了')
  10. console.log(this)
  11. // 定义数据和函数
  12. const msg = 'hi vue3'
  13. const say = () => {
  14. console.log(msg)
  15. }
  16. return { msg , say}
  17. },
  18. beforeCreate() {
  19. console.log('beforeCreate执行了')
  20. console.log(this)
  21. }
  22. }
  23. </script>

总结: setup 组件初始化之前执行,它返回的数据和函数可在模版使用。

组合API-生命周期

目标:掌握使用组合API写法的生命周期钩子函数

  1. 回顾vue2.x生命周期钩子函数:
  • beforeCreate
  • created
  • beforeMount
  • mounted
  • beforeUpdate
  • updated
  • beforeDestroy
  • destroyed
  1. 认识vue3.0生命周期钩子函数
  • setup 创建实例前
  • onBeforeMount 挂载DOM前
  • onMounted 挂载DOM后
  • onBeforeUpdate 更新组件前
  • onUpdated 更新组件后
  • onBeforeUnmount 卸载销毁前
  • onUnmounted 卸载销毁后

演示代码:

  1. <template>
  2. <div class="container">
  3. container
  4. </div>
  5. </template>
  6. <script>
  7. import { onBeforeMount, onMounted } from 'vue'
  8. export default {
  9. setup () {
  10. onBeforeMount(()=>{
  11. console.log('DOM渲染前',document.querySelector('.container'))
  12. })
  13. onMounted(()=>{
  14. console.log('DOM渲染后1',document.querySelector('.container'))
  15. })
  16. onMounted(()=>{
  17. console.log('DOM渲染后2',document.querySelector('.container'))
  18. })
  19. },
  20. }
  21. </script>

总结: 组合API的生命周期钩子有7个,可以多次使用同一个钩子,执行顺序和书写顺序相同。

组合API-reactive函数

目标:掌握使用reactive函数定义响应式数据

  • reactive是一个函数,它可以定义一个复杂数据类型,成为响应式数据。

演示代码:

  1. <template>
  2. <div class="container">
  3. <div>{{obj.name}}</div>
  4. <div>{{obj.age}}</div>
  5. <button @click="updateName">修改数据</button>
  6. </div>
  7. </template>
  8. <script>
  9. import { reactive } from 'vue'
  10. export default {
  11. name: 'App',
  12. setup () {
  13. // 普通数据
  14. // const obj = {
  15. // name: 'ls',
  16. // age: 18
  17. // }
  18. const obj = reactive({
  19. name: 'ls',
  20. age: 18
  21. })
  22. // 修改名字
  23. const updateName = () => {
  24. console.log('updateName')
  25. obj.name = 'zs'
  26. }
  27. return { obj ,updateName}
  28. }
  29. }
  30. </script>

总结: 通常是用来定义响应式对象数据

组合API-toRef函数

目标:掌握使用toRef函数转换响应式对象中某个属性为单独响应式数据,并且值是关联的。

定义响应式数据:

  • toRef是函数,转换响应式对象某个属性为单独响应式数据,并且值是关联的

演示代码:

  1. <template>
  2. <div class="container">
  3. {{name}} <button @click="updateName">修改数据</button>
  4. </div>
  5. </template>
  6. <script>
  7. import { reactive, toRef } from 'vue'
  8. export default {
  9. name: 'App',
  10. setup () {
  11. // 1. 响应式数据对象
  12. const obj = reactive({
  13. name: 'ls',
  14. age: 10
  15. })
  16. console.log(obj)
  17. // 2. 模板中只需要使用name数据
  18. // 注意:从响应式数据对象中解构出的属性数据,不再是响应式数据
  19. // let { name } = obj 不能直接解构,出来的是一个普通数据
  20. const name = toRef(obj, 'name')
  21. // console.log(name)
  22. const updateName = () => {
  23. console.log('updateName')
  24. // toRef转换响应式数据包装成对象,value存放值的位置
  25. name.value = 'zs'
  26. }
  27. return {name, updateName}
  28. }
  29. }
  30. </script>
  31. <style scoped lang="less"></style>

使用场景:有一个响应式对象数据,但是模版中只需要使用其中一项数据。

组合API-toRefs函数

目标:掌握使用toRefs函数定义转换响应式中所有属性为响应式数据,通常用于解构|展开reactive定义对象。

  • toRefs是函数,转换响应式对象中所有属性为单独响应式数据,对象成为普通对象,并且值是关联的

演示代码:

  1. <template>
  2. <div class="container">
  3. <div>{{name}}</div>
  4. <div>{{age}}</div>
  5. <button @click="updateName">修改数据</button>
  6. </div>
  7. </template>
  8. <script>
  9. import { reactive, toRef, toRefs } from 'vue'
  10. export default {
  11. name: 'App',
  12. setup () {
  13. // 1. 响应式数据对象
  14. const obj = reactive({
  15. name: 'ls',
  16. age: 10
  17. })
  18. console.log(obj)
  19. // 2. 解构或者展开响应式数据对象
  20. // const {name,age} = obj
  21. // console.log(name,age)
  22. // const obj2 = {...obj}
  23. // console.log(obj2)
  24. // 以上方式导致数据就不是响应式数据了
  25. const obj3 = toRefs(obj)
  26. console.log(obj3)
  27. const updateName = () => {
  28. // obj3.name.value = 'zs'
  29. obj.name = 'zs'
  30. }
  31. return {...obj3, updateName}
  32. }
  33. }
  34. </script>
  35. <style scoped lang="less"></style>

使用场景:剥离响应式对象(解构|展开),想使用响应式对象中的多个或者所有属性做为响应式数据。

组合API-ref函数

目标:掌握使用ref函数定义响应式数据,一般用于简单类型数据

  • ref函数,常用于简单数据类型定义为响应式数据
    • 再修改值,获取值的时候,需要.value
    • 在模板中使用ref申明的响应式数据,可以省略.value

演示代码:

  1. <template>
  2. <div class="container">
  3. <div>{{name}}</div>
  4. <div>{{age}}</div>
  5. <button @click="updateName">修改数据</button>
  6. </div>
  7. </template>
  8. <script>
  9. import { ref } from 'vue'
  10. export default {
  11. name: 'App',
  12. setup () {
  13. // 1. name数据
  14. const name = ref('ls')
  15. console.log(name)
  16. const updateName = () => {
  17. name.value = 'zs'
  18. }
  19. // 2. age数据
  20. const age = ref(10)
  21. // ref常用定义简单数据类型的响应式数据
  22. // 其实也可以定义复杂数据类型的响应式数据
  23. // 对于数据未之的情况下 ref 是最适用的
  24. // const data = ref(null)
  25. // setTimeout(()=>{
  26. // data.value = res.data
  27. // },1000)
  28. return {name, age, updateName}
  29. }
  30. }
  31. </script>

总结

  1. 当你明确知道需要的是一个响应式数据 对象 那么就使用 reactive 即可
  2. 其他情况使用ref

知识运用案例

目标:利用所学知识完成组合API实例

基本步骤:

  • 记录鼠标坐标
    • 定义一个响应式数据对象,包含x和y属性。
    • 在组件渲染完毕后,监听document的鼠标移动事件
    • 指定move函数为事件对应方法,在函数中修改坐标
    • 在setup返回数据,模版中使用
  • 累加1功能
    • 定义一个简单数据类型的响应式数据
    • 定义一个修改数字的方法
    • 在setup返回数据和函数,模板中使用

落的代码:

  1. <template>
  2. <div class="container">
  3. <div>坐标</div>
  4. <div>x: {{x}}</div>
  5. <div>y: {{y}}</div>
  6. <hr>
  7. <div>{{count}} <button @click="add">累加1</button></div>
  8. </div>
  9. </template>
  10. <script>
  11. import { onMounted, onUnmounted, reactive , ref, toRefs} from 'vue'
  12. const useMouse = () => {
  13. // 1. 记录鼠标坐标
  14. // 1.1 申明一个响应式数据,他是一个对象,包含x y
  15. const mouse = reactive({
  16. x: 0,
  17. y: 0
  18. })
  19. // 1.3 修改响应式数据
  20. const move = (e) => {
  21. mouse.x = e.pageX
  22. mouse.y = e.pageY
  23. }
  24. // 1.2 等dom渲染完毕。去监听事件
  25. onMounted(()=>{
  26. document.addEventListener('mousemove', move)
  27. })
  28. // 1.4 组件消耗,删除事件
  29. onUnmounted(()=>{
  30. document.removeEventListener('mousemove', move)
  31. })
  32. return mouse
  33. }
  34. export default {
  35. name: 'App',
  36. setup () {
  37. const mouse = useMouse()
  38. // 2. 数字累加
  39. const count = ref(0)
  40. const add = () => {
  41. count.value ++
  42. }
  43. return { ...toRefs(mouse), count, add }
  44. }
  45. }
  46. </script>
  47. <style scoped lang="less"></style>

总结: 体会组合API的写法,尝试组织可读性高的代码。

组合API-computed函数

目标:掌握使用computed函数定义计算属性

  • computed函数,是用来定义计算属性的,计算属性不能修改。

基本使用:

  1. <template>
  2. <div class="container">
  3. <div>今年:{{age}}岁</div>
  4. <div>后年:{{newAge}}岁</div>
  5. </div>
  6. </template>
  7. <script>
  8. import { computed, ref } from 'vue'
  9. export default {
  10. name: 'App',
  11. setup () {
  12. // 1. 计算属性:当你需要依赖现有的响应式数据,根据一定逻辑得到一个新的数据。
  13. const age = ref(16)
  14. // 得到后年的年龄
  15. const newAge = computed(()=>{
  16. // 该函数的返回值就是计算属性的值
  17. return age.value + 2
  18. })
  19. return {age, newAge}
  20. }
  21. }
  22. </script>

高级用法:

  1. <template>
  2. <div class="container">
  3. <div>今年:{{age}}岁</div>
  4. <div>后年:{{newAge}}岁</div>
  5. <!-- 使用v-model绑定计算属性 -->
  6. <input type="text" v-model="newAge">
  7. </div>
  8. </template>
  9. <script>
  10. import { computed, ref } from 'vue'
  11. export default {
  12. name: 'App',
  13. setup () {
  14. // 1. 计算属性:当你需要依赖现有的响应式数据,根据一定逻辑得到一个新的数据。
  15. const age = ref(16)
  16. // 得到后年的年龄
  17. // const newAge = computed(()=>{
  18. // // 该函数的返回值就是计算属性的值
  19. // return age.value + 2
  20. // })
  21. // 计算属性高级用法,传人对象
  22. const newAge = computed({
  23. // get函数,获取计算属性的值
  24. get(){
  25. return age.value + 2
  26. },
  27. // set函数,当你给计算属性设置值的时候触发
  28. set (value) {
  29. age.value = value - 2
  30. }
  31. })
  32. return {age, newAge}
  33. }
  34. }
  35. </script>

目的:让计算属性支持双向数据绑定。

总结:计算属性两种用法

  • 给computed传入函数,返回值就是计算属性的值
  • 给computed传入对象,get获取计算属性的值,set监听计算属性改变。

组合API-watch函数

目标:掌握使用watch函数定义侦听器

定义计算属性:

  • watch函数,是用来定义侦听器的

监听ref定义的响应式数据

监听多个响应式数据数据

监听reactive定义的响应式数据

监听reactive定义的响应式数据,某一个属性

深度监听

默认执行

  1. <template>
  2. <div class="container">
  3. <div>
  4. <p>count的值:{{count}}</p>
  5. <button @click="add">改数据</button>
  6. </div>
  7. <hr>
  8. <div>
  9. <p>{{obj.name}}</p>
  10. <p>{{obj.age}}</p>
  11. <p>{{obj.brand.name}}</p>
  12. <button @click="updateName">改名字</button>
  13. <button @click="updateBrandName">改品牌名字</button>
  14. </div>
  15. </div>
  16. </template>
  17. <script>
  18. import { reactive, ref, watch } from 'vue'
  19. export default {
  20. name: 'App',
  21. setup () {
  22. const count = ref(0)
  23. const add = () => {
  24. count.value++
  25. }
  26. // 当你需要监听数据的变化就可以使用watch
  27. // 1. 监听一个ref数据
  28. // 1.1 第一个参数 需要监听的目标
  29. // 1.2 第二个参数 改变后触发的函数
  30. // watch(count, (newVal,oldVal)=>{
  31. // console.log(newVal,oldVal)
  32. // })
  33. const obj = reactive({
  34. name: 'ls',
  35. age: 10,
  36. brand: {
  37. id: 1,
  38. name: '宝马'
  39. }
  40. })
  41. const updateName = () => {
  42. obj.name = 'zs'
  43. }
  44. const updateBrandName = () => {
  45. obj.brand.name = '奔驰'
  46. }
  47. // 2. 监听一个reactive数据
  48. watch(obj, ()=>{
  49. console.log('数据改变了')
  50. })
  51. watch(()=>obj.brand, ()=>{
  52. console.log('brand数据改变了')
  53. },{
  54. // 5. 需要深度监听
  55. deep: true,
  56. // 6. 想默认触发
  57. immediate: true
  58. })
  59. // 3. 监听多个数据的变化
  60. // watch([count, obj], ()=>{
  61. // console.log('监听多个数据改变了')
  62. // })
  63. // 4. 此时监听对象中某一个属性的变化 例如:obj.name
  64. // 需要写成函数返回该属性的方式才能监听到
  65. // watch(()=>obj.name,()=>{
  66. // console.log('监听obj.name改变了')
  67. // })
  68. return {count, add, obj, updateName, updateBrandName}
  69. }
  70. }
  71. </script>

总结: 掌握watch的各种用法。

组合API-ref属性

目标:掌握使用ref属性绑定DOM或组件

获取DOM或者组件实例可以使用ref属性,写法和vue2.0需要区分开

获取单个DOM或者组件

  1. <template>
  2. <div class="container">
  3. <!-- vue2.0 获取单个元素 -->
  4. <!-- 1. 通过ref属性绑定该元素 -->
  5. <!-- 2. 通过this.$refs.box获取元素 -->
  6. <!-- <div ref="box">我是box</div> -->
  7. <!-- vue2.0 获取v-for遍历的多个元素 -->
  8. <!-- 1. 通过ref属性绑定被遍历元素 -->
  9. <!-- 2. 通过this.$refs.li 获取所有遍历元素 -->
  10. <!-- <ul>
  11. <li v-for="i in 4" :key="i" ref="li">{{i}}</li>
  12. </ul> -->
  13. <!-- 单个元素 -->
  14. <div ref="dom">我是box</div>
  15. <!-- 被遍历的元素 -->
  16. <ul>
  17. <li v-for="i in 4" :key="i" :ref="setDom">第{{i}}LI</li>
  18. </ul>
  19. </div>
  20. </template>
  21. <script>
  22. import { onMounted, ref } from 'vue'
  23. export default {
  24. name: 'App',
  25. setup () {
  26. // 1. 获取单个元素
  27. // 1.1 先定义一个空的响应式数据ref定义的
  28. // 1.2 setup中返回该数据,你想获取那个dom元素,在该元素上使用ref属性绑定该数据即可。
  29. const dom = ref(null)
  30. onMounted(()=>{
  31. console.log(dom.value)
  32. })
  33. }
  34. }
  35. </script>
  36. <style scoped lang="less"></style>

获取v-for遍历的DOM或者组件

  1. // 2. 获取v-for遍历的元素
  2. // 2.1 定义一个空数组,接收所有的LI
  3. // 2.2 定义一个函数,往空数组push DOM
  4. const domList = []
  5. const setDom = (el) => {
  6. domList.push(el)
  7. }
  8. onMounted(()=>{
  9. console.log(domList)
  10. })
  11. return {dom, setDom}

总结:

  1. 单个元素:先申明ref响应式数据,返回给模版使用,通过ref绑定数据
  2. 遍历的元素:先定义一个空数组,定一个函数获取元素,返回给模版使用,通过ref绑定这个函数

组合API-父子通讯

目标:掌握使用props选项和emits选项完成父子组件通讯

父传子:

  1. <template>
  2. <div class="container">
  3. <h1>父组件</h1>
  4. <p>{{money}}</p>
  5. <hr>
  6. <Son :money="money" />
  7. </div>
  8. </template>
  9. <script>
  10. import { ref } from 'vue'
  11. import Son from './Son.vue'
  12. export default {
  13. name: 'App',
  14. components: {
  15. Son
  16. },
  17. // 父组件的数据传递给子组件
  18. setup () {
  19. const money = ref(100)
  20. return { money }
  21. }
  22. }
  23. </script>
  1. <template>
  2. <div class="container">
  3. <h1>子组件</h1>
  4. <p>{{money}}</p>
  5. </div>
  6. </template>
  7. <script>
  8. import { onMounted } from 'vue'
  9. export default {
  10. name: 'Son',
  11. // 子组件接收父组件数据使用props即可
  12. props: {
  13. money: {
  14. type: Number,
  15. default: 0
  16. }
  17. },
  18. setup (props) {
  19. // 获取父组件数据money
  20. console.log(props.money)
  21. }
  22. }
  23. </script>

子传父:

  1. <template>
  2. <div class="container">
  3. <h1>父组件</h1>
  4. <p>{{money}}</p>
  5. <hr>
  6. + <Son :money="money" @change-money="updateMoney" />
  7. </div>
  8. </template>
  9. <script>
  10. import { ref } from 'vue'
  11. import Son from './Son.vue'
  12. export default {
  13. name: 'App',
  14. components: {
  15. Son
  16. },
  17. // 父组件的数据传递给子组件
  18. setup () {
  19. const money = ref(100)
  20. + const updateMoney = (newMoney) => {
  21. + money.value = newMoney
  22. + }
  23. + return { money , updateMoney}
  24. }
  25. }
  26. </script>
  1. <template>
  2. <div class="container">
  3. <h1>子组件</h1>
  4. <p>{{money}}</p>
  5. + <button @click="changeMoney">花50元</button>
  6. </div>
  7. </template>
  8. <script>
  9. import { onMounted } from 'vue'
  10. export default {
  11. name: 'Son',
  12. // 子组件接收父组件数据使用props即可
  13. props: {
  14. money: {
  15. type: Number,
  16. default: 0
  17. }
  18. },
  19. // props 父组件数据
  20. // emit 触发自定义事件的函数
  21. + setup (props, {emit}) {
  22. // 获取父组件数据money
  23. console.log(props.money)
  24. // 向父组件传值
  25. + const changeMoney = () => {
  26. // 消费50元
  27. // 通知父组件,money需要变成50
  28. + emit('change-money', 50)
  29. + }
  30. + return {changeMoney}
  31. }
  32. }
  33. </script>

扩展:

  • 在vue2.x的时候 .sync 除去v-model实现双向数据绑定的另一种方式
  1. <!-- <Son :money='money' @update:money="fn" /> -->
  2. <Son :money.sync='money' />
  • 在vue3.0的时候,使用 v-model:money="money" 即可
  1. <!-- <Son :money="money" @update:money="updateMoney" /> -->
  2. <Son v-model:money="money" />

总结:

  • 父传子:在setup种使用props数据 setup(props){ // props就是父组件数据 }
  • 子传父:触发自定义事件的时候emit来自 setup(props,{emit}){ // emit 就是触发事件函数 }
  • 在vue3.0中 v-model.sync 已经合并成 v-model 指令

组合API-依赖注入

目标:掌握使用provide函数和inject函数完成后代组件数据通讯

使用场景:有一个父组件,里头有子组件,有孙组件,有很多后代组件,共享父组件数据。

演示代码:

  1. <template>
  2. <div class="container">
  3. <h1>父组件 {{money}} <button @click="money=1000">发钱</button></h1>
  4. <hr>
  5. <Son />
  6. </div>
  7. </template>
  8. <script>
  9. import { provide, ref } from 'vue'
  10. import Son from './Son.vue'
  11. export default {
  12. name: 'App',
  13. components: {
  14. Son
  15. },
  16. setup () {
  17. const money = ref(100)
  18. const changeMoney = (saleMoney) => {
  19. console.log('changeMoney',saleMoney)
  20. money.value = money.value - saleMoney
  21. }
  22. // 将数据提供给后代组件 provide
  23. provide('money', money)
  24. // 将函数提供给后代组件 provide
  25. provide('changeMoney', changeMoney)
  26. return { money }
  27. }
  28. }
  29. </script>
  30. <style scoped lang="less"></style>
  1. <template>
  2. <div class="container">
  3. <h2>子组件 {{money}}</h2>
  4. <hr>
  5. <GrandSon />
  6. </div>
  7. </template>
  8. <script>
  9. import { inject } from 'vue'
  10. import GrandSon from './GrandSon.vue'
  11. export default {
  12. name: 'Son',
  13. components: {
  14. GrandSon
  15. },
  16. setup () {
  17. // 接收祖先组件提供的数据
  18. const money = inject('money')
  19. return { money }
  20. }
  21. }
  22. </script>
  23. <style scoped lang="less"></style>
  1. <template>
  2. <div class="container">
  3. <h3>孙组件 {{money}} <button @click="fn">消费20</button></h3>
  4. </div>
  5. </template>
  6. <script>
  7. import { inject } from 'vue'
  8. export default {
  9. name: 'GrandSon',
  10. setup () {
  11. const money = inject('money')
  12. // 孙组件,消费50,通知父组件App.vue组件,进行修改
  13. // 不能自己修改数据,遵循单选数据流原则,大白话:数据谁定义谁修改
  14. const changeMoney = inject('changeMoney')
  15. const fn = () => {
  16. changeMoney(20)
  17. }
  18. return {money, fn}
  19. }
  20. }
  21. </script>
  22. <style scoped lang="less"></style>

总结:

  1. provide函数提供数据和函数给后代组件使用
  2. inject函数给当前组件注入provide提供的数据和函数

v-model语法糖

目标:掌握vue3.0的v-model语法糖原理

在vue2.0中v-mode语法糖简写的代码 <Son :value="msg" @input="msg=$event" />

在vue3.0中v-model语法糖有所调整:<Son :modelValue="msg" @update:modelValue="msg=$event" />

演示代码:

  1. <template>
  2. <div class="container">
  3. <!-- 如果你想获取原生事件事件对象 -->
  4. <!-- 如果绑定事函数 fn fn(e){ // e 就是事件对象 } -->
  5. <!-- 如果绑定的是js表达式 此时提供一个默认的变量 $event -->
  6. <h1 @click="$event.target.style.color='red'">父组件 {{count}}</h1>
  7. <hr>
  8. <!-- 如果你想获取自定义事件 -->
  9. <!-- 如果绑定事函数 fn fn(data){ // data 触发自定义事件的传参 } -->
  10. <!-- 如果绑定的是js表达式 此时 $event代表触发自定义事件的传参 -->
  11. <!-- <Son :modelValue="count" @update:modelValue="count=$event" /> -->
  12. <Son v-model="count" />
  13. </div>
  14. </template>
  15. <script>
  16. import { ref } from 'vue'
  17. import Son from './Son.vue'
  18. export default {
  19. name: 'App',
  20. components: {
  21. Son
  22. },
  23. setup () {
  24. const count = ref(10)
  25. return { count }
  26. }
  27. }
  28. </script>
  1. <template>
  2. <div class="container">
  3. <h2>子组件 {{modelValue}} <button @click="fn">改变数据</button></h2>
  4. </div>
  5. </template>
  6. <script>
  7. export default {
  8. name: 'Son',
  9. props: {
  10. modelValue: {
  11. type: Number,
  12. default: 0
  13. }
  14. },
  15. setup (props, {emit}) {
  16. const fn = () => {
  17. // 改变数据
  18. emit('update:modelValue', 100)
  19. }
  20. return { fn }
  21. }
  22. }
  23. </script>

总结: vue3.0封装组件支持v-model的时候,父传子:modelValue 子传父 @update:modelValue

补充: vue2.0的 xxx.sync 语法糖解析 父传子 :xxx 子传父 @update:xxx 在vue3.0 使用 v-model:xxx 代替。

mixins语法

目标:掌握mixins语法的基本使用,vue2.x封装逻辑的方式,vue3.0建议使用组合API

官方话术:

  • 混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。
  • 理解全局混入:所有组件混入了这些逻辑代码
  1. // 全局混入 全局mixin
  2. // vue2.0 写法 Vue.mixin({})
  3. app.mixin({
  4. methods: {
  5. say () {
  6. console.log(this.$el,'在mounted中调用say函数')
  7. }
  8. },
  9. mounted () {
  10. this.say()
  11. }
  12. })
  1. <template>
  2. <div class="container1">
  3. <h1> 作者:周杰伦 <a href="javascript:;">关注</a> </h1>
  4. <hr>
  5. <Son />
  6. </div>
  7. </template>
  8. <script>
  9. import Son from './Son.vue'
  10. export default {
  11. name: 'App',
  12. components: {
  13. Son
  14. }
  15. }
  16. </script>
  1. <template>
  2. <div class="container2">
  3. <h2> 作者:周杰伦 <button>关注</button> </h2>
  4. </div>
  5. </template>
  6. <script>
  7. export default {
  8. name: 'Son'
  9. }
  10. </script>
  11. <style scoped lang="less"></style>
  • 理解局部混入:通过mixins选项进行混入
  1. // 配置对象
  2. export const followMixin = {
  3. data () {
  4. return {
  5. loading: false
  6. }
  7. },
  8. methods: {
  9. followFn () {
  10. this.loading = true
  11. // 模拟请求
  12. setTimeout(()=>{
  13. // 省略请求代码
  14. this.loading = false
  15. },2000)
  16. }
  17. }
  18. }
  1. <template>
  2. <div class="container1">
  3. <h1> 作者:周杰伦 <a href="javascript:;" @click="followFn">{{loading?'请求中...':'关注'}}</a> </h1>
  4. <hr>
  5. <Son />
  6. </div>
  7. </template>
  8. <script>
  9. import Son from './Son.vue'
  10. import {followMixin} from './mixins'
  11. export default {
  12. name: 'App',
  13. components: {
  14. Son
  15. },
  16. mixins: [followMixin]
  17. }
  18. </script>
  1. <template>
  2. <div class="container2">
  3. <h2> 作者:周杰伦 <button @click="followFn">{{loading?'loading...':'关注'}}</button> </h2>
  4. </div>
  5. </template>
  6. <script>
  7. import {followMixin} from './mixins'
  8. export default {
  9. name: 'Son',
  10. mixins: [followMixin]
  11. }
  12. </script>
  13. <style scoped lang="less"></style>

总结: 在vue2.0中一些可复用的逻辑可以使用mixins来封装,当是需要考虑逻辑代码冲突问题。vue3.0的组合API很好的解决了这个问题,就不在推荐使用mixins了。