使用社交账号登录
最近正在学习 Vue3,尝试把一些重点和踩过的坑给记录下来。
首先我们使用npm init vue@latest来创建一个 Vue3 项目,本文所使用的是 Ts+Vite 的组合,开发工具为 Vscode,Vscode 推荐使用插件Vue Language Features(Volar),这个插件改过名称,实际就是官方推荐的 Volar。另外请关闭 Vetur 等连体插件,因为 Volar 已经集成 Vetur 的功能,而且 Vetur 在使用script setup 语法糖导入组件时会报其未使用的错误。
如果你使用的是 Chrome 浏览器的话可以安装Vue.js devtools(记得先关闭 Vue2 的扩展)



Vue3 一个很重要的特性那便是从选项式 API -> 组合式 API的转变, 虽然选项式 API 使用 (data、computed、methods、watch) 组件选项来组织逻辑通常都很有效,但是当我们的组件开始变得更大时,逻辑关注点的列表也会增长,这会导致组件难以阅读和理解,从而使项目变得越来越难以维护(就是选项式 API 逻辑太分散了,项目做大后不利于维护)。
这次新增加的组合式 API 中,它将同一个功能的逻辑和数据放置在了一起,使同一个的功能代码更加聚合。

因此在 Vue3.0 版本中组合式 API 便出现 setup 函数的写法
会发现最终输出的结果为undefined和beforeCreate,我们可以得出如下结论
setup 函数在任何生命周期函数之前执行
setup 函数中你应该避免使用 this,因为它不会找到组件实例
你会发现1顺利的在你屏幕上显示出来,但是你无论怎么按 button 你的数据都不会发生变化,我们可以得出如下结论
注意:但是如果你在 Vscode 中如此输入代码的话,template 模板中可能会报找不到名称“xxxx”的错误,这是因为在 Vue3.2 中出现了script setup 语法糖的写法导致数值无法被 Volar 读取(下方为案例 script setup 语法糖方式的重写)。
可以很明显的发现script setup 语法糖有着更少的样板内容,更简洁的代码,因此我们接下来的代码都会以script setup 语法糖方式来书写。
我们还是使用上方累加的例子,如下我们把它改成响应式的
我们用 reactive 创建一个引用数据类型的响应式数据,并通过点击按钮改变它的值
value响应式 API 中 computed 和之前的 组合式 API 的 computed 选项用法类似,但需要先引入:import { computed } from "vue"
import { computed } from "vue"watch 函数用于监听响应式数据的变化,下面的示例演示了如何使用watch
import { watch } from "vue"在 <script setup> 中必须使用 defineProps 和 defineEmits API 来声明 props 和 emits 。因为我们使用了 Typescript,所以我们可以尝试使用纯类型声明来声明 props 和 emits
子组件
父组件
最终结果如下图

defineProps 和 defineEmits 都是只在 <script setup> 中才能使用的编译器宏。他们不需要导入且会随着 <script setup> 处理过程一同被编译掉。defineProps 和 defineEmits 在选项传入后,会提供恰当的类型推断。withDefaults可以给props提供默认值//undefined //beforeCreate
<script lang="ts">
export default {
setup() {
console.log(this);
},
beforeCreate() {
console.log("beforeCreate");
},
};
</script>
<script lang="ts">
export default {
setup() {
let count = 1;
return {
count,
};
},
};
</script>
<template>
<h1>{{count}}</h1>
<button @click="count++">+1</button>
</template>
//与上方代码完全相同
<script setup lang="ts">
let count = 1;
</script>
<template>
<h1>{{ count }}</h1>
<button @click="count++">+1</button>
</template>
<script setup lang="ts">
import { ref } from 'vue';
let count = ref(1)
count.value++
</script>
<template>
<h1>{{ count }}</h1>
<button @click="count++">+1</button>
</template>
<style>
<script setup lang="ts">
import { reactive } from "vue";
const person = reactive({
name: "suemor",
age: 18,
});
const changePerson = () => {
(person.name = "小杰"), (person.age = 28);
};
// const name = reactive('小黄') 无效写法
</script>
<template>
<button @click="changePerson">点我改变person属性</button>
<ul>
<li v-for="(item, index) in person" :key="index">{{item}}</li>
</ul>
</template>
<script setup lang="ts">
import { computed, ref } from 'vue';
const num1 = ref(1)
const num2= ref(1)
const sum = computed(()=>num1.value + num2.value)
</script>
<template>
<h1>{{sum}}</h1>//2
</template>
<style>
<script setup lang="ts">import {watch,reactive, ref } from 'vue';
const person = ref('')
watch(person,(oldValue,newValue)=>{
console.log(oldValue,newValue);
})
</script>
<template>
<input v-model="person" type="text" placeholder="请输入姓名">
</template>
<style>
<template>
<h1>{{ props.msg }}</h1>
<button @click="handleClick">点击我调用父组件方法</button>
</template>
<script setup lang="ts">
//props
const props = withDefaults(
defineProps<{
msg?: string;
}>(),
{
msg: "我是默认值",
}
);
//emits
const emit = defineEmits<{
(e: "on-change", data: string): void;
}>();
const handleClick = () => emit("on-change", "父组件方法被调用了");
</script>
<script setup lang="ts">
import { ref } from "vue";
import TestPropsEmit from "./views/TestPropsEmit.vue";
const msg = ref("我是来自父组件的值");
const handleChange = (data: string) => {
console.log(data);
};
</script>
<template>
<TestPropsEmit :msg="msg" @on-change="handleChange" />
</template>