🥝FANMR.CN热爱,追求
Vue3知识及其新特性

组合API

为什么出现组合API

对于小型项目而言,使用Vue2的方式,数据和业务逻辑分离确实方便,但是当项目过大后,在一个Vue中加功能就会加数据加逻辑,数据和逻辑并不在一起,维护难度加大,复用性降低,大部分功能看似相似,却做着复制粘贴的功能开发

组合API使用示例

ref:简单数据处理

import { ref } from "vue";
export default {
  name: "App",
  // 入口函数
  setup() {
    // 1. 使用 ref 只能定义基本类型的变化,不能监听复杂类型的变化(对象/数组)
    let count = ref(0);
    // 2. 在组合 API 中,如果想定义方法,不用定义到 methods 中,直接定义即可
    function myFn() {
      count.value += 1;
    }
    // 3. 注意点:在组合 API 中定义的变量/方法,要想在外面使用,必须通过 return 暴露出去
    return { count, myFn };
  },
};

reactive:复杂数据处理(对象,数组)

import { reactive } from "vue";
export default {
  name: "App",
  // 入口函数
  setup() {
    // 1. 使用 reactive 定义(对象/数组)
    let state = reactive({
      stus: [{ id: 1, name: "zs", age: 10 }],
    });
    // 2. 改变其中的一个值,其会相应变换
    function changeStus() {
      state.stus[0].age += 1;
    }
    return { state, changeStus };
  },
};
/*
1. 什么是reactive?
  - reactive 是 Vue3中提供的实现响应式数据的方法
  - 在 Vue2中响应式数据是通过defineProperty来实现的
    而在Vue3中响应式数据是通过 ES6 中的 Proxy 来实现的
  - 本质:就是将传入的数据包装成一个 Proxy 对象
2. reactive 注意点:
  - reactive 参数必须是对象(json/arr)
  - 如果给 reactive 传递了其他对象
    + 默认情况下修改对象,界面不会自动更新
    + 如果想更新,可以通过重新赋值的方式
*/

抽离

import { reactive } from "vue";
export default {
  name: "App",
  setup() {
    // 只需要在这里引入进来就行了
    let { state, changeStus } = change();
    return { state, changeStus };
  },
};

// 在外面定义一个业务逻辑单元(类似类,有数据和操作)
function change() {
  // 1. 使用 reactive 定义(对象/数组)
  let state = reactive({
    stus: [{ id: 1, name: "zs", age: 10 }],
  });
  // 2. 改变其中的一个值,其会相应变换
  function changeStus() {
    state.stus[0].age += 1;
  }
  return { state, changeStus };
}

抽离到js

// chang.js
// 在外面定义一个业务逻辑单元(类似类,有数据和操作)
import { reactive } from "vue";
export default function change() {
  // 1. 使用 reactive 定义(对象/数组)
  let state = reactive({
    stus: [
      { id: 1, name: "zs", age: 10 },
      { id: 2, name: "ls", age: 20 },
      { id: 3, name: "ww", age: 30 },
    ]
  });
  // 2. 改变其中的一个值,其会相应变换
  function changeStus() {
    state.stus[0].age += 1
  }
  return { state, changeStus }
}

使用

import change from "./change";
export default {
  name: "App",
  setup() {
    // 只需要在这里引入进来就行了
    let { state, changeStus } = change();
    return { state, changeStus };
  },
};

本质

从setup中暴露的数据,会注入到 Option api 的data中, 从setup 中暴露的方法,会注入到Option api的methods中

setup 执行(注入)时机

在 beforeCreate 和 created 之间

  • beforeCreate:表示组件刚刚被创建出来,组件的data和methods还没初始化好
  • setup
  • Created:表示组件刚刚被创建出来,并且组件的data和methods已经初始化好

结论:

  • 由于在执行 setup 函数的时候,还没有执行 Created 生命周期方法,所以在 setup 函数中,是无法使用 data和methods的
  • 由于我们不能在 setup 函数中使用 data 和 methods,所以Vue为了避免我们错误的使用,它直接将setup函数中的this修改成了undefined
  • setup 函数只能是同步的不能是异步的(不能在函数前面加 async)
图

允许多个根节点

在Vue3中,一个模板可以有多个根节点了

CSS直接绑定JS变量

<script setup>
let globleWidth = 100px
</script>

<style lang="sass>
.box
  width: v-bind(globleWidth )
</style>

变量直接使用

setup中定义的变量可以直接在模板中使用

<template>
  <button type="button" @click="count++">count is: {{ count }}</button>
</template>

<script setup>
import { ref } from 'vue'

const count = ref(0)
</script>

响应式绑定

在Vue3中,变量的响应式采用了ref()reactive()函数进行绑定,否则变量改变后,页面的数据依然无法改变

  • ref()是对reactive()的二次包装
  • ref()定义的数据访问的时候要多一个.value
  • ref()定义基本数据类型
  • reactive()定义数组和对象

计算属性

只执行一次,减少计算,有缓存机制

import { computed } from 'vue'

const double = computed(()=>{
  return count.value* 2;
})

监听

监听数据的变化,然后需要执行的操作

import { watch} from 'vue'

watch(user, () => {
  fullName3.value = user.firstName + '-' + user.lastName;
}, {
  immediate: true,  // 是否初始化立即执行一次, 默认是false
  deep: true, // 是否是深度监视, 默认是false
});

watch(user, (newValue, oldValue) => {
  fullName3.value = user.firstName + '-' + user.lastName;
});

watch(() => user.name, (newValue, oldValue) => {
  fullName3.value = user.firstName + '-' + user.lastName;
});

插槽

https://blog.csdn.net/m0_47135993/article/details/124259448

动态组件

用于解决Tab切换的场景

<template>
  <div class="tabs-content" @click="switchTab(tab)" v-for="(tab, index) in tabData" :key="index">
    {{ tab.name }}
  </div>
  <component :is="currentTab.tabComp"></component>
</template>
<script setup lang="ts">
import { reactive, markRaw } from 'vue'
import A from './A.vue'
import B from './B.vue'
import C from './C.vue'
 
type tabType = {
  name: string,
  tabComp: any
}
 
type Comp = Pick<tabType, 'tabComp'>
const tabData = reactive<tabType[]>([
  {
    name: 'A组件',
    // proxy会代理reactive中的所有内容
    // 无需对组件进行proxy代理
    // 必须使用markRaw跳过对组件的代理,否则vue会给警告
    tabComp: markRaw(A)
  },
  {
    name: 'B组件',
    tabComp: markRaw(B)
  },
  {
    name: 'C组件',
    tabComp: markRaw(C)
  },
])
 
let currentTab = reactive<Comp>({
  tabComp: tabData[0].tabComp
})
 
const switchTab = (tab: tabType) => {
  currentTab.tabComp = tab.tabComp
}
</script>
<style scoped lang="less">
.tabs-content {
  display: inline-block;
  width: 100px;
  border: 1px solid #ccc;
  background: rgb(175, 96, 96);
  color: white;
}
</style>

异步组件

用于如滚动到组件再进行加载,否则不加载,实现按需引入等

provide和inject

//父组件代码
<script>
import { provide } from "vue"

export default {
  setup(){
    provide('info',"值")
  }
}
</script>

//子组件 代码
<template>
 {{info}}
</template>

<script>
import { inject } from "vue"

export default {
  setup(){
    const info = inject('info')
    return{
      info
    }
  }
}

</script>

mixin混入