Vue3的核心语法【未完】

Vue3的核心语法

OptionsAPI与CompositionAPI

Options API(选项式) 和 Composition API (组合式)是 Vue.js 中用于构建组件的两种不同方式。Options API

Options API

Options API 是 Vue 2 中的传统模式,并在 Vue 3 中继续得到支持。它通过在组件定义中使用选项(如 datamethodscomputed 等)来组织代码,选项所定义的属性都会暴露在函数内部的 this 上,它会指向当前的组件实例

Composition API

Composition API 是 Vue 3 引入的新特性,允许开发者以函数的形式编写可重用的逻辑片段,并将这些片段组合在一起。

对比

特性 Options API Composition API
代码组织方式 分散在 datamethodscomputed 等选项中 使用 setup 函数,相关逻辑集中
复用性 较差,逻辑分散 较好,逻辑封装为函数,便于复用
维护性 随着组件复杂度增加,维护难度增大 代码集中,维护方便
学习难度 更直观,易于上手 学习曲线较陡
适用场景 小型项目、新手 大型项目、需要复用逻辑的

拉开序幕的setup

在 Vue 3 中,setup 函数是 Composition API 的核心入口,用于替代 Options API 中的 datamethodscomputed 等选项。它在组件实例化之前执行,允许开发者以更灵活和模块化的方式组织组件逻辑。

setup 函数的作用

  1. 声明响应式状态

    使用 refreactive 创建响应式数据,这些数据可以在模板中直接使用。

    javascript 复制代码
    import { ref } from 'vue';
    export default {
      setup() {
        const count = ref(0);
        return { count };
      }
    };
  2. 定义计算属性和侦听器

    使用 computedwatch 来创建计算属性和侦听器,从而实现更灵活的状态管理。

    javascript 复制代码
    import { ref, computed, watch } from 'vue';
    export default {
      setup() {
        const count = ref(0);
        const doubleCount = computed(() => count.value * 2);
        watch(count, (newVal, oldVal) => {
          console.log(`count changed from ${oldVal} to ${newVal}`);
        });
        return { count, doubleCount };
      }
    };
  3. 定义方法

    setup 中定义方法,并在模板中调用这些方法。

    javascript 复制代码
    export default {
      setup() {
        const count = ref(0);
        const increment = () => { count.value++; };
        return { count, increment };
      }
    };
  4. 使用生命周期钩子

    虽然 setup 本身不是生命周期钩子,但可以在其中访问生命周期钩子函数(如 onMountedonUnmounted 等)。

    javascript 复制代码
    import { onMounted } from 'vue';
    export default {
      setup() {
        onMounted(() => {
          console.log('Component is mounted!');
        });
      }
    };
  5. 逻辑复用和组合

    通过自定义的组合函数(Composables),可以封装特定逻辑,并在多个组件中复用。

    javascript 复制代码
    // useCounter.js
    import { ref } from 'vue';
    export function useCounter() {
      const count = ref(0);
      const increment = () => { count.value++; };
      return { count, increment };
    }
    
    // MyComponent.vue
    import { useCounter } from './useCounter';
    export default {
      setup() {
        const { count, increment } = useCounter();
        return { count, increment };
      }
    };
  6. 与 Options API 的兼容性

    虽然 setup 是 Vue 3 的新特性,但它可以与 Options API 共存。不过,为了保持代码的一致性,建议选择一种方式并坚持使用。

setup 函数的参数

setup 函数可以接收两个参数:propscontext

  • props:包含传递给组件的所有属性,是响应式的,不能直接解构。
  • context :包含 attrsslotsemit,分别对应未声明为 props 的属性、插槽内容和自定义事件。

示例

以下是一个更复杂的示例,展示如何在 setup 中综合使用响应式数据、计算属性、侦听器和生命周期钩子。

html 复制代码
<template>
  <div>
    <h1>{{ message }}</h1>
    <p>Count: {{ count }}</p>
    <p>Double Count: {{ doubleCount }}</p>
    <button @click="increment">Increment</button>
    <button @click="resetCount">Reset Count</button>
  </div>
