Skip to content

第一章 Vue3基础 v1.0

第一部分 Vue3基本介绍

一、Vue3的优势

  • 更容易维护:组合式API的引入与TypeScript支持
  • 更快的速度:重写diff算法、模板编译优化与更高效的组件初始化
  • 更小的体积:良好的TreeShaking与按需引入
  • 更优的数据响应式:Proxy

二、选项式API与组合式API

选项式 API (Options API):
在 Vue 2 及早期版本中,我们主要使用的是选项式 API。每个 Vue 组件的选项都组织在一个对象中,包括 data、methods、computed、watch、lifecycle hooks 等。

组合式 API (Composition API):
Vue 3 引入了组合式 API,允许我们使用函数式的方式来组织组件的逻辑。它依赖于 setup 函数,该函数提供了一个响应式系统的入口点,并允许我们使用 ref、reactive、computed 等函数来创建响应式状态,以及使用 watch 和 watchEffect 来观察状态的变化。

使用对比(点击按钮使数字加1)
vue
<script>
  export default {
      data () {
          return {
              count: 0
          }
      },
    methods: {
          addCount () {
              this.count++
          }
    }
  }
</script>
vue
<script setup>
  import { ref } from 'vue'
  const count = ref(0)
  const addCount = () => count.value++
</script>

三、代码结构

1.main.js

javascript
import './assets/main.css'
import { createApp } from 'vue'
import App from './App.vue'

// 使用 new Vue() 创建一个应用实例并挂载
createApp(App).mount('#app')

2.App.vue

vue
<!-- setup允许在script中直接编写组合式API -->
<script setup>
  // js逻辑结构
  // 与Vue2不同,Vue3中组件只需要import即可使用,不需要注册
</script>
<template>
  <!-- 模板结构 -->
</template>
<style scoped>
  /* 样式结构 */
</style>

第二部分 组合式API

一、基本使用

1.setup选项

setup选项执行时机:早于beforeCreate钩子函数

vue
<script setup>
  const data = "abc"
  const logData = () => {
      console.log(data)
  }
</script>
vue
<script>
  //<script setup>实际是一种语法糖,其完整写法与解释如下
  export default {
      setup () {
        const data = "abc"
        const logData = () => {
          console.log(data)
        }
        return {
          data,logData
        }
      }
  }
</script>

2.ref()与reactive()

javascript
// 作用:接受一个简单类型或对象类型数据,返回一个封装后的响应式对象
// 一般推荐使用:统一代码规范
import { ref } from 'vue'
const data = ref(17)
console.log(data.value)  // ref()对数据会进行一层封装,如需获取数据需要访问其value属性
javascript
// 作用:接受一个对象类型数据,返回一个响应式对象
// ref()通过包装数据再通过reactive()实现响应式数据的生成
import { reactive } from 'vue'
const data = reactive({
    day : 17
})
console.log(data.day)

3.计算属性

思想与Vue2基本一致,只是修改了写法为使用computed函数

vue
<script setup>
  // 1.导入computed函数
  import { computed } from "vue"
  // 2.定义执行函数
  const computedValue = computed(() = >{
      // 计算逻辑
  })
</script>

4.监听器

思想与Vue2基本一致,只是修改了写法为使用watch函数

vue
<script setup>
  // 1.导入watch函数
  import { watch, ref } from "vue"
  const value = ref(100)
  // 2.调用watch监听变化
  watch(value,   // value应当是响应式数据
      (newValue, oldValue) => {
      // 数据变化操作逻辑
  })
</script>
vue
<script setup>
  // 1.导入watch函数
  import { watch, ref } from "vue"
  const value1 = ref(100)
  const value2 = ref(200)
  // 2.调用watch监听变化
  watch([value1, value2],    // value1, value2应当是响应式数据
      ([newValue1, newValue2], [oldValue1, oldValue2]) => {
    // 数据变化操作逻辑
  })
</script>
vue
<script setup>
  // 1.导入watch函数
  import { watch, ref } from "vue"
  const value1 = ref(100)
  // ...
  // 2.调用watch监听变化
  watch([value1, ...],
      ([newValue1, ...], [oldValue1, ...]) => {
        // 数据变化操作逻辑
      },{
        immediate: false,    // 进入页面立即执行
        deep: false          // 深度监听,默认浅层监听(监听复杂类型)
      })
</script>
vue
<script setup>
  // 1.导入watch函数
  import { watch, ref } from "vue"
  const data = ref({column: 'value'})
  // 2.调用watch监听变化
  watch(() => data.value.column,(newValue, oldValue) => {  // 指定监听column数据
        // 数据变化操作逻辑
      })
</script>

5.模板引用

通过ref标识获取真实的dom对象或组件实例对象

vue
<script setup>
  import { ref } from 'vue'
  const myRef = ref(null)  // 通过相同名称进行绑定,需要在挂载阶段之后才能获取到并使用
</script>
<template>
  <myCom ref="myRef"></myCom>
</template>

6.defineExpose

默认情况下setup中组件内部的属性与方法是不开放给父组件访问的
可以通过 defineExpose 编译宏指定哪些属性与方法允许访问

