vue3介绍
vue3变化
1.性能的提升
打包大小减少41%
初次渲染快55%, 更新渲染快133%
内存减少54%
2.源码的升级
使用Proxy代替defineProperty实现响应式
重写虚拟DOM的实现和Tree-Shaking
3.拥抱TypeScript
Vue3可以更好的支持TypeScript
4.新的特性
Composition API(组合API)
setup配置
ref与reactive
watch与watchEffect
provide与inject
5.新的内置组件
Fragment
Teleport
Suspense
6.其他改变
新的生命周期钩子
data 选项应始终被声明为一个函数
移除keyCode支持作为 v-on 的修饰符
组合式API和配置项API
Options API 存在的问题
使用传统OptionsAPI(配置项API)中,新增或者修改一个需求,就需要分别在data,methods,computed里修改 。
组合式API
我们可以更加优雅的组织我们的代码,函数。让相关功能的代码更加有序的组织在一起。
创建vue3项目
1.创建vue3项目有两种方式
1.vue-cli
1.终端输入:vue create vue_cli_test
2.路由选择,选择vue3即可
3.跟之前创建vue2是一样的
2.vite
npm init vue@latest
2.文档:https://cn.vuejs.org/guide/quick-start.html#creating-a-vue-application
vite创建
1.什么是vite?—— 新一代前端构建工具。
2.优势如下:
开发环境中,无需打包操作,可快速的冷启动。
轻量快速的热重载(HMR)。
真正的按需编译,不再等待整个应用编译完成。
3.创建工程
1.npm init vue@latest
2.进入工程目录
cd <project-name>
3.安装依赖
npm install
4.运行
npm run dev
4.工具链,构建工具
工具链(Toolchain)是指一系列相互关联的工具集合,用于支持软件开发和构建过程中的各个环节。它包括了编译器、解释器、链接器、调试器等一系列工具,用于将源代码转换为可执行文件或库文件。
构建工具(Build tool)是工具链中的一部分,用于自动化构建过程,管理源代码的编译、链接和打包等操作。构建工具的主要目标是简化和加速软件构建过程,提高开发效率
npm init vue@latest
setup
1.setup是个函数,以后vue的代码,都写在这里面
2.使用总结
1.里面可以定义变量
2.可以定义函数,可以定义匿名函数
3.如果想在templage中使用,必须return
4.如果要对变量加入响应式,需要使用ref包裹变量
5.data,methods都可以用,但是是setup函数先执行,才走其它
6.template中使用函数,变量,都优先用setup中的
7.setup最先执行,是再生命周期的beforeCreate前执行的,内部没有this,也不能用this了
在setup中定义函数、变量
1.总结:
1.里面可以定义变量
2.可以定义函数,可以定义匿名函数
3.如果想在templage中使用,必须return
4.直接定义的变量和函数,在页面中使用,失去了响应式
2.var:老语法 let:新语法 const:定义常量
<template>
<div class="home">
<p>姓名:{{ name }}</p>
<p>年龄:{{ age }}</p>
<ul v-for="item in hobby">
<li>{{ item }}</li>
</ul>
<p>购物车:</p>
物品名:{{goods_obj.name}}
价格:{{goods_obj.price}}
<br>
<button @click="ClickAdd">点我,价格、年龄加一</button>
</div>
</template>
<script>
export default {
name: 'HomeView',
setup() {
//以后所有vue3的代码,都写在这里面
//原来写在data中定义变量,若果想在view中使用定义的变量,必须return出去
//var:老语法 let:新语法 const:定义常量
let name = 'nana'
let age = 18
let hobby = ['read', 'shopping']
let goods_obj = {'name': '钢笔', 'price': 19}
//定义函数
const ClickAdd=()=>{
goods_obj.price +=1
age += 1
console.log(goods_obj.price,age)
}
return {name, age, hobby, goods_obj,ClickAdd}
//定义的变量和函数,在页面中使用,失去了响应式
}
}
</script>
ref函数
1.作用: 定义一个响应式的数据
2.导入:import {ref} from 'vue'
3.语法: const xxx = ref(initValue)
4.创建一个包含响应式数据的引用对象(reference对象,简称ref对象)。
5.响应数据
JS中操作数据: xxx.value
模板中读取数据: 不需要.value,直接:<div>{{xxx}}</div>
ps:
1. 接收的数据可以是:基本类型、也可以是对象类型。
2.基本类型的数据:响应式依然是靠Object.defineProperty()的get与set完成的
3.对象类型的数据:内部 求助 了Vue3.0中的一个新函数—— reactive函数
使用
<template>
<div class="home">
<p>姓名:{{ name }}</p>
<p>年龄:{{ age }}</p>
<ul v-for="item in hobby">
<li>{{ item }}</li>
</ul>
<p>购物车:</p>
物品名:{{goods_obj.name}}
价格:{{goods_obj.price}}
<br>
<button @click="ClickAdd">点我,年龄加一</button>
<button @click="ClickChange">点我,名字改变</button>
</div>
</template>
<script>
import {ref} from 'vue' //导入
export default {
name: 'HomeView',
setup() {
let name = ref('nana') //变成了响应式
let age = ref(18)
let hobby = ['read', 'shopping']
let goods_obj = {'name': '钢笔', 'price': 19}
const ClickAdd=()=>{
console.log(age,typeof age) //RefImpl ,obj
age.value +=1 //需要 对象.value才能取出来
console.log(age) //RefImpl
}
const ClickChange=()=>{
name.value = 'cx'
}
return {name, age, hobby, goods_obj,ClickAdd,ClickChange}
}
}
</script>
Data、menthods等都可以使用
1..data,methods都可以用,但是是setup函数先执行,才走其它
2.template中使用函数,变量,都优先用setup中的
3..setup最先执行,是再生命周期的beforeCreate前执行的,内部没有this,也不能用this了
<template>
<div class="home">
名字是:{{ name }},年龄是:{{ age }},爱好:{{ hobby }}
<br>
<button @click="handleAdd">点我涨年龄</button>
<br>
<button @click="handleChange">点击变名字</button>
</div>
</template>
<script>
import {ref} from 'vue'
export default {
name: 'HomeView',
data(){
return {
hobby: this.name + '爱打篮球'
}
},
methods: {
handleAdd() {
console.log('methods中的handleAdd')
}
},
setup() {
// 原来的data,method能不能用
let name = 'nana'
let age = 19
const handleAdd = () => {
console.log('setup中的handleAdd')
}
console.log('---',this)
return {name, age,handleAdd}
},
}
</script>
reactive
1.作用: 定义一个对象类型的响应式数据(基本类型不要用它,要用ref函数)
2.语法:const 代理对象= reactive(源对象)接收一个对象(或数组),返回一个代理对象(Proxy的实例对象,简称proxy对象)
3.reactive定义的响应式数据是“深层次的”
4.内部基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据进行操作
4.reactive对比ref
1.从定义数据角度对比:
ref用来定义:基本类型数据
reactive用来定义:对象(或数组)类型数据
2.从原理角度对比:
ref通过Object.defineProperty()的get与set来实现响应式(数据劫持)。
reactive通过使用Proxy来实现响应式(数据劫持), 并通过Reflect操作源对象内部的数据。
3.从使用角度对比:
ref定义的数据:操作数据需要.value,读取数据时模板中直接读取不需要.value。
reactive定义的数据:操作数据与读取数据:均不需要.value。
5.使用方式
let data = reactive({'name': 'nana', 'age': 19, 'hobby': '篮球'})
const handelAdd = () => {
data.age += 1 // 使用reactive包裹的对象,直接当对象用即可
console.log(data)
}
return {data, handelAdd}
使用
<template>
<div class="home">
<p>姓名:{{ name }}</p>
<p>年龄:{{ age }}</p>
<ul v-for="item in hobby">
<li>{{ item }}</li>
</ul>
<p>购物车:</p>
物品名:{{goods_obj.name}}
价格:{{goods_obj.price}}
<br>
<button @click="ClickAdd">点我,年龄加一</button>
<button @click="ClickChange">点我,名字改变</button>
</div>
</template>
<script>
import {ref,reactive} from 'vue'
export default {
name: 'HomeView',
setup() {
let name = ref('nana')
let age = ref(18)
let hobby = ['read', 'shopping']
let goods_obj = reactive({'name': '钢笔', 'price': 19})
//定义函数
const ClickAdd=()=>{
age.value +=1
goods_obj.price +=1
console.log(goods_obj.price,typeof goods_obj.price)
}
const ClickChange=()=>{
name.value = 'cx'
}
return {name, age, hobby, goods_obj,ClickAdd,ClickChange}
}}
</script>
计算、监听属性
computed函数
与Vue2.x中computed配置功能一致
原来写法照常使用
<template>
<div class="home">
<h1>首页</h1>
<input type="text" v-model="name"> -->{{newName}}
<br>
</div>
</template>
<script>
import {ref,computed} from "vue";
export default {
name: 'HomeView',
setup(){
let name = ref('')
//原来写法照常使用
const newName=computed(()=>{
return name.value +'nb'
})
return {name,newName}
}
}
</script>
计算属性可以取值用,还可以改值
<template>
<div class="home">
<h1>首页</h1>
<input type="text" v-model="name"> -->{{newName}}
<br>
<input type="text" v-model="newName">
</div>
</template>
<script>
import {ref,computed} from "vue";
export default {
name: 'HomeView',
setup(){
let name = ref('')
//计算属性可以取值用,还可以改值
const newName = computed({
get(){
// 使用计算属性,会触发这里
return name.value +'=nb'
},
set(value){
// 只要计算属性发生变化,就会执行这里
// 只要newName变了,name理应该也变,需要我们写代码变
console.log(value)
let res = value.split('=')
name.value=res[0]
console.log('计算属性变了,变成', value)
}
})
return {name,newName}
}
}
</script>
watch函数
与Vue2.x中watch配置功能一致
1.两个小“坑”:
1.监视reactive定义的响应式数据时:oldValue无法正确获取、强制开启了深度监视(deep配置失效)。
2.监视reactive定义的响应式数据中某个属性时:deep配置有效。
使用
配置api
<template>
<div class="home">
<h1>首页</h1>
姓名:{{name}}
年龄:{{age}}
<button @click = 'handleChange'>点我,年龄+1</button>
</div>
</template>
<script>
import {ref,reactive} from 'vue'
export default {
name: 'HomeView',
data(){
return {
name:'nana',
age:18
}
},
methods:{
handleChange(){
this.age +=1
}
},
watch:{
age(){
console.log('age变了')
}
}
}
</script>
组合api
监听属性--普通
<template>
<div class="home">
<h1>首页</h1>
姓名:{{name}}
年龄:{{age}}
<button @click = 'handleAdd'>点我,年龄+1</button>
<button @click = 'handleChange'>点我,名字变</button>
</div>
</template>
<script>
import {ref,watch} from 'vue'
export default {
name: 'HomeView',
setup(){
let name = ref('nana')
let age = ref(19)
const handleAdd=()=>{
age.value +=1
}
const handleChange=()=>{
name.value='cx'
}
// 1 监听属性--监听普通变了
// watch(name,()=>{
// console.log('name变了')
// })
//2.监听属性--同时监听多个
watch([name,age],(newValue,oldValue)=>{
console.log('name或age变了',newValue,oldValue) //name或age变了 (2) ['cx', 20] (2) ['nana', 20]
})
return {name,age,handleAdd,handleChange}
}
}
</script>
监听对象的某个属性
<template>
<div class="home">
<h1>首页</h1>
购物详情:{{good_info}}
商品名:{{good_info.title}}
商品价格:{{good_info.price}}
<button @click = 'handleAdd'>点我,价格+1</button>
</div>
</template>
<script>
import {ref,watch,reactive} from 'vue'
export default {
name: 'HomeView',
setup(){
// 监听属性之监听对象中的某个属性
let good_info = reactive({'title':'钢笔','price':99})
const handleAdd=()=>{
good_info.price +=1
}
watch(()=>good_info.price,()=>{
console.log('good_info中的price变了')
})
return {good_info,handleAdd}
// return {name,age,handleAdd,handleChange}
}
}
</script>
生命周期
1.Vue3.0中可以继续使用Vue2.x中的生命周期钩子,但有有两个被更名:
beforeDestroy改名为 beforeUnmount
destroyed改名为 unmounted
2.Vue3.0也提供了 Composition API 形式的生命周期钩子,与Vue2.x中钩子对应关系如下:
1.beforeCreate===>setup()
2.created=======>setup()
3.beforeMount ===>onBeforeMount
4.mounted=======>onMounted
5.beforeUpdate===>onBeforeUpdate
6.updated =======>onUpdated
7.beforeUnmount ==>onBeforeUnmount
8.unmounted =====>onUnmounted
ps:
1.vue3不建议使用 配置项api,建议把所有代码都写在setup函数中
2.可以写配置项api,但是不建议了(以后写组合式aip)
练习
HomeView.vue
<template>
<div class="home">
<h1>首页</h1>
<button @click="handleShow">点我显示</button>
<HelloWorld v-if="show"></HelloWorld>
</div>
</template>
<script>
import HelloWorld from "@/components/HelloWorld.vue";
import {ref} from 'vue'
export default {
name: 'HomeView',
setup() {
let show = ref(true)
const handleShow = () => {
show.value = !show.value
}
return {show,handleShow}
},
components:{
HelloWorld
}
}
</script>
配置项api
HelloWorld.vue
<template>
<div class="hello">
<h1>HelloWorld组件</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data(){
return{
t:null
}
},
beforeCreate() {
console.log('beforeCreate触发了')
},
created(){
this.t = setInterval(()=>{
console.log('ok')
},3000)
console.log('created触发了')
},
beforeMount() {
console.log('beforeMount触发了')
},
mounted() {
console.log('mounted触发了')
},
beforeUpdate() {
console.log('beforeUpdate触发了')
},
updated(){
console.log('updated触发了')
},
beforeUnmount(){
console.log('beforeUnmount触发了')
clearInterval(this.t)
this.t=null
},
unmounted(){
console.log('unmounted触发了')
}
}
</script>
组合式api
<template>
<div class="hello">
<h1>HelloWorld组件</h1>
</div>
</template>
<script>
import {onBeforeMount, onMounted, onBeforeUpdate, onUpdated, onBeforeUnmount, onUnmounted} from "vue";
export default {
name: 'HelloWorld',
setup() {
console.log('vue组件创建了(包含beforeCreate,created)')
//原来写在created中的,直接写在下面即可,直接在这开启定期器
var t = setInterval(() => {
console.log('ok')
}, 3000)
onBeforeMount(() => {
console.log('onBeforeMount')
})
onMounted(() => {
console.log('onMounted')
})
onBeforeUpdate(() => {
console.log('onBeforeUpdate')
})
onUpdated(() => {
console.log('onUpdated')
})
onBeforeUnmount(() => {
console.log('onBeforeUnmount')
clearInterval(t)
t = null
})
onUnmounted(() => {
console.log('onUnmounted')
})
}
}
</script>
toRef
1.作用:创建一个ref对象,其value值指向另一个对象中的某个属性。
2.语法:const name = toRef(person,'name')
3.应用: 要将响应式对象中的某个属性单独提供给外部使用时。
4.扩展:toRefs 与toRef功能一致,但可以批量创建多个 ref 对象,语法:toRefs(person)
5.文档:https://www.jianshu.com/p/0c6ad50a9055
使用
...{对象}--->相当于解压
<template>
<div class="home">
<h1>首页</h1>
姓名{{ data.name }}--->年龄{{ data.age }}
<br>
</div>
</template>
<script>
export default {
name: 'HomeView',
setup() {
let data = {name: 'nana', age: 19}
return {data}
},
}
</script>
<template>
<div class="home">
<h1>首页</h1>
姓名{{ name }}--->年龄{{ age }}
<br>
</div>
</template>
<script>
export default {
name: 'HomeView',
setup() {
let data = {name: 'nana', age: 19}
let b = {...data,gender:'female'}
console.log(b) //{name: 'nana', age: 19, gender: 'female'}
return {...data}
},
}
</script>
在setup函数中return时,使用return {...toRefs(data)},以后再templte中直接使用内层的变量即可
<template>
<div class="home">
<h1>首页</h1>
姓名{{ name }}--->年龄{{ age }}
<br>
<button @click ='handleClick'>点我看美女</button>
<button @click = 'handleAdd'>点我改年龄</button>
</div>
</template>
<script>
import {reactive,toRefs} from "vue";
export default {
name: 'HomeView',
setup() {
let data = reactive({name: 'nana', age: 19})
const handleClick=()=>{
alert('美女')
}
const handleAdd=()=>{
data.age +=1
console.log(data.age)
}
//...toRefs(data) 等同于 {name:data.name,age:data.age}
return {...toRefs(data),handleClick,handleAdd}
},
}
</script>
vue3 setup写法
1.<script setup>表示:这个script里所有东西是setup函数,原来写在setup中的,现在定格写即可
2.组件导入,自动注册
3.不需要return
4.照样写:watch,computed,生命周期钩子,组件导入,自动注册
<script setup>
//组件导入,自动注册
import {ref} from 'vue'
import HelloWorld from "../components/HelloWorld.vue";
let name = ref('nana')
//不需要return
const handelClick=()=>{
name.value='cx'
}
</script>
<template>
<div>
<h1>首页</h1>
{{name}}
<br>
<button @click="handelClick">点我,变名字</button>
<HelloWorld msg="nana"> </HelloWorld>
</div>
</template>