</template>

<script>
import { ref, computed, watch, onMounted, onUnmounted } from 'vue';

export default {
  props: {
    message: String
  },
  setup(props) {
    // 响应式数据
    const count = ref(0);

    // 计算属性
    const doubleCount = computed(() => count.value * 2);

    // 方法
    const increment = () => {
      count.value++;
    };

    const resetCount = () => {
      count.value = 0;
    };

    // 侦听器
    watch(count, (newVal, oldVal) => {
      console.log(`Count changed from ${oldVal} to ${newVal}`);
    });

    // 生命周期钩子
    onMounted(() => {
      console.log('Component is mounted!');
    });

    onUnmounted(() => {
      console.log('Component is unmounted!');
    });

    // 返回对象,暴露给模板
    return {
      message: props.message,
      count,
      doubleCount,
      increment,
      resetCount
    };
  }
};
</script>
  1. 响应式数据count 是通过 ref 创建的响应式数据。
  2. 计算属性doubleCount 是基于 count 的计算属性。
  3. 方法incrementresetCount 是定义的操作方法。
  4. 侦听器 :通过 watch 监听 count 的变化,并在控制台输出变化信息。
  5. 生命周期钩子:在组件挂载和卸载时分别输出日志。
  6. 返回值setup 返回的对象包含所有需要在模板中使用的数据和方法。

setup语法糖

setup 语法糖是 Vue 3 提供的一种更简洁的 setup 使用方式。它允许你直接在组件中使用 propscontext,而无需手动解构。

使用场景

  • 简化 props 的声明和使用
  • 简化 context 的访问
  • 与 TypeScript 的更好集成
基本用法
js 复制代码
<script setup>    //关键
import { ref } from 'vue';

const count = ref(0);
const increment = () => count.value++;
</script>

<template>
  <div>
    <p>{{ count }}</p>
    <button @click="increment">Increment</button>
  </div>
</template>

在上面的例子中,<script setup>setup 语法糖的关键。它允许你在 <script> 标签中直接编写逻辑代码,而无需手动定义 setup 函数。

2. 声明 props

setup 语法糖中,props 可以直接在 <script> 标签中声明,而无需手动解构。

html 复制代码
<script setup>
import { ref } from 'vue';

const props = defineProps({
  title: String,
  initialCount: {
    type: Number,
    default: 0
  }
});

const count = ref(props.initialCount);
const increment = () => count.value++;
</script>

<template>
  <div>
    <h1>{{ title }}</h1>
    <p>{{ count }}</p>
    <button @click="increment">Increment</button>
  </div>
</template>

3.使用emit

setup 语法糖还支持直接使用 emit,而无需手动解构 context

html 复制代码
<script setup>
import { ref } from 'vue';

const props = defineProps({
  title: String
});
const emit = defineEmits(['update:title']);

const updateTitle = () => {
  emit('update:title', 'New Title');
};
</script>

<template>
  <div>
    <h1>{{ title }}</h1>
    <button @click="updateTitle">Update Title</button>
  </div>
</template>

4.使用 attrsslots

setup 语法糖还支持直接访问 attrsslots,而无需手动解构 context

html 复制代码
<script setup>
import { useSlots, useAttrs } from 'vue';

const slots = useSlots();
const attrs = useAttrs();
</script>

<template>
  <div>
    <p>Slots: {{ Object.keys(slots) }}</p>
    <p>Attrs: {{ attrs }}</p>
  </div>
</template>

ref

ref 是 Composition API 的核心功能之一,用于创建响应式数据引用。它允许开发者将基++本类型++ (如数字、字符串、布尔值)或++复杂类型++(如对象、数组)包装成响应式对象。

ref 基本概念

ref 是 Vue 3 提供的一个函数,用于创建一个响应式引用。它将一个值包装成一个响应式对象,该对象通过 .value 属性访问和修改其值。

js 复制代码
import { ref } from 'vue';

const count = ref(0); // 创建一个响应式的数字
const name = ref('Vue 3'); // 创建一个响应式的字符串
const isVisible = ref(true); // 创建一个响应式的布尔值

