1.创建vue项目

npm create vite
# or
yarn create vite

在这里插入图片描述
vite快捷使用

如果想要快速创建一个vue3项目,可以使用如下命令

  • 创建普通vue项目
yarn create vite vite-demo --template vue
  • 创建基于ts模板的项目
yarn create vite vite-demo-ts --template vue-ts

2.vsocd插件说明

vue2中需要安装插件Vetur,可以实现组件高亮。但是vue3的一些语法在vetur中报错。
vue3中需要安装插件Volar,提供了更加强大的功能,插件和 Vetur 会出现冲突。
所以,使用功能vue3,需要禁用 vetur插件,安装Volar插件。 Volar 共需要安装两个插件,第二个提供 Volar TypeScript 支持。
3.# 组合式API

3. composition API vs options API

  1. vue2 采用的就是 optionsAPI

    (1) 优点:易于学习和使用, 每个代码有着明确的位置 (例如: 数据放 data 中, 方法放 methods中)

    (2) 缺点: 相似的逻辑, 不容易复用, 在大项目中尤为明显

    (3) 虽然 optionsAPI 可以通过mixins 提取相同的逻辑, 但是也并不是特别好维护

  2. vue3 新增的就是 compositionAPI

    (1) compositionAPI 是基于 逻辑功能 组织代码的, 一个功能 api 相关放到一起

    (2) 即使项目大了, 功能多了, 也能快速定位功能相关的 api

    (3) 大大的提升了 代码可读性可维护性

  3. vue3 推荐使用 composition API, 也保留了options API 即就算不用 composition API, 用 vue2 的写法也完全兼容!!

3.1 setup函数
  1. setup 函数是一个新的组件选项, 作为组件中 compositionAPI 的起点
  2. 从生命周期角度来看, setup 会在 beforeCreate 钩子函数之前执行
  3. setup 中不能使用 this, this 指向 undefined
  4. 在模版中需要使用的数据和函数,需要在 setup 返回。
3.1 reactive 函数 通常是用来定义响应式 对象数据

前置说明:

  1. setup 需要有返回值, 只有返回的值才能在模板中使用
  2. 默认普通的数据, 不是响应式的
    作用: 传入一个复杂数据类型,将复杂类型数据, 转换成响应式数据 (返回该对象的响应式代理Proxy)
 setup() {
    const obj = reactive({
      name: "小明",
      age: 18,
    });

    return { obj };
  },
3.2 ref 函数

reactive 处理的数据, 必须是复杂类型, 如果是简单类型无法处理成响应式, 所以有 ref 函数!
作用: 对传入的数据(一般简单数据类型),包裹一层对象, 转换成响应式。

  1. ref 函数接收一个的值, 返回一个ref 响应式对象, 有唯一的属性 value
  2. 在 setup 函数中, 通过 ref 对象的 value 属性, 可以访问到值
  3. 在模板中, ref 属性会自动解套, 不需要额外的 .value
  4. ref函数也支持传入复杂类型,传入复杂类型,也会做响应式处理

ref 和 reactive 的最佳使用方式:

  • 明确的对象,明确的属性,用 reactive,其他用 ref
  • 从vue3.2之后,官方更推荐使用 ref
3.3 script setup 语法

script setup是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。相比于普通的 script 语法更加简洁
要使用这个语法,需要将 setup 添加到 <script> 代码块上:

<script setup lang="ts">
console.log('hello script setup')
console.log(this)    // undefined
</script>

顶层的绑定会自动暴露给模板,所以定义的变量,函数和import导入的内容都可以直接在模板中直接使用

<template>
  <div>
    <h3>根组件</h3>
    <div>点击次数:{{ count }}</div>
    <button @click="add">点击修改</button>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const count = ref(0)
const add = () => {
  count.value++
}
</script>

script setup 优势:

  1. 使用 ts 项目不需要再 defineComponent 包裹了。
  2. 无需再 return 了, template 可直接使用,顶层的绑定会自动暴露给模板。
3.4计算属性computed函数

computed函数调用时, 要接收一个处理函数, 处理函数中, 需要返回计算属性的值

  • 简单写法,不带set的计算
  • 复杂写法,带 set 的计算,传入对象
<template>
  <div>我今年的年纪 <input type="text" v-model.number="age" /></div>
  <div>我明年的年龄 {{ nextAge }}</div>
  <div>我后年的年龄 <input type="text" v-model.numbe="nextAge2" /></div>
</template>

<script setup lang="ts">
import { computed, ref } from "vue";
const age = ref(10);
// 不带set的计算属性
const nextAge = computed(() => {
  return age.value + 1;
});

// 带set的计算属性
const nextAge2 = computed({
  get() {
    return age.value + 2;
  },
  set(val: number) {
    age.value = val - 2;
  },
});
</script>

3.5 侦听器watch函数

watch 侦听器, 接收三个参数

  1. 参数1: 监视的数据源
  2. 参数2: 回调函数
  3. 参数3: 额外的配置
