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 很强大,但过度使用可能会导致组件逻辑复杂化。对于简单的逻辑,直接在模板中使用表达式可能更清晰。

相关推荐
川石课堂软件测试17 分钟前
涨薪技术|持续集成Git使用详解
开发语言·javascript·git·python·功能测试·ci/cd·单元测试
imkaifan19 分钟前
如何在前端项目中看出node_modules中的库是一个可选依赖库
前端·npm命令·可选依赖
Warren9821 分钟前
使用SLF4J + Logback进行日志记录:
java·开发语言·前端·javascript·笔记·intellij-idea·logback
幸运小圣35 分钟前
编程题 - 明明的随机数【JavaScript/Node.js解法】
javascript·node.js
南城巷陌37 分钟前
Node.js 中的 http2 模块的使用
前端·node.js
kcarly43 分钟前
Web Snapshot 网页截图 模块代码详解
前端·python·网页截图
坐吃山猪44 分钟前
跨域-告别CORS烦恼
前端·后端·跨域·cors
dorabighead1 小时前
前端虚拟列表的深入解析:如何用虚拟滚动拯救你的DOM性能
前端·javascript
GISer_Jing1 小时前
【前端场景题】如何应对页面请求接口的大规模并发问题
前端·react.js·前端框架
帅帅哥的兜兜1 小时前
甘特图开发代码(测试版)
前端·javascript·甘特图