在模板中使用 ref 时,Vue 会自动解包 .value,因此可以直接使用。

html 复制代码
<template>
  <div>
    <p>Count: {{ count }}</p>
    <p>Name: {{ name }}</p>
    <h2>当前和为:{{ sum }}</h2>
  </div>
</template>
ref 的用法

1.基本用法:

ref 可以包装基本类型或复杂类型,但是必须通过 .value 访问和修改值。

js 复制代码
console.log(count.value); // 输出 0
count.value++; // 修改值
console.log(count.value); // 输出 1

function changesum(){
  sum.value +=1;
}

2.响应式对象和数组
ref 也可以用于对象和数组,Vue 会自动追踪其内部属性的变化。

javascript 复制代码
const user = ref({ name: 'John', age: 30 });
console.log(user.value.name); // 输出 John
user.value.age = 31; // 修改对象属性

对于数组,可以直接使用数组方法(如 pushpop)。

javascript 复制代码
const tasks = ref(['学习 Vue 3']);
tasks.value.push('完成项目');

3 .响应式对象的嵌套

如果 ref 包装的是一个对象,对象内部的属性也是响应式的,但需要通过 .value 访问。

javascript 复制代码
const user = ref({ name: 'John', age: 30 });
console.log(user.value.name); // 输出 John
user.value.age = 31; // 修改对象属性

注意事项:

  • 直接修改 ref.value 属性才会触发响应式更新。

reactive

reactive 是一个核心的响应式 API,用于创建响应式对象。它通过 ES6 的 Proxy 实现深层次的响应式代理,能够自动追踪对象属性的变化并触发视图更新。

基本用法

reactive 主要用于处理对象或数组类型的响应式数据。它将一个普通对象转换为响应式对象,可以直接访问和修改其属性,而无需通过 .value

示例 1:基本用法

vue 复制代码
<template>
  <div>
    <p>用户信息: {{ user.name }} - {{ user.age }}岁</p>
    <button @click="incrementAge">增加年龄</button>
  </div>
</template>

<script>
import { reactive } from 'vue';

export default {
  setup() {
    const user = reactive({
      name: '张三',
      age: 25,
    });

    const incrementAge = () => {
      user.age++; // 直接修改属性,无需使用 .value
    };

    return { user, incrementAge };
  }
};
</script>

在这个示例中,reactive 创建了一个包含用户信息的对象 user。点击按钮时,user.age 直接被修改,视图也会自动更新。

reactive 支持深层嵌套对象的响应式更新,这使得它非常适合处理复杂的数据结构。

示例 2:嵌套对象与数组

vue 复制代码
<template>
  <div>
    <p>用户信息: {{ user.name }} - {{ user.age }}岁</p>
    <p>地址: {{ user.address.city }}, {{ user.address.zip }}</p>
    <button @click="incrementAge">增加年龄</button>
    <button @click="updateAddress">更新地址</button>
  </div>
</template>

<script>
import { reactive } from 'vue';

export default {
  setup() {
    const user = reactive({
      name: '张三',
      age: 25,
      address: {
        city: '北京',
        zip: '100000'
      }
    });

    const incrementAge = () => {
      user.age++;
    };

    const updateAddress = () => {
      user.address.city = '上海';
      user.address.zip = '200000';
    };

    return { user, incrementAge, updateAddress };
  }
};
</script>

在这个示例中:

  1. user 是一个包含嵌套对象 address 的响应式对象。
  2. 修改 user.ageuser.address 的属性时,视图会自动更新。

解析

  1. 响应式原理
    reactive 使用 ES6 的 Proxy 对象实现深层次的响应式代理。它会自动拦截对对象属性的 getset 操作,从而实现依赖收集和更新触发。

reactive的弊端

ref 对比reactive

特性 ref reactive
适用类型 基本类型(数字、字符串、布尔值),也可以用于对象和数组 对象、数组
访问方式 需要 .value 直接访问
深度响应式 不支持 支持
性能 轻量级,适合简单数据 深度响应式,适合复杂数据
使用场景 简单数据、计数器、DOM 引用 复杂对象、表单数据、状态管理

