PS D:\web\vue3> vue --version
@vue/cli 5.0.6
PS D:\web\vue3> vue create vue3_test
什么是vite? - 新一代前端构建工具
传统构建与vite构建对比图

创建步骤
## 创建工程
npm init vite-app <project-name>
## 进入工程目录
cd <project-name>
## 安装依赖
npm install
## 运行
npm run dev
具体应用
PS D:\web\vue3> npm init vite-app vue3_test_vite
Need to install the following packages:
create-vite-app@1.21.0
Ok to proceed? (y) y
npm WARN deprecated create-vite-app@1.21.0: create-vite-app has been deprecated. run `npm init @vitejs/app` or `yarn create @vitejs/app` instead.
Scaffolding project in D:\web\vue3\vue3_test_vite...
Done. Now run:
cd vue3_test_vite
npm install (or `yarn`)
npm run dev (or `yarn dev`)
PS D:\web\vue3>
PS D:\web\vue3> cd .\vue3_test_vite\
PS D:\web\vue3\vue3_test_vite> npm install
added 290 packages in 18s
PS D:\web\vue3\vue3_test_vite> npm run dev
> vue3_test_vite@0.0.0 dev
> vite
[vite] Optimizable dependencies detected:
vue
Dev server running at:
> Network: http://10.33.201.152:3000/
> Local: http://localhost:3000/
1、尽量不要与Vue2.x配置混用
- Vue2.x配置(data、methods、computed…)中可以访问到setup中的属性、方法
- 但在setup中不能访问到Vue2.x配置(data、methods、computed…)
- 如果有重名,setup优先
2、setup不能是一个async函数,因为返回值不再是return的对象,而是promise,模板看不到return对象中的属性,后期也可以返回一个Promise实例,但需要Suspense和异步组件的配合
<template>
<h1>一个人的信息</h1>
<h2>姓名:{{name}}</h2>
<h2>年龄:{{age}}</h2>
<button @click="sayHello">说话</button>
</template>
<script>
import {h} from 'vue'
export default {
name: "App",
setup() {
// 数据 定义了数据直接使用即可
let name = '张三'
let age = 18
// 方法
function sayHello() {
alert(`我叫${name},我今年${age}岁了,你好啊!`)
}
/*
setup函数的两种返回值
- 1、若返回一个对象,则对象中的属性、方法、在模板中均可以直接使用(重点关注)
- 2、若返回一个渲染函数,则可以自定义渲染内容(了解)
*/
// 1 返回一个对象(常用)
/* return {
name,
age,
sayHello
} */
// 2 返回一个渲染函数(了解)
// return () => {h('h1', '尚硅谷')}
return () => h('h1', '尚硅谷')
/*
注意点:
1、尽量不要与Vue2.x配置混用
- Vue2.x配置(data、methods、computed...)中可以访问到setup中的属性、方法
- 但在setup中不能访问到Vue2.x配置(data、methods、computed...)
- 如果有重名,setup优先
2、setup不能是一个async函数,因为返回值不再是return的对象,而是promise,模板看不到return对象中的属性
*/
}
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
const xxx = ref(initValue)
① 创建一个包含响应式数据的引用对象(reference对象,简称ref对象)
② JS中操作数据:xxx.value
③ 模板中读取数据:不需要.value,直接
<div>{{xxx}}</div>
备注:
Object.defineProperty()的get与set完成的。reactive函数。ref函数_处理基本类型 && ref函数_处理对象类型
<template>
<h1>一个人的信息</h1>
<h2>姓名:{{ name }}</h2>
<h2>年龄:{{ age }}</h2>
<h2>工作种类:{{ job.type }}</h2>
<h2>工作薪水:{{ job.salary }}</h2>
<button @click="changeInfo">更新修改人的信息</button>
</template>
<script>
import { ref } from "vue";
export default {
name: "App",
setup() {
// 数据
let name = ref("张三");
let age = ref(18);
let job = ref({
type: "前端工程师",
salary: "30k",
});
// 方法
function changeInfo() {
name.value = "李四";
age.value = 48;
// console.log(name, age);
// console.log(job.value)
job.value.type = "UI设计师";
job.value.salary = "60k";
}
return {
name,
age,
job,
changeInfo,
};
},
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
ref函数)const 代理对象= reactive(源对象)接收一个对象(或数组),返回一个代理对象(Proxy的实例对象,简称proxy对象)<template>
<h1>一个人的信息</h1>
<h2>姓名:{{ person.name }}</h2>
<h2>年龄:{{ person.age }}</h2>
<h2>工作种类:{{ person.job.type }}</h2>
<h2>工作薪水:{{ person.job.salary }}</h2>
<h2>爱好{{ person.hobby }}</h2>
<h2>测试的数据c:{{ person.job.a.b.c }}</h2>
<button @click="changeInfo">更新修改人的信息</button>
</template>
<script>
import { reactive } from "vue";
export default {
name: "App",
setup() {
// 我们在书写的时候有一个套路 - 我们一般将组件所用到的数据封装到一个对象当中
/* let preson = {
name: "张三",
age: 18,
job: {
type: "前端工程师",
salary: "30k",
a: {
b: {
c: 666,
},
},
},
hobby:['抽烟', '喝酒', '烫头']
};
let p = reactive(preson) */
let person = reactive({
name: "张三",
age: 18,
job: {
type: "前端工程师",
salary: "30k",
a: {
b: {
c: 666,
},
},
},
hobby: ["抽烟", "喝酒", "烫头"],
});
// 方法
function changeInfo() {
person.name = "李四";
person.age = 48;
person.job.type = "UI设计师";
person.job.salary = "60k";
person.job.a.b.c = 999;
person.hobby[0] = "学习";
}
return {
person,
changeInfo,
};
},
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
上面提到的:基本类型不要用它,要用ref函数
实现原理
Object.defineProperty()对属性的读取、修改进行拦截(数据劫持)Object.defineProperty(data, 'count', {
get () {},
set () {}
})
存在问题
通过demo来演示vue存在的问题,在App组件中进行演示
<template>
<div>
<h1>我是Vue2写的效果</h1>
<h2 v-show="person.name">姓名:{{ person.name }}</h2>
<h2>年龄:{{ person.age }}</h2>
<h2 v-show="person.sex">性别:{{ person.sex }}</h2>
<h2>我的爱好是:{{ person.hobby }}</h2>
<button @click="addSex">添加一个sex属性</button>
<button @click="deleteName">删除name属性</button>
<button @click="updateHobby">修改第一个爱好</button>
</div>
</template>
<script>
import Vue from "vue";
export default {
name: "App",
data() {
return {
person: {
name: "张三",
age: 18,
hobby: ["学习", "爱好"],
},
};
},
methods: {
addSex() {
// console.log("添加前", this.person.sex); // undefined
// this.person.sex = "女";
// console.log("添加后", this.person.sex); // 女 属性值是修改了,但是页面没有呈现出来
// 在vue2中也可以修复这种问题,使用this.$set() 来解决
this.$set(this.person, "sex", "女"); // 在Vue3项目中直接书写是不行的
// Vue.set(this.person, "sex", "女"); // 在Vue3项目中直接书写是不行的
},
deleteName() {
// console.log(this.person.name);
// delete this.person.name;
// console.log(this.person.name);
// 上面也是删除了,但是在页面中没有呈现出来
// 也有相应的解决办法
// this.$delete(this.person, 'name')
Vue.delete(this.person, "name");
},
updateHobby() {
// this.person.hobby[0] = "抽烟";
// console.log(this.person.hobby) 确实修改了,但是页面不进行展示
// this.$set(this.person.hobby, 0, '逛街') 可以
// 调用数组身上的变更方法,
this.person.hobby.splice(0, 1, '逛街')
},
},
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
注意
let a = [1, 2, 3, 4, 5]
a.splice(2, 0, 'a', 'b') // [], a现在是[1, 2, 'a', 'b', 3, 4, 5]
a.splice(2, 2, [1, 2], 3) // ['a', 'b'], a现在是[1, 2, [1, 2], 3, 3, 4, 5]
模拟Vue2的响应式原理
<script>
// 源数据
let person = {
name: '张三',
age: 18
}
// 模拟Vue2中响应式原理
/* let p = {}
Object.defineProperty(p, 'name', {
configurable:true, // 配置为true表示是可删除的
get() { // 有人读取name时调用
return person.name
},
set(value) { // 有人修改name时调用
console.log('有人修改了name属性,我发现了,我要去更新界面!')
person.name = value
}
})
Object.defineProperty(p, 'age', {
get() { // 有人读取age时调用
return person.age
},
set(value) { // 有人修改age时调用
console.log('有人修改了age属性,我发现了,我要去更新界面!')
person.age = value
}
}) */
</script>
使用Vue3来实现响应式的原理: - 很好的解决了Vue2遗留下来的问题
模拟Vue3的响应式原理
<script>
// 源数据
let person = {
name: '张三',
age: 18
}
// 模拟Vue3中实现响应式 window.Proxy
// Proxy 代理
// 真想实现响应式,必须捕获到数据的修改操作
/*
person - 源数据
p - 代理数据
*/
const p = new Proxy(person, {
// 有人读取p的某个属性时调用
get(target, propName) {
// console.log('有人读取了p身上的某个属性', target, propName)
console.log(`有人读取了p身上的${propName}属性`)
return target[propName]
},
// 有人修改p的某个属性时或给p追加某个属性时调用
set(target, propName, value) {
// console.log(target, propName, value)
console.log(`有人修改了p身上的${propName}属性,我要去更新界面了`)
target[propName] = value
},
// 有人删除p的某个属性时调用
deleteProperty(target, propName) {
console.log(`有人删除了p身上的${propName}属性,我要去更新界面了`)
return delete target[propName]
}
})
</script>
reactive转为代理对象。Object.defineProperty()的get与set来实现响应式(数据劫持)。.value,读取数据时模板中直接读取不需要.value。.value。当我们所需要配置的数据有很多种的时候,我们可以封装到一个对象中,如果有很多不同类型的数据对象,我们可以在对象里面接着进行封装不同的对象,然后将数据data返回即可
let data = reactive({
person:{},
student:{}
})
return {
data
}
① attrs: 值为对象,包含:组件外部传递过来,但没有在props配置中声明的属性, 相当于
this.$attrs。
② slots: 收到的插槽内容, 相当于this.$slots。
③ emit: 分发自定义事件的函数, 相当于this.$emit。
父组件
子组件
一个人的信息
姓名:{{person.name}}
年龄:{{person.age}}
{{msg}}
简写形式
person.fullName = computed(() => {
return person.firstName + "-" + person.lastName;
});
完整版写法 - 里面有相应的set以及get方法
person.fullName = computed({
get() {
return person.firstName + "-" + person.lastName;
},
set(value){
const nameArr = value.split('-')
person.firstName = nameArr[0]
person.lastName = nameArr[1]
}
});
一个人的信息
姓:
名:
{ fullName }} -->
全名: {{ person.fullName }}
两个小坑
回顾Vue2中的watch的使用
watch: {
// 简写形式
/* sum(newValue, oldValue) {
console.log("sum的值变化了");
}, */
// 完整版写法 可以配置一些属性
/* sum: {
immediate: true, // 一上来就进行监听一次
deep: true, // 深度监视 数据的层级是很多层的 因为默认是开启一个浅层次的监视
handler(newValue, oldValue) {
console.log("sum的值变化了", newValue, oldValue);
},
}, */
},
1、情况一:监视ref定义的响应式数据
watch(sum,(newValue,oldValue)=>{
console.log('sum变化了',newValue,oldValue)
},{immediate:true})
2、情况二:监视多个ref定义的响应式数据
watch([sum,msg],(newValue,oldValue)=>{
console.log('sum或msg变化了',newValue,oldValue)
})
3、情况三:监视reactive定义的响应式数据
watch(person,(newValue,oldValue)=>{
console.log('person变化了',newValue,oldValue)
},{immediate:true,deep:false}) //此处的deep配置不再奏效
4、情况四:监视reactive定义的响应式数据中的某个属性
watch(()=>person.age,(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{immediate:true,deep:true})
5、情况五:监视reactive定义的响应式数据中的某些属性
watch([()=>person.name,()=>person.age],(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{immediate:true,deep:true})
6、特殊情况
watch(()=>person.job,(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{deep:true}) //此处由于监视的是reactive素定义的对象中的某个属性,所以deep配置有效
总DEMO
当前求和为:{{ sum }}
当前的信息为 {{ msg }}
姓名:{{ person.name }}
年龄:{{ person.age }}
薪资:{{ person.job.j1.salary }}K
ref定义的数据,在进行监测的时候,不能进行.value 操作,watch监测的不是一个具体的值,而应该是一个结构


声明周期图

注意点
beforeDestroy改名为beforeUnmountdestroyed改名为unmounted
beforeCreate===>setup()created=======>setup()beforeMount===>onBeforeMountmounted=======>onMountedbeforeUpdate===>onBeforeUpdateupdated=======>onUpdatedbeforeUnmount==>onBeforeUnmountunmounted=====>onUnmounted
<template>
<button @click="isShowDemo = !isShowDemo">切换隐藏/显示</button>
<Demo v-if="isShowDemo"></Demo>
</template>
<script>
import { ref } from "vue";
import Demo from "./components/Demo.vue";
export default {
name: "App",
components: { Demo },
setup() {
let isShowDemo = ref(true);
return {
isShowDemo,
};
},
};
</script>
<style>
</style>
子组件
<template>
<h1>当前求和为:{{ sum }}</h1>
<button @click="sum++">点我+1</button>
</template>
<script>
import {
ref,
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
} from "vue";
export default {
name: "Demo",
setup() {
console.log('setup')
// 数据
let sum = ref(0);
onBeforeMount(() => {
console.log('onBeforeMount')
})
// 通过组合式API的形式去使用生命周期钩子
// 返回一个对象(常用)
return {
sum,
};
},
// 通过配置项的形式使用声明周期钩子
// #region
/* beforeCreate() {
console.log("---beforeCreate---");
},
created() {
console.log("---created---");
},
beforeMount() {
console.log("beforeMount");
},
mounted() {
console.log("mounted");
},
beforeUpdate() {
console.log("beforeUpdate");
},
updated() {
console.log("updated");
},
beforeUnmount() {
console.log("beforeUnmount");
},
unmounted() {
console.log("unmounted");
}, */
// #endregion
};
</script>
<style>
</style>
Vue3中书写生命周期钩子有两种形式
想要复用的代码书写在hook文件夹中
比如实现一个鼠标打点,显示出鼠标具体位置的方法,书写的方法要暴露出去 里面可以书写相应的函数方法
import { reactive, onMounted, onBeforeUnmount } from "vue";
export default function() {
// 实现鼠标打点相关的数据
let point = reactive({
x: 0,
y: 0,
})
// 实现鼠标打点相关的方法
function savePoint(event) {
point.x = event.pageX;
point.y = event.pageY;
}
// 只要demo组件一挂载的时候,就立刻执行
// 实现鼠标打点的相关方法
onMounted(() => {
window.addEventListener("click", savePoint);
})
onBeforeUnmount(() => {
window.removeEventListener("click", savePoint);
})
return point
}
在组件中调用刚才在hooks中定义的方法
<template>
<h1>当前求和为:{{ sum }}</h1>
<button @click="sum++">点我+1</button>
<hr />
<h2>当前点击时鼠标的坐标为:x:{{ point.x }}, y:{{ point.y }}</h2>
</template>
<script>
import { ref } from "vue";
import usePoint from '../hooks/usePoint'
export default {
name: "Demo",
setup() {
// 数据
let sum = ref(0);
let point = usePoint()
return {
sum,
point
};
},
};
</script>
<style>
</style>
const name = toRef(person,'name')toRefs与toRef功能一致,但可以批量创建多个 ref 对象,语法:toRefs(person)组件示例
<template>
<h2>姓名:{{ name }}</h2>
<h2>年龄:{{ age }}</h2>
<h2>薪资:{{ job.j1.salary }}K</h2>
<button @click="name += '~'">修改姓名</button>
<button @click="age++">修改年龄</button>
<!-- <button @click="salary++">修改薪资</button> -->
<button @click="job.j1.salary++">修改薪资</button>
</template>
<script>
import { reactive, toRef, toRefs } from "vue";
export default {
name: "Demo",
setup() {
// 切记setup() 里面的箭头函数是undefined
// 数据
let person = reactive({
name: "张三",
age: 18,
job: {
j1: {
salary: 20,
},
},
});
// const name1 = person.name
// console.log('%%%', name1)
// const name2 = toRef(person, 'name') // ObjectRefImpl 中间人ref可以做响应式
// console.log('####', name2)
const x = toRefs(person)
console.log('****', x)
return {
person,
/*
toRef是引用一个 有引用关系,这一点很关键!
ref是复制一个
*/
// name:toRef(person, 'name'),
// age:toRef(person, 'age'),
// // 第一个参数传入一个对象即可
// salary:toRef(person.job.j1, 'salary')
...toRefs(person) // ...toRefs只是把第一层拆了出来作为一个对象
};
},
};
</script>
<style>
</style>
什么时候使用 ?
组件示例
<template>
<h4>当前的x.y的值是:{{ x.y }}</h4>
<!-- <button @click="x.y++">点我x+1</button> -->
<button @click="x={y:888}">点我替换</button>
<hr />
<h2>{{ person }}</h2>
<h2>姓名:{{ name }}</h2>
<h2>年龄:{{ age }}</h2>
<h2>薪资:{{ job.j1.salary }}K</h2>
<button @click="name += '~'">修改姓名</button>
<button @click="age++">修改年龄</button>
<!-- <button @click="salary++">修改薪资</button> -->
<button @click="job.j1.salary++">修改薪资</button>
</template>
<script>
import { ref, reactive, toRef, toRefs, shallowReactive, shallowRef } from "vue";
export default {
name: "Demo",
setup() {
// 切记setup() 里面的箭头函数是undefined
// 数据
// shallowReactive只考虑第一层数据的响应式
let person = shallowReactive({
name: "张三",
age: 18,
job: {
j1: {
salary: 20,
},
},
});
// let x = ref(0);
// 第一层肯定是响应式的 就是看里面的,你会不会进行深挖的操作
let x = shallowRef({
y:0
});
return {
x,
person,
...toRefs(person), // ...toRefs只是把第一层拆了出来作为一个对象
};
},
};
</script>
<style>
</style>
组件示例
<template>
<h4>当前求和为:{{ sum }}</h4>
<button @click="sum++">点我x+1</button>
<hr />
<h2>姓名:{{ name }}</h2>
<h2>年龄:{{ age }}</h2>
<h2>薪资:{{ job.j1.salary }}K</h2>
<button @click="name += '~'">修改姓名</button>
<button @click="age++">修改年龄</button>
<button @click="job.j1.salary++">修改薪资</button>
</template>
<script>
import { ref, reactive, toRefs, readonly, shallowReadonly } from "vue";
export default {
name: "Demo",
setup() {
let sum = ref(0);
let person = reactive({
name: "张三",
age: 18,
job: {
j1: {
salary: 20,
},
},
});
// person = readonly(person) // 前面用readonly进行接收了
// 有可能数据是别的组件的,你可以收到,但是你不能修改
person = shallowReadonly(person)
// sum = readonly(sum)
// sum = shallowReadonly(sum)
return {
sum,
...toRefs(person), // ...toRefs只是把第一层拆了出来作为一个对象
};
},
};
</script>
<style>
</style>
toRaw
reactive生成的响应式对象转为普通对象。markRaw
组件示例
<template>
<h4>当前求和为:{{ sum }}</h4>
<button @click="sum++">点我x+1</button>
<hr />
<h2>姓名:{{ name }}</h2>
<h2>年龄:{{ age }}</h2>
<h2>薪资:{{ job.j1.salary }}K</h2>
<h2 v-show="person.car">座驾信息{{ person.car }}</h2>
<button @click="name += '~'">修改姓名</button>
<button @click="age++">修改年龄</button>
<button @click="job.j1.salary++">修改薪资</button>
<!-- 输出最原始的person -->
<button @click="showRawPerson">输出最原始的person</button>
<button @click="addCar">给人添加一台车</button>
<button @click="person.car.name += '!'">换车名</button>
<button @click="person.car.price++">换车名</button>
<button @click="addPrice">点我变换价格</button>
</template>
<script>
import { ref, reactive, toRefs, toRaw, markRaw } from "vue";
export default {
name: "Demo",
setup() {
let sum = ref(0);
let person = reactive({
name: "张三",
age: 18,
job: {
j1: {
salary: 20,
},
},
// car: {},
});
function showRawPerson() {
const p = toRaw(person); // p不是响应式的了
p.age++; // 无效
// console.log(person)
console.log(p);
}
function addCar() {
let car = { name: "奔驰", price: 40 };
// person.car = car; // 往person中添加的任何东西都是响应式的
person.car = markRaw(car);
}
function addPrice() {
person.car.price += 1;
console.log(person.car.price); // 价格一直在改变,但不是响应式的,页面不进行更新
}
return {
sum,
person, // 将整个person传出去,这个person对象里面的内容变化,页面就会跟着变,因为其是响应式的
...toRefs(person), // ...toRefs只是把第一层拆了出来作为一个对象
showRawPerson,
addCar,
addPrice
};
},
};
</script>
<style>
</style>
App组件
{{ keyWord }}

provide 选项来提供数据,后代组件有一个 inject 选项来开始使用这些数据1. 祖组件中:
```js
setup(){
......
let car = reactive({name:'奔驰',price:'40万'})
provide('car',car)
......
}
2. 后代组件中:
```js
setup(props,context){
......
const car = inject('car')
return {car}
......
}
父组件
我是App组件(祖) {{name}} -- {{price}}
子组件
我是Son组件(孙), {{ car.name }} -- {{ car.price }}
reactive 创建的响应式代理readonly 创建的只读代理reactive 或者 readonly 方法创建的代理
https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bc0be8211fc54b6c941c036791ba4efe~tplv-k3u1fbpfcp-watermark.image
https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/6cc55165c0e34069a75fe36f8712eb80~tplv-k3u1fbpfcp-watermark.image



Teleport 是一种能够将我们的组件html结构移动到指定位置的技术。
我是一个弹窗
父组件
我是Son组件(孙)
子组件
我是一个弹窗
一些内容
一些内容
一些内容
// JS
import {defineAsyncComponent} from 'vue'
const Child = defineAsyncComponent(()=>import('./components/Child.vue'))
② 使用Suspense包裹组件,并配置好default与 fallback
<template>
<div class="app">
<h3>我是App组件</h3>
<Suspense>
<template v-slot:default>
<Child/>
</template>
<template v-slot:fallback>
<h3>加载中.....</h3>
</template>
</Suspense>
</div>
</template>
父组件
<template>
<div class="app">
<h3>我是App组件(祖)</h3>
<Suspense>
<!-- default -->
<template v-slot:default>
<Child />
</template>
<template v-slot:fallback>
<h3>加载中,稍等....</h3>
</template>
</Suspense>
</div>
</template>
<script>
// import Child from "./components/Child.vue"; 静态引入
import { defineAsyncComponent } from "vue";
// 动态引入 异步引入
const Child = defineAsyncComponent(() => import("./components/Child.vue"));
export default {
name: "App",
components: { Child },
};
</script>
<style>
.app {
background-color: gray;
padding: 10px;
}
</style>
子组件
<template>
<div class="child">
<h3>我是Child组件</h3>
{{ sum }}
</div>
</template>
<script>
import { ref } from "vue";
export default {
name: "Child",
async setup() {
let sum = ref(0);
let p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ sum });
}, 1000);
});
return await p; // await 返回成功的结果 可以用Promise
},
};
</script>
<style>
.child {
background-color: skyblue;
padding: 10px;
}
</style>
await返回成功的结果,可以用Promise
//注册全局组件
Vue.component('MyButton', {
data: () => ({
count: 0
}),
template: ''
})
//注册全局指令
Vue.directive('focus', {
inserted: el => el.focus()
}
Vue3.0中对这些API做出了调整:将全局的API,即:Vue.xxx调整到应用实例(app)上
对比图
2.x 全局 API(Vue) | 3.x 实例 API (app) |
|---|---|
| Vue.config.xxxx | app.config.xxxx |
| Vue.config.productionTip | 移除 |
| Vue.component | app.component |
| Vue.directive | app.directive |
| Vue.mixin | app.mixin |
| Vue.use | app.use |
| Vue.prototype | app.config.globalProperties |
Vue2.x的写法
// CSS
.v-enter,
.v-leave-to {
opacity: 0;
}
.v-leave,
.v-enter-to {
opacity: 1;
}
Vue3.x的写法
// CSS
.v-enter-from,
.v-leave-to {
opacity: 0;
}
.v-leave-from,
.v-enter-to {
opacity: 1;
}
config.keyCodesv-on.native修饰符移除该修饰符 Vue3的解决方案
父组件中绑定事件
<my-component
v-on:close="handleComponentEvent"
v-on:click="handleNativeClickEvent"
/>
子组件中声明自定义事件
<script>
export default {
emits: ['close']
}
</script>
使用emits选项去指定自定义事件,没有指定的,默认是原生事件
…