// 监听单个ref
const money = ref(100)
watch(money, (value, oldValue) => {
  console.log(value)
})

// 监听多个ref
const money = ref(100)
const count = ref(0)
watch([money, count], (value) => {
  console.log(value)
})

// 监听ref复杂数据
const user = ref({
  name: 'zs',
  age: 18,
})
watch(
  user,
  (value) => {
    console.log('user变化了', value)
  },
  {
    // 深度监听,当ref的值是一个复杂数据类型,需要深度监听
    deep: true,
    immediate: true
  }
)

// 监听对象的某个属性的变化
const user = ref({
  name: 'zs',
  age: 18,
})
watch(
  () => {
      return user.value.name
  },
  (value) => {
    console.log(value)
  }
)
3.6 组件通讯-父传子

步骤:

  1. 父组件提供数据
  2. 父组件将数据传递给子组件
  3. 子组件通过 defineProps 进行接收
  4. 子组件渲染父组件传递的数据

父组件

<template>
  <son :car="str" :user1="user"></son>
</template>

<script setup lang="ts">
import { ref, watch } from "vue";
// 在setup语法中,只需要导入子组件,就可以渲染,不需要components注册

import son from "./components/son.vue";
const user = ref(100);
const str = ref({
  name: "ddd",
  age: 18,
});
</script>

子组件

<template>
  <div>父组件传过来的数据1{{ user1 }}</div>
  <div>父组件传过来的数据2{{ car.name }}</div>
</template>

<script setup lang="ts">
import { ref } from "vue";
interface Props {
  car: object;
  user1: number;
}
const props = defineProps<Props>();
console.log(props.user1);
</script>

注意:

  • 如果使用 defineProps 接收数据,这个数据只能在模板中渲染
  • 如果想要在 <script> 中也访问 props 属性,应该接收返回值。
3.7 组件通讯-子传父

步骤:

  1. 子组件通过 defineEmits 获取emit对象(因为没有this)
  2. 子组件通过emit触发事件,并且传递数据
  3. 父组件提供方法
  4. 父组件通过自定义事件的方式给子组件注册事件

子组件

<template>
  <div>父组件传过来的数据1{{ user1 }}</div>
  <div>父组件传过来的数据2{{ car.name }}</div>
  <div @click="emit('xiu', 1000)">点击传个父组件</div>
</template>

<script setup lang="ts">
import { ref } from "vue";
interface Props {
  car: object;
  user1: number;
}
const emit = defineEmits(["xiu"]);
const props = defineProps<Props>();
console.log(props.user1);
</script>

父组件

<template>
  <son :car="str" :user1="user" @xiu="handleXiu"></son>
</template>

<script setup lang="ts">
import { ref, watch } from "vue";
// 在setup语法中,只需要导入子组件,就可以渲染,不需要components注册

import son from "./components/son.vue";
const user = ref(100);
const str = ref({
  name: "ddd",
  age: 18,
});
const handleXiu = (val: number) => {
  console.log("子组件传过来的数据", val);
};
</script>

3.8 组件通讯-依赖注入 - provide 和 inject

依赖注入, 可以非常方便的实现 跨层级的 组件通信

<script setup lang="ts">
import { provide, ref } from 'vue'
import Son from './components/Son.vue'
const money = ref(100)
const car = ref('小黄车')

provide('money', money)
provide('car', car)
</script>

<template>
  <h1>根组件-{{ money }} --- {{ car }}</h1>
  <hr />
  <Son></Son>
</template>

子组件 (子孙后代, 都可以拿到这个数据)

<script setup lang="ts">
import { inject, Ref } from 'vue'

const money = inject<Ref<number>>('money')
const car = inject<Ref<string>>('car')

const changeMoney = (m: number) => {
  if (money) {
    money.value = money.value - m
  }
}
</script>
<template>
  <h5>Sun组件--{{ money }} --- {{ car }}</h5>
  <button @click="changeMoney(10)">修改</button>
</template>

如果希望子传父, 可以 provide 传递一个方法

子组件

<script setup lang="ts">
import { inject, Ref } from 'vue'

const money = inject<Ref<number>>('money')
const car = inject<Ref<string>>('car')
const changeMoney = inject<(m: number) => void>('changeMoney')
</script>

<template>
  <h5>Sun组件--{{ money }} --- {{ car }}</h5>
  <button @click="changeMoney && changeMoney(10)">修改</button>
</template>

父组件

<script setup lang="ts">
import { provide, ref } from 'vue'
import Son from './components/Son.vue'
const money = ref(100)
const car = ref('小黄车')

provide('money', money)
provide('car', car)

const changeMoney = (m: number) => {
  if (money) {
    money.value = money.value - m
  }
}
provide('changeMoney', changeMoney)
</script>

<template>
  <h1>根组件-{{ money }} --- {{ car }}</h1>
  <hr />
  <Son></Son>
</template>

更多推荐