toRefs 和 toRef

toRef 的介绍与用法

1. 作用

toRef 用于从一个响应式对象 中提取某个属性 ,并将其转换为一个独立ref 对象。这个 ref 对象与原始属性保持响应式连接 ,即修改 ref 的值会同步更新原始属性,反之亦然。

2. 使用场景

  • 当需要将响应式对象的某个属性单独提取出来时。
  • 当需要将某个属性传递给组合式函数或子组件时。

3. 示例代码

javascript 复制代码
import { reactive, toRef } from 'vue';

const state = reactive({
  name: 'Alice',
  age: 25
});

const nameRef = toRef(state, 'name'); // 提取 name 属性为 ref
console.log(nameRef.value); // 输出 Alice

nameRef.value = 'Bob'; // 修改 ref 的值
console.log(state.name); // 输出 Bob,原始属性也被更新

state.age = 30; // 修改原始属性
const ageRef = toRef(state, 'age');
console.log(ageRef.value); // 输出 30,ref 与原始属性同步[^36^]
toRefs的介绍与用法

1. 作用

toRefs 用于将一个响应式对象的所有属性转换为一个普通对象,其中每个属性都是一个 ref 对象。这些 ref 对象与原始属性保持响应式连接。

2. 使用场景

  • 当需要解构响应式对象并在模板中使用其属性时,toRefs 可以确保解构后的属性仍然保持响应式。
  • 当需要将响应式对象的属性传递给子组件时,toRefs 可以确保子组件接收到的属性是响应式的。

3. 示例代码

javascript 复制代码
import { reactive, toRefs } from 'vue';

const state = reactive({
  name: 'Alice',
  age: 25
});

const stateRefs = toRefs(state); // 将所有属性转换为 ref
console.log(stateRefs.name.value); // 输出 Alice
console.log(stateRefs.age.value); // 输出 25

stateRefs.name.value = 'Bob'; // 修改 ref 的值
console.log(state.name); // 输出 Bob,原始属性也被更新

state.age = 30; // 修改原始属性
console.log(stateRefs.age.value); // 输出 30,ref 与原始属性同步[^37^]

4. 原理解释

toRefs 遍历响应式对象的所有属性,并为每个属性调用 toRef,从而创建一个包含所有属性的 ref 对象的普通对象。


toRef 与toRefs 的区别

特性 toRef toRefs
作用对象 单个属性 整个对象的所有属性
返回值 单个 ref 对象 包含所有属性的 ref 对象的普通对象
使用场景 提取单个属性并保持响应式连接 解构整个对象并保持响应式连接
灵活性 更灵活,适用于特定属性 适用于需要批量处理所有属性的场景

computed

在 Vue 3 中,computed 是一个非常重要的响应式特性,用于声明式地计算派生值。它基于依赖的响应式数据自动缓存计算结果,并且只有当依赖项发生变化时才会重新计算。

1. computed 的基本用法

computed 可以在 Vue 组件的 setup() 函数中通过 computed() 方法使用,也可以在选项式 API 中直接定义。

js 复制代码
//CompositionAPI中的写法

import { ref, computed } from 'vue';

export default {
    setup(){
        const fiestName = ref('John');
        const lastName = ref('Doa');
        
        //定义一个 computed 属性
        const fullName = computed(()=>{
            return `${firstName.value} ${lastName.value}`
        });
		
        return {
            firstName,
            lastName,
            fullName
        };
    }
};

在模板中可以直接使用fullName

html 复制代码
<template>
  <div>
    <p>Full Name: {{ fullName }}</p>
    <input v-model="firstName" placeholder="First Name">
    <input v-model="lastName" placeholder="Last Name">
  </div>
</template>
2. computed 的两种模式

computed 支持两种模式:getter-only (只读)和 writable(可读可写)。

这是最常见的模式,只提供一个 getter 函数,用于计算派生值。

javascript 复制代码
const fullName = computed(() => {
  return `${firstName.value} ${lastName.value}`;
});