vue
<script setup>
  import { ref } from 'vue'
  const msg = ref('msg')
  defineExpose({
    msg
  })
</script>

二、生命周期

选项式API组合式API
beforeCreate/createdsetup
beforeMountonBeforeMount
mountedonMounted
beforeUpdateonBeforeUpdate
updatedonUpdated
beforeUnmountonBeforeUnmount
unmountedonUnmounted

注:Vue3没有destroy相关生命周期函数

vue
<script setup>
  // beforeCreate 与 created 相关代码直接写在setup执行
  // 其他生命周期,以onMounted为例
  import { onMounted } from 'vue'
  
  onMounted(() => {
      // 逻辑代码,多次使用生命周期函数不会冲突,而是依次执行
  })
</script>

三、组件通信

1.父子通信

①父传子

通过 defineProps 编译器宏接收子组件传递的数据

vue
<script setup>
  const props = defineProps({
    message: String
  })
</script>
<template>
  {{ message }}
</template>
vue
<script setup>
  // 引入子组件
  import sonCom from './son-com.vue'
</script>
<template>
  <sonCom message="msg"/>
</template>
②子传父

通过 defineEmits 编译器宏生成emit方法

vue
<script setup>
  const emit = defineEmits(['get-msg'])
  const sendMsg = () => {
      emit('get-msg', 'msg')
  }
</script>
<template>
  <button @click="sendMsg">sendMsg</button>
</template>
vue
<script setup>
  import sonCom from './son-com.vue'
  const getMessage = (msg) => {
      console.log(msg)
  }
</script>
<template>
  <sonCom @get-message="getMessage"/>
</template>

2.跨层级组件通信

使用provide和inject(传递的可以是普通数据/响应式数据/函数)

顶层组件:provide('key', data)
底层组件:const message = inject('key')

四、Vue3.3新特性

1.defineOption

Vue3.3引入了defineOption宏,用于在setup中定义Options API的选项
defineOption宏可以定义任意选项(props,emits,expose,slots除外)

Vue
<script setup>
  defineOptions({
    name: 'MyCom',
    // 更多自定义属性
  })
</script>

2.defineModel

用于配合v-model,快速实现自定义组件双向数据绑定

使用defineModel: defineModel是试验阶段特性,使用需要在vite.config.js中开启

开启defineModel
javascript
export default defineConfig({
    plugins:[
        vue({
            script: {
                defineModel: true
            }
        })],
})

示例:使用defineModel

vue
<script setup>
  import MyInput from 'my-input.vue'
  import { ref } from 'vue'
  const txt = ref("123456")
</script>
<template>
  <MyInput v-model="txt"></MyInput>
  {{ txt }}
</template>
vue
<script setup>
  import { defineModel } from 'vue'
  const modelValue = defineModel()
</script>
<template>
  <input type="text" :value="modelValue" @input="e => modelValue = e.target.value">
</template>
vue
<script setup>
  import MyInput from 'my-input.vue'
  import { ref } from 'vue'
  const txt = ref("123456")
</script>
<template>
  <MyInput :modelValue="txt" @update:modelValue="txt=$event"></MyInput>
  {{ txt }}
</template>
vue
<script setup>
  import { defineProps, defineEmits } from "vue";
  defineProps({
    modelValue: String
  })
  const emit = defineEmits(['update:modelValue'])
</script>
<template>
  <input type="text" :value="modelValue" @input="e => emit('update:modelValue', e.target.value)">
</template>

第三部分 Pinia

Pinia是Vue最新的状态管理工具,是Vuex的替代品,详见官方网站:Pinia

一、简介

  1. 提供了更加简单的API
  2. 提供符合组合式风格的API
  3. 去掉modules概念,没一个store都是一个独立的模块
  4. 配合TypeScript更加友好,提供可靠的类型推断

二、安装

1.create-vue创建时添加

bash
npm create vue@lastest  # 直接创建时选择 => Add Pinia for state management (Yes)

2.在Vue3项目中引入

bash
npm install pinia
javascript
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

const pinia = createPinia()  // 创建pinia实例
const app = createApp(App)

app.use(pinia)
app.mount('#app')

三、使用

1.使用示例

javascript
export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)  // ref() 即 state属性
  const doubleCount = computed(() => count.value * 2)  // computed() 即 getters
  function increment() {  // function() 即 action
    count.value++
  }

  return { count, doubleCount, increment }
})
javascript
export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0 }),
  getters: {
    double: (state) => state.count * 2,
  },
  actions: {
    increment() {
      this.count++
    },
  },
})

2.storeToRefs()

作用:使从store中提取属性时保持其响应性

vue
<script setup>
  import { useDataStore } from 'data'
  import { storeToRefs } from 'pinia'
  const dataStore = useDataStore()
  const { data } = storeToRefs(dataStore)  // 此时data响应式不会丢失
</script>
vue
<script setup>
  import {useDataStore} from 'data'
  const dataStore = useDataStore()
  const { data } = dataStore  // 此时data响应式丢失
</script>