Vue2的进阶Vue3

对比Vue2

Vue3使用与Vue2选项式api不同的组合式api

javascript 复制代码
// Vue2
<script>
export default {
  data(){
    return {
      count:0
    }
  },
  methods:{
    addCount(){
      this.count++
    }
  }
}
</script>
javascript 复制代码
// Vue3
<script setup>
import { ref } from 'vue'
const count = ref(0)
const addCount = ()=> count.value++
</script>

create-vue

create-vue是Vue官方新的脚手架工具,底层切换到了 vite,为开发提供极速响应

安装命令

复制代码
npm init vue@latest

组合式API - setup选项

在beforeCreate钩子之前执行

不在script加时需要像Vue2中的data一样

javascript 复制代码
<script>
  export default {
    setup(){
      const message = 'this is message'
      const logMessage = ()=>{
        console.log(message)
      }
      // 必须return才可以
      return {
        message,
        logMessage
      }
    }
  }
</script>

在script中加入后的语法糖写法

javascript 复制代码
<script setup>
const message = 'this is a message'
const logMessage = () => {
  console.log(message)
}
</script>

<template>
  <div>{{ message }}</div>
  <button @click="logMessage">按钮</button>
</template>

注意不用this:setup中的this指向undefined

reactive()

作用:接受对象类型数据的参数传入并返回一个响应式的对象

  1. 从 vue 包中导入 reactive 函数

2.在<script setup>中执行 reactive 函数并传入类型为对象的初始值,并使用变量接收函数返回值

只能传类型为对象的初始值

javascript 复制代码
import { reactive } from 'vue'
const state = reactive({
  count: 100
})
const setCount = () => {
  state.count++
}

ref()

作用:接收简单类型或者对象类型的数据传入并返回一个响应式的对象

  1. 从 vue 包中导入 ref 函数

  2. 在<script setup>中执行 ref 函数并传入初始值,并使用变量接收函数返回值

javascript 复制代码
// 2. ref: 接收简单类型 或 复杂类型,返回一个响应式的对象
//    本质:是在原有传入数据的基础上,外层包了一层对象,包成了复杂类型
//    底层,包成复杂类型之后,再借助 reactive 实现的响应式
//    注意点:
//    1. 脚本中访问数据,需要通过 .value
//    2. 在template中,.value不需要加 (帮我们扒了一层)
import { ref } from 'vue'
const count = ref(0)
const setCount = () => {
  count.value++
}

computed计算属性函数

计算属性基本思想和Vue2的完全一致,组合式API下的计算属性只是修改了写法

  1. 导入computed函数

  2. 执行函数在回调参数中return基于响应式数据做计算的值,用变量接收

javascript 复制代码
<script setup>
// const 计算属性 = computed(() => {
//    return 计算返回的结果
// })

import { computed, ref } from 'vue'

// 声明数据
const list = ref([1, 2, 3, 4, 5, 6, 7, 8])

// 基于list派生一个计算属性,从list中过滤出 > 2
const computedList = computed(() => {
  return list.value.filter(item => item > 2)
})

// 定义一个修改数组的方法
const addFn = () => {
  list.value.push(666)
}
</script>

<template>
  <div>
    <div>原始数据: {{ list }}</div>
    <div>计算后的数据: {{ computedList }}</div>
    <button @click="addFn" type="button">修改</button>
  </div>
</template>

注意:计算属性应该是只读的,特殊情况可以配置 get set(看官网)

watch函数

  1. 导入watch函数

  2. 执行watch函数传入要侦听的响应式数据(ref对象)和回调函数

javascript 复制代码
<script setup>
import { ref, watch } from 'vue'
const count = ref(0)
const nickname = ref('张三')

const changeCount = () => {
  count.value++
}
const changeNickname = () => {
  nickname.value = '李四'
}

// 1. 监视单个数据的变化
//    watch(ref对象, (newValue, oldValue) => { ... })
watch(count, (newValue, oldValue) => {
  console.log(newValue, oldValue)
})

// 2. 监视多个数据的变化
//    watch([ref对象1, ref对象2], (newArr, oldArr) => { ... })
watch([count, nickname], (newArr, oldArr) => {
  console.log(newArr, oldArr)
})

// 3. immediate 立刻执行
watch(count, (newValue, oldValue) => {
  console.log(newValue, oldValue)
}, {
  immediate: true
})
// --------------------------------------------
// 4. deep 深度监视, 默认 watch 进行的是 浅层监视
//    const ref1 = ref(简单类型) 可以直接监视
//    const ref2 = ref(复杂类型) 监视不到复杂类型内部数据的变化
const userInfo = ref({
  name: 'zs',
  age: 18
})
const setUserInfo = () => {
  // 修改了 userInfo.value 修改了对象的地址,才能监视到
  // userInfo.value = { name: 'ls', age: 50 }
  userInfo.value.age++
}

// deep 深度监视
// watch(userInfo, (newValue) => {
//   console.log(newValue)
// }, {
//   deep: true
// })

// 5. 对于对象中的单个属性,进行监视
watch(() => userInfo.value.age, (newValue, oldValue) => {
  console.log(newValue, oldValue)
})
</script>

Vue3的生命周期API

生命周期函数基本使用

  1. 导入生命周期函数

  2. 执行生命周期函数 传入回调

javascript 复制代码
<script setup>
import { onMounted } from 'vue';

// beforeCreate 和 created 的相关代码
// 一律放在 setup 中执行