如果需要让 computed 属性可写,可以传入一个对象,包含 getset 方法。

js 复制代码
const fullName = computed({
  get() {
    return `${firstName.value} ${lastName.value}`;
  },
  set(newValue) {
    const names = newValue.split(' ');
    firstName.value = names[0];
    lastName.value = names[1];
  }
});

在模板中,fullName 现在可以被赋值:

html 复制代码
<input v-model="fullName" placeholder="Full Name">

完整示例:

html 复制代码
<template>
  <div class="person">
    姓: <input type="text" v-model="firstName"><br><br>
    名: <input type="text" v-model="lastName"><br><br>
  全名:<span>{{ fullName }}</span>
  <button @click="changFN">改全名为li-si</button> 
  </div>
 
</template>
js 复制代码
<script setup lang="ts" name = "Person">

  import {ref,computed} from 'vue';

  let firstName = ref('zhang');
  let lastName = ref('san');

  // //这么定义的fullName是一个计算属性,且是只读的
  // let fullName = computed(()=>{
  //   return firstName.value.slice(0,1).toUpperCase() +firstName.value.slice(1)+ '-' + lastName.value;
  // })
  //这么定义的fullName是一个计算属性,是可读可写的
    let fullName = computed({
      get(){
        return firstName.value.slice(0,1).toUpperCase() +firstName.value.slice(1)+ '-' + lastName.value;
      },
      set(val){
        const [str1,str2] = val.split('-');
        firstName.value = str1;
        lastName.value = str2;
        console.log('set');
      }
    })

  function changFN(){
    fullName.value = 'li-si';
  }

</script>
css 复制代码
<style scoped>
  .person{
    background-color: rgb(5, 141, 141);
    border-radius: 10px;
    color: rgb(195, 202, 202);
    box-shadow: 0 0 10px;
    padding: 20px;
  }
  button{
    margin: 10px;
  }
</style>
3. 注意点

(1) ++缓存机制++

computed 是基于依赖的缓存。只有当依赖项发生变化时,才会重新计算。如果依赖项没有变化,即使手动调用 computed,也不会重新计算,而是直接返回缓存值。

(2) ++避免将 computed 用于副作用操作++

computed 应该是纯函数,仅用于计算派生值。不要在 computed 中执行副作用操作(如 API 请求、修改数据等)。如果需要执行副作用操作,应该使用 watchwatchEffect

(3) ++依赖响应式数据++

computed 的依赖必须是响应式数据(如 refreactive 或其他 computed)。如果依赖非响应式数据,computed 将不会自动更新。

(4) 在 computed 中访问 this

在 Options API 中,可以直接通过 this 访问组件的上下文。但在 Composition API 中,computed 是一个独立的函数,不能直接访问 this,需要通过 setup() 中的变量来访问。

(5) ++computed 的返回值++

computed 的返回值必须是一个值(如字符串、数字、对象等),不能返回函数或其他复杂结构。

(6) 避免过度使用 computed

虽然 computed 很强大,但过度使用可能会导致组件逻辑复杂化。对于简单的逻辑,直接在模板中使用表达式可能更清晰。

相关推荐
持续升级打怪中3 分钟前
Vue3 中虚拟滚动与分页加载的实现原理与实践
前端·性能优化
GIS之路7 分钟前
GDAL 实现矢量合并
前端
hxjhnct9 分钟前
React useContext的缺陷
前端·react.js·前端框架
冰暮流星16 分钟前
javascript逻辑运算符
开发语言·javascript·ecmascript
前端 贾公子34 分钟前
从入门到实践:前端 Monorepo 工程化实战(4)
前端
菩提小狗37 分钟前
Sqlmap双击运行脚本,双击直接打开。
前端·笔记·安全·web安全
前端工作日常1 小时前
我学习到的AG-UI的概念
前端
韩师傅1 小时前
前端开发消亡史:AI也无法掩盖没有设计创造力的真相
前端·人工智能·后端
XiaoYu20021 小时前
第12章 支付宝SDK
前端
双向331 小时前
RAG的下一站:检索增强生成如何重塑企业知识中枢?
前端