目录
一、创建Vue3工程
(一)、cli
(二)、vite
二、常用Composition API
(一)、setup函数
(二)、ref函数
(三)、reactive函数
(四)、setup注意事项
(五)、计算属性
(六)、watch
(七)、watchEffect函数
(八)、生命周期
1、以配置项的形式使用生命周期钩子
2、组合式api(在setup中使用)
(九)、自定义hook
(十)、toRef、toRefs
三、其他Composition API
(一)、shallowReactive、shallowRef
(二)、readonly 与 shallowReadonly
(三)、toRaw 与 markRaw
(四)、自定义ref(customRef)
(五)、provide、inject
(六)、响应式数据的判断
五、新的组件
(一)、Fragment
(二)、Teleport
(三)、Suspense
六、Vue3的其他改变
(一)、全局API的转移
(二)、data
(三)、过度类名更改
(四)、keyCode
(五)、移除v-on.native
(六)、移除过滤器
一、创建Vue3工程
(一)、cli
创建一个项目 | Vue CLI🛠️ Vue.js 开发的标准工具https://cli.vuejs.org/zh/guide/creating-a-project.html#vue-create
##查看@vue/c1i版本,确保@vue/c1i版本在4.5.8以上
vue --version
#安装或者升级你的@vue/cli
npm install -g @vue/cli
##创建
vue create 项目名
##启动
cd 项目名
npm run serve
(二)、vite
快速上手 | Vue.jsVue.js - 渐进式的 JavaScript 框架https://v3.cn.vuejs.org/guide/installation.html#viteVite中文网下一代前端开发与构建工具https://vitejs.cn
##创建工程
npm init vite-app 项目名
#进入工程目录
cd 项目名
##安装依赖
npm i
##运行
npm run dev
二、常用Composition API
(一)、setup函数
简单演示,下面的写法不对,丢失了响应式。
<template>
<h2>我的名字是{{ name }},年龄是{{ age }}</h2>
</template>
<script>
export default {
name: "HelloWorld",
setup() {
let name = "jack";
let age = 18;
function sayHello() {
console.log("hello");
}
return {
name,
age,
sayHello,
};
},
};
</script>
(二)、ref函数
// 示例,执行changeInfo函数修改信息,响应式数据
import {ref} from 'vue'
export default {
name: 'App',
setup(){
let name = ref('LHD')
let age = ref(19)
let job = ref({
type:'前端工程师',
salary:'15k'
})
function changeInfo(){
name.value = 'DHL',
age.value = '20',
job.value.type = '搬砖工程师',
job.value.salary = '10k'
}
return{
name,
age,
job,
changeInfo
}
}
}
(三)、reactive函数
// 先引入reactive
import {reactive} from 'vue'
// 2的示例,setup函数中改成这样
let person = reactive({
name:'LHD',
age:'19',
job:{
type:'工程师',
salary:'20k'
},
hobby:['Study','Video Game']
})
function changeInfo(){
person.name = 'DHL',
person.age = '20',
person.job.type = '搬砖工程师',
person.job.salary = '10k',
person.hobby[1] = 'fly'
}
return{
person,
changeInfo
}
(四)、setup注意事项
(五)、计算属性
(六)、watch
//情况一:监视ref定义的响应式数据
watch(sum,(newValue,oldValue)=>{
console.log('sum变化了',newValue,oldValue)
},{immediate:true})
//情况二:监视多个ref定义的响应式数据
watch([sum,msg],(newValue,oldValue)=>{
console.log('sum或msg变化了',newValue,oldValue)
})
/* 情况三:监视reactive定义的响应式数据
若watch监视的是reactive定义的响应式数据,则无法正确获得oldValue!!
若watch监视的是reactive定义的响应式数据,则强制开启了深度监视
*/
watch(person,(newValue,oldValue)=>{
console.log('person变化了',newValue,oldValue)
},{immediate:true,deep:false}) //此处的deep配置不再奏效
//情况四:监视reactive定义的响应式数据中的某个属性
watch(()=>person.job,(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{immediate:true,deep:true})
//情况五:监视reactive定义的响应式数据中的某些属性
watch([()=>person.job,()=>person.name],(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{immediate:true,deep:true})
//特殊情况
watch(()=>person.job,(newValue,oldValue)=>{
console.log('person的job变化了',newValue,oldValue)
},{deep:true}) //此处由于监视的是reactive素定义的对象中的某个属性,所以deep配置有效
(七)、watchEffect函数
//watchEffect所指定的回调中用到的数据只要发生变化,则直接重新执行回调。
watchEffect(()=>{
const x1 = sum.value
const x2 = person.age
console.log('watchEffect配置的回调执行了')
})
(八)、生命周期
1、以配置项的形式使用生命周期钩子
与setup平级
2、组合式api(在setup中使用)
(九)、自定义hook
src/hooks/usePoint.js
///得到鼠标点的api
import { reactive, onMounted, onBeforeUnmount } from "vue";
export default function usePoint(){
//响应式数据
let point = reactive({
x: 0,
y: 0
});
//方法
const savePoint = event => {
console.log(event.pageX, event.pageY);
point.x = event.pageX;
point.y = event.pageY;
};
//生命周期
onMounted(() => {
window.addEventListener('click', savePoint)
});
onBeforeUnmount(() => {
//在卸载之前取消事件的监听
window.removeEventListener('click', savePoint);
});
return point;
}
src/components/Demo.vue
<template>
<h1>当前求和为:{{ sum }}</h1>
<button @click="sum++">点我加一</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);
//复用自定义hooks
const point = usePoint();
//返回一个对象
return {
sum,
point
}
},
}
</script>
<style>
</style>
(十)、toRef、toRefs
<template>
<h4>{{ person }}</h4>
<h2>姓名:{{ name }}</h2>
<h2>年龄:{{ age }}</h2>
<h2>薪资:{{ salary }}K</h2>
<button @click="name = name + '~'">修改姓名</button>
<button @click="age++">增长年龄</button>
<button @click="salary++">增长薪资</button>
</template>
<script>
import { ref, reactive, toRef, toRefs} from 'vue';
export default {
name: 'Demo',
setup(){
let person = reactive({
name: '张三',
age: 18,
job:{
j1:{
salary: 20
}
}
});
//ref类型的值在模板里使用是不需要.value来取的
const name1 = person.name //注意输出字符串,并不是响应式的数据
console.log('@@@@@', name1);
const name2 = toRef(person,name); //RefImpl 这里的name2与person.name是完全一模一样的(你改这里的name2与你改person.name是一码事),且数据还是响应式的
console.log('####', name2);
const x = toRefs(person);
console.log(x);
//返回一个对象(toRef是引用 name就是person.name且为响应式)
//toRef处理一个,而toRefs处理一群
//大白话:toRef(s)就是方便我们把响应式数据(ref,reactive)展开丢出去,方便在模版中应用
return {
person,
// name: toRef(person, "name"),
// age: toRef(person, "age"),
// salary: toRef(person.job.j1, "salary")
...toRefs(person),
salary: toRef(person.job.j1, 'salary') //toRef可以与toRefs连用,更加方便
};
//注意千万不能这样写
//一旦这样写就与元数据分离了,改name不会引起person.name的变化(因为ref把name值包装成了一个refImpl对象)
// return {
// person,
// name: ref(person.name),
// age: ref(person.age),
// salary: ref(person.job.j1.salary)
// };
}
}
</script>
<style>
</style>
三、其他Composition API
(一)、shallowReactive、shallowRef
(二)、readonly 与 shallowReadonly
(三)、toRaw 与 markRaw
<template>
<h2>当前求和为:{{ sum }}</h2>
<button @click="sum++">sum+1</button>
<hr/>
<h2>姓名:{{ name }}</h2>
<h2>年龄:{{ age }}</h2>
<h2>薪资:{{ job.j1.salary }}K</h2>
<h3 v-show="person.car">座驾信息:{{ person.car }}</h3>
<button @click="name = name + '~'">修改姓名</button>
<button @click="age++">增长年龄</button>
<button @click="job.j1.salary++">增长薪资</button>
<button @click="showRawPerson">输出最原始的person</button>
<button @click="addCar">给人添加一台车</button>
<button @click="person.car && (person.car.name +='!') ">换车名</button>
<button @click="changePrice">换价格</button>
</template>
<script>
import {markRaw, reactive, ref, toRaw, toRefs} from 'vue';
export default {
name: 'Demo',
setup(){
let sum = ref(0);
let person = reactive({
name: '张三',
age: 18,
job:{
j1:{
salary: 20
}
}
});
//ref reactive(响应式)
const showRawPerson = () => {
const p = toRaw(person);
// console.log(person); //proxy代理对象 Proxy {....}
p.age++; //注意此时页面不会再发生变化了,普普通通的对象不是响应式
console.log(p); //原始对象数据 {....}
// const sum = toRaw(sum);
// console.log(sum); //undefined //这条路走不通,toRaw只处理reactive对象
}
const addCar = () => {
person.car = markRaw({
name: 'benz',
price: 40
}); //在响应式的对象身上添加任何属性都是响应式的,经过markRaw一包装就变成最原始的数据就不会再做响应
}
const changePrice = () => {
person.car?.price && person.car.price++;
console.log(person?.car?.price);
}
return {
sum,
person,
...toRefs(person),
showRawPerson,
addCar,
changePrice
};
}
}
</script>
<style>
</style>
(四)、自定义ref(customRef)
需求
<template>
<input type="text" v-model="keyword">
<h3>{{keyword}}</h3>
</template>
<script>
import {ref,customRef} from 'vue'
export default {
name:'Demo',
setup(){
// let keyword = ref('hello') //使用Vue准备好的内置ref
//自定义一个myRef
function myRef(value,delay){
let timer
//通过customRef去实现自定义
return customRef((track,trigger)=>{
return{
get(){
track() //告诉Vue这个value值是需要被“追踪”的
return value
},
set(newValue){
clearTimeout(timer)
timer = setTimeout(()=>{
value = newValue
trigger() //告诉Vue去更新界面
},delay)
}
}
})
}
let keyword = myRef('hello',500) //使用程序员自定义的ref
return {
keyword
}
}
}
</script>
(五)、provide、inject
(六)、响应式数据的判断
- isRef: 检查一个值是否为一个 ref 对象
- isReactive: 检查一个对象是否是由 reactive 创建的响应式代理
- isReadonly: 检查一个对象是否是由 readonly 创建的只读代理
- isProxy: 检查一个对象是否是由 reactive 或者 readonly 方法创建的代理
五、新的组件
(一)、Fragment
- 在Vue2中: 组件必须有一个根标签
- 在Vue3中: 组件可以没有根标签, 内部会将多个标签包含在一个Fragment虚拟元素中
- 好处: 减少标签层级, 减小内存占用
(二)、Teleport
什么是Teleport?—— Teleport
是一种能够将我们的组件html结构移动到指定位置的技术。
(三)、Suspense
六、Vue3的其他改变
(一)、全局API的转移
Vue 2.x 有许多全局 API 和配置。
-
例如:注册全局组件、注册全局指令等
//注册全局组件
Vue.component('MyButton', {
data: () => ({
count: 0
}),
template: '<button @click="count++">Clicked {{ count }} times.</button>'
})
//注册全局指令
Vue.directive('focus', {
inserted: el => el.focus()
}
Vue3.0中对这些API做出了调整:
-
将全局的API,即:
Vue.xxx
调整到应用实例(app
)上
(二)、data
data选项应始终被声明为一个函数。
(三)、过度类名更改
Vue2.x写法
.v-enter,
.v-leave-to {
opacity: 0;
}
.v-leave,
.v-enter-to {
opacity: 1;
}
Vue3.x写法
.v-enter-from,
.v-leave-to {
opacity: 0;
}
.v-leave-from,
.v-enter-to {
opacity: 1;
}
(四)、keyCode
移除 keyCode作为 v-on 的修饰符,同时也不再支持config.keyCodes
(五)、移除v-on.native
移除 v-on.native
修饰符
父组件中绑定事件
<my-component
v-on:close="handleComponentEvent"
v-on:click="handleNativeClickEvent"
/>
子组件中声明自定义事件
<script>
export default {
emits: ['close']
}
</script>