const getList = () => {
  setTimeout(() => {
    console.log('发送请求,获取数据')
  }, 2000)
}
// 一进入页面的请求
getList()

// 如果有些代码需要在mounted生命周期中执行
onMounted(() => {
  console.log('mounted生命周期函数 - 逻辑1')
})

// 写成函数的调用方式,可以调用多次,并不会冲突,而是按照顺序依次执行
onMounted(() => {
  console.log('mounted生命周期函数 - 逻辑2')
})

</script>

组合式API - 父子通信

父传子

基本思想:

  1. 父组件中给子组件以绑定属性的方式传值

  2. 子组件内部通过props选项接收

注意:由于写了 setup,所以无法直接配置 props 选项,所以此处需要借助于 "编译器宏" 函数接收子组件传递的数据

对于props传递过来的数据,模板中可以直接使用

在js里需要props.调用

子传父

基本思想:

  1. 父组件中给子组件标签通过@绑定事件

  2. 子组件内部通过 emit 方法触发事件

通过模板引用

模板引用的时机是什么在组件挂载完毕时

javascript 复制代码
// 模板引用(可以获取dom,也可以获取组件)
// 1. 调用ref函数,生成一个ref对象
// 2. 通过ref标识,进行绑定
// 3. 通过ref对象.value即可访问到绑定的元素(必须渲染完成后,才能拿到)
const inp = ref(null)
javascript 复制代码
  <div>
    <input ref="inp" type="text">
    <button @click="clickFn">点击让输入框聚焦</button>
  </div>

defineExpose()

默认情况下在<script setup>语法糖下组件内部的属性和方法是不开放给父组件访问的,可以通过defineExpose 编译宏指定哪些属性和方法允许访问**(显式暴露组件内部的属性和方法)**

javascript 复制代码
<script setup>
const count = 999
const sayHi = () => {
  console.log('打招呼')
}

defineExpose({
  count,
  sayHi
})
</script>
javascript 复制代码
<script setup>
const testRef = ref(null)
const getCom = () => {
  console.log(testRef.value.count)
  testRef.value.sayHi()
}
</script>
javascript 复制代码
  <TestCom ref="testRef"></TestCom>
  <button @click="getCom">获取组件</button>

组合式API - provide和inject

顶层组件向任意的底层组件传递数据和方法,实现跨层组件通信

  1. 导入povide,顶层组件通过provide函数提供数据
javascript 复制代码
import { provide, ref } from 'vue'

// 1. 跨层传递普通数据
provide('theme-color', 'pink')

// 2. 跨层传递响应式数据
const count = ref(100)
provide('count', count)

setTimeout(() => {
  count.value = 500
}, 2000)

// 3. 跨层传递函数 => 给子孙后代传递可以修改数据的方法
provide('changeCount', (newCount) => {
  count.value = newCount
})
  1. 导入inject,底层组件通过inject函数获取数据
javascript 复制代码
<script setup>
import { inject } from 'vue'

const themeColor = inject('theme-color')
const count = inject('count')
const changeCount = inject('changeCount')
const clickFn = () => {
  changeCount(1000)
}
</script>

<template>
<div>
  <h3>我是底层组件-{{ themeColor }} - {{ count }}</h3>
  <button @click="clickFn">更新count</button>
</div>
</template>

defineOptions

如果我们要定义组件的 name 或其他自定义的属性,得再添加一个<script></script>在其中export

所以我们可以用 defineOptions 定义任意的定义 Options API 的选项, props, emits, expose, slots 除外(因为这些可以使用 defineXXX 来做到)

defineModel()

自定义组件上使用v-model, 相当于传递一个modelValue属性,同时触发 update:modelValue 事件

javascript 复制代码
<script setup>
import MyInput from '@/components/my-input.vue'
import { ref } from 'vue'
const txt = ref('123456')
</script>

<template>
<div>
  <MyInput v-model="txt"></MyInput>
  {{ txt }}
</div>
</template>
javascript 复制代码
<script setup>
const modelValue = defineModel()
</script>

<template>
<div>
  <input 
    type="text" 
    :value="modelValue" 
    @input="e => modelValue = e.target.value"
  >
</div>
</template>

defineModel() 返回的值是一个 ref。它可以像其他 ref 一样被访问以及修改,不过它能起到在父组件和当前变量之间的双向绑定的作用:

  • 它的 .value 和父组件的 v-model 的值同步;
  • 当它被子组件变更了,会触发父组件绑定的值一起更新

可以在子组件中更改父组件传过来的值并同步到父组件

相关推荐
purpleseashell_Lili10 分钟前
react 和 react native 的开发过程区别
javascript·react native·react.js
前端小巷子26 分钟前
Vue 2 渲染链路剖析
前端·vue.js·面试
Mintopia1 小时前
🧠 AI 本地自由之路:Ollama 教程指南
前端·javascript·aigc
Mintopia1 小时前
🧠 从像素到现实:用 Three.js + Cesium 构建数字孪生系统
前端·javascript·three.js
xyphf_和派孔明1 小时前
关于Web前端安全防御CSRF攻防的几点考虑
前端·安全·csrf
stars1 小时前
数字人开发02--前端服务配置
前端·人工智能
就改了2 小时前
Ajax——异步前后端交互提升OA系统性能体验
javascript
懋学的前端攻城狮2 小时前
Next.js + TypeScript + Shadcn UI:构建高性能懒加载与无限滚动系统
前端·react.js·前端框架
酷飞飞3 小时前
C语言的复合类型、内存管理、综合案例
java·c语言·前端