Vue3 vs Vue2
一、速度更快 1.5-2倍
1、编译速度 2、运行速度
3、计算(效率)速度 ** diff算法->静态提升**
二、体积减少
tree-shaking webpack插件
vue2 130.01k vue3 113.37k
三、用Vue创建项目体验一下。
①首先创建淘宝镜像。
npm config set registry http://registry.npm.taobao.org/
②查看自己的镜像是否有问题命令:
npm config get registry
③安装脚手架命令。
cnpm install -g @vue/cli
④查看脚手架版本命令:
vue -V
⑤创建vue项目体验Vue3.
在自己电脑上找到方代码的地方。【用 vue create vue3-app】
下一步:
下一步
下一步
安装完就可以用开发工具打开。
⑥运行项目。
npm run serve
看到上述页面代表项目安装启动成功。
四、对比Vue3和Vue2 看看有哪些不同。
①首先入口初始化不相同。
②生命周期不相同。
与 2.x 版本生命周期相对应的组合式 API beforeCreate -> 使用 setup() created -> 使用 setup() beforeMount -> onBeforeMount mounted -> onMounted beforeUpdate -> onBeforeUpdate updated -> onUpdated beforeDestroy -> onBeforeUnmount destroyed -> onUnmounted errorCaptured -> onErrorCaptured onRenderTracked 检查依赖被追踪。当render函数被调用时,会检查哪个响应式数据被收集依赖 onRenderTriggered 当执行update操作时,会检查哪个响应式数据导致组件重新渲染。
案例一:
<template>
<div class="home">
<!-- <img alt="Vue logo" src="../assets/logo.png">-->
<!-- <HelloWorld msg="Welcome to Your Vue.js App"/>-->
</div>
</template>
<script>
// @ is an alias to /src
/*import HelloWorld from '@/components/HelloWorld.vue'*/
import {
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
onErrorCaptured,
onRenderTracked,
onRenderTriggered
} from 'vue'
export default {
name: 'HomeView',
components: {
/* HelloWorld*/
},
setup(){
onBeforeMount(()=>{
console.log("这个onBeforeMount方法实行了")
})
onMounted(()=>{
console.log("onMounted方法实行了")
})
onBeforeUpdate(()=>{
console.log("onBeforeUpdate方法实行了")
})
onUpdated(()=>{
console.log("onUpdated方法实行了")
})
onBeforeUnmount(()=>{
console.log(" onBeforeUnmount方法实行了")
})
onUnmounted(()=>{
console.log(" onUnmounted方法实行了")
})
onErrorCaptured(err =>{
console.log("err 实行了")
})
onRenderTracked(obj =>{
console.log("obj实行了")
})
onRenderTriggered(obj=>{
console.log("obj onRenderTriggered 实行了")
})
console.log('setup 实行了')
},
}
</script>
总结:
①在vue2中需要定义数据在data()方法中,而vue3中直接在setup()中定义,通过return {} 返回。
②vue2中在方法中需要this 调用,而vue3中不需用this,就可以直接调用。
案例二:
<template>
<div class="home">
<p>
{{num}}
</p>
<span @click="add">加1</span>
<hr>
<span> {{name}}</span>
<!-- <img alt="Vue logo" src="../assets/logo.png">-->
<!-- <HelloWorld msg="Welcome to Your Vue.js App"/>-->
</div>
</template>
<script>
// @ is an alias to /src
/*import HelloWorld from '@/components/HelloWorld.vue'*/
import {
onRenderTracked,
onRenderTriggered,
ref
} from 'vue'
export default {
name: 'HomeView',
components: {
/* HelloWorld*/
},
setup(){
let name = '你好,张三'
let num = ref(1)
//追踪页面依赖的响应式数据
onRenderTracked(obj =>{
console.log("obj实行了")
})
//追踪引发页面重新渲染的响应式数据
onRenderTriggered(obj=>{
console.log("obj onRenderTriggered 实行了")
})
let add =()=>{
//console.log('this=',this)
//console.log('num=',num)
num.value++
console.log('num=',num)
}
return{
name,
add,
num
}
},
}
</script>
案例三
<template>
<div class="home">
<p>
{{user.age}}
</p>
<span @click="add">加1岁</span>
<hr>
<span> {{user.name}}</span>
<!-- <img alt="Vue logo" src="../assets/logo.png">-->
<!-- <HelloWorld msg="Welcome to Your Vue.js App"/>-->
</div>
</template>
<script>
// @ is an alias to /src
/*import HelloWorld from '@/components/HelloWorld.vue'*/
import {
onBeforeMount,
onMounted,
onBeforeUpdate,
onUpdated,
onBeforeUnmount,
onUnmounted,
onErrorCaptured,
onRenderTracked,
onRenderTriggered,
reactive
} from 'vue'
export default {
name: 'HomeView',
components: {
/* HelloWorld*/
},
setup(){
let user = reactive({
id: 1,
name: '张三',
age: 18
})
let add=()=>{
user.age++
}
//追踪页面依赖的响应式数据
onRenderTracked(obj =>{
console.log("obj实行了")
})
//追踪引发页面重新渲染的响应式数据
onRenderTriggered(obj=>{
console.log("obj onRenderTriggered 实行了")
})
return{
user,
add
}
},
}
</script>
重点:
reactive与ref
①被响应式api标记过的数据才可以成为响应式数据 ②ref--用来标记简单类型数据 ③reactive—标记复杂类型数据(深度响应式) ④如果用ref对象/数组, 会自动将对象/数组转换为reactive的代理对象 ⑤ref的数据操作: 在js中要.value, 在模板中不需要(内部解析会自动添加.value)
安装:element-plus
参考官方:element-plus.gitee.io/zh-CN/guide…
安装命令:
npm install element-plus --save
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
const app = createApp(App)
app.use(ElementPlus)
app.mount('#app')
上述需要导入到main.js中。
案例四:
<div>
<el-row class="mb-4">
<el-button>Default</el-button>
<el-button type="primary">Primary</el-button>
<el-button type="success">Success</el-button>
<el-button type="info">Info</el-button>
<el-button type="warning">Warning</el-button>
<el-button type="danger">Danger</el-button>
</el-row>
</div>
同时:在vue3中不在是一个根
Vue3+TS
创建vue3+TS 项目体验
创建项目命令:
npm init vite
官网:Vite中文网
发现VS code 报红,禁用 vetur 然后在应用商店搜索Vue Language Features 或者搜索 Volar
①安装
②安装
启动项目。
npm run dev
看到上述页面代表Vue3+ TS 运行成功。
模块骨架
<template>
</template>
<script lang="ts">
export default{
}
</script>
<style lang="less" scoped>
</style>
试试第一个程序:
<template>
<div>
{{ name }}
</div>
</template>
<script lang="ts">
export default {
setup() {
let name: string = '中国宜昌'
return {
name,
}
},
}
</script>
<style lang="less" scoped></style>
记得修改main.ts 文件。
import app from './components/01-app.vue'
createApp(app).mount('#app')
ref方法学习处理基本类型。
案例一:
<template>
<div>
{{ name }}
<hr />
{{ num }}
<button @click="add">增加</button>
</div>
</template>
<script lang="ts">
import { ref } from 'vue'
export default {
setup() {
let name: string = '中国宜昌'
let num = ref(18)
let add = () => {
num.value++
}
return {
name,
num,
add,
}
},
}
</script>
<style lang="less" scoped></style>
reactive方法处理复杂类型
案例二:
<template>
id:{{ user.id }}<br />
姓名:{{ user.name }}<br />
年龄:{{ user.age }}<br />
性别:{{ user.sex }}
</template>
<script lang="ts">
import { reactive } from 'vue'
export default {
setup() {
let user = reactive({
id: 0,
name: '张三',
age: 18,
sex: '男',
})
return {
user,
}
},
}
</script>
<style lang="less" scoped></style>
toRefs()函数的相应数据处理
<template>
<div>
{{ name }}
<hr />
{{ num }}
<button @click="add">增加</button>
</div>
</template>
<script lang="ts">
import { reactive, toRefs } from 'vue'
export default {
setup() {
let name: string = '中国宜昌'
let obj = {
num: 18,
}
let { num } = toRefs(reactive(obj))
let add = () => {
num.value++
console.log(num.value)
}
return {
name,
num,
add,
}
},
}
</script>
<style lang="less" scoped></style>
toRefs()方法的作用就是将 reactive 处理的复杂对象结构成相应是数据。
setup语法糖
案例
<template>
<div>
{{ name }}
<hr />
{{ num }}
<button @click="add">增加</button>
</div>
</template>
<script lang="ts" setup>
import { reactive, toRefs } from 'vue'
let name: string = '中国宜昌'
let obj = {
num: 18,
}
let { num } = toRefs(reactive(obj))
let add = () => {
num.value++
console.log(num.value)
}
</script>
<style lang="less" scoped></style>
在开发中简化了好多,建议后续同学以setup语法糖 方式开发。
setup语法糖 简化了
①没有导出export default {}
②去掉了return 返回,直接以响应式数据返回。
语法糖模块如下:
<template>
</template>
<script lang="ts" setup>
//(1)导入方法或者类、接口
//(2)写自己的代码
</script>
<style lang="less" scoped></style>
watch 用法
<template>
<p>{{ num }}</p>
<button @click="num++">加1</button>
</template>
<script lang="ts" setup>
//(1)导入方法或者类、接口
import { ref, watch } from 'vue'
//(2)写自己的代码
let num = ref(20)
//这里需要传递num num 必须是响应式数据
watch(num, (newVal, oldVal) => {
console.log(newVal, oldVal)
})
</script>
<style lang="less" scoped></style>
监听对象
<template>
<p>{{ num }}</p>
<button @click="num++">加1</button>
</template>
<script lang="ts" setup>
//(1)导入方法或者类、接口
import { ref, watch, reactive, toRefs } from 'vue'
//(2)写自己的代码
//let num = ref(20)
//这里需要传递num num 必须是响应式数据
let obj = {
num: 30,
}
let objRef = reactive(obj)
let { num } = toRefs(objRef)
watch(num, (newVal, oldVal) => {
console.log(newVal, oldVal)
})
</script>
<style lang="less" scoped></style>
计算属性用法
案例:
<template>
{{ numRef }}
<button @click="num++">加加</button>
<hr />
{{ numDb }}
<button @click="objRef.num++">下面加</button>
</template>
<script lang="ts" setup>
//(1)导入方法或者类、接口
import { ref, computed, reactive } from 'vue'
//(2)写自己的代码
let num = ref(20)
let numRef = computed(() => {
return num.value * 2
})
let obj = {
num: 30,
}
let objRef = reactive(obj)
let numDb = computed(() => {
return objRef.num * 2
})
</script>
<style lang="less" scoped></style>
计算属性computed 组件 Vue3中需要定义变量(let)或者常量来做接收,如果是setup语法糖模式,会自动返回return 。
父传子组件
案例:
父组件
<template>
<child :num="num"> </child>
</template>
<script lang="ts" setup>
//(1)导入方法或者类、接口
import { ref } from 'vue'
import child from './07-appChild.vue'
//(2)写自己的代码
let num = ref(20)
</script>
<style lang="less" scoped></style>
子组件
<template>
<p>
{{ num }}
</p>
</template>
<script lang="ts" setup>
//(1)导入方法或者类、接口
import { defineProps } from 'vue'
//props:{
//num :num
// }
//(2)写自己的代码
defineProps({
num: {
type: Number,
default: 80,
},
})
</script>
<style lang="less" scoped></style>
父传子组件需要用到defineProps 在子组件中接收传递对象。
子传父组件
父组件
<template>
<child @fn="chanAge" :age="age"> </child>
</template>
<script lang="ts" setup>
//(1)导入方法或者类、接口
import { ref } from 'vue'
import child from './08-appChild.vue'
//(2)写自己的代码
let age = ref(2)
const chanAge = () => {
age.value++
}
</script>
<style lang="less" scoped></style>
子组件
<template>
<p>{{ age }}</p>
<button @click="add">按钮</button>
</template>
<script lang="ts" setup>
//(1)导入方法或者类、接口
import { defineProps, defineEmits } from 'vue'
defineProps({
age: {
type: Number,
default: 22,
},
})
//子传父需要用defineEmits
const emit = defineEmits<{
(event: 'fn'): void
}>()
const add = () => {
emit('fn')
}
</script>
<style lang="less" scoped></style>
子传父需要通过导入 defineEmits方法。需要定义常量【const emit】 来接收,在父组件当中应该定义好方法【fn】。
VS code 自定义代码片段:
{
"dome": {
"prefix": "v3",
"body": [
"<template>",
"\t",
"</template>",
"",
"<script lang='ts' setup>",
"import {} from 'vue'",
"\t$0",
"</script>",
" ",
"<style lang='less' scoped >",
"\t",
"</style>"
],
"description": "自定义Vue3片段"
}
}
案例练习 全选/反选
分解题目
①先显示界面
<template>
<input type="checkbox" />全选/反选
<ul>
<li v-for="(item, index) in list" :key="index">
<input type="checkbox" />{{ item }}
</li>
</ul>
</template>
<script lang="ts" setup>
import { reactive, ref, toRefs, computed } from 'vue'
let data = reactive({
list: ['篮球', '足球', '乒乓球', '网球']
})
let { list } = toRefs(data)
</script>
<style lang="less" scoped></style>
②双向绑定 计算属性
<template>
<input type="checkbox" v-model="chackAll" />全选/反选
<ul>
<li v-for="(item, index) in list" :key="index">
<input type="checkbox" />{{ item }}
</li>
</ul>
</template>
<script lang="ts" setup>
import { reactive, ref, toRefs, computed } from 'vue'
let data = reactive({
list: ['篮球', '足球', '乒乓球', '网球']
})
let { list } = toRefs(data)
let chackAll = ref(true)
</script>
<style lang="less" scoped></style>
③能不能全选或者反选
<template>
<input type="checkbox" v-model="chackAll" />全选/反选
<ul>
<li v-for="(item, index) in list" :key="index">
<input type="checkbox" v-model="checkList[index]" />
{{ item }}
</li>
</ul>
</template>
<script lang="ts" setup>
import { reactive, ref, toRefs, computed } from 'vue'
let data = reactive({
list: ['篮球', '足球', '乒乓球', '网球'],
checkList: [false, true, false, false],
})
let { list, checkList } = toRefs(data)
let chackAll = ref(true)
</script>
<style lang="less" scoped></style>
④按照计算属性来处理如下:
<template>
<input type="checkbox" v-model="chackAll" />全选/反选
<ul>
<li v-for="(item, index) in list" :key="index">
<input type="checkbox" v-model="checkList[index]" />{{ item }}
</li>
</ul>
</template>
<script lang="ts" setup>
import { reactive, ref, toRefs, computed } from 'vue'
let data = reactive({
list: ['篮球', '足球', '乒乓球', '网球'],
checkList: [false, false, false, false],
})
let { list, checkList } = toRefs(data)
let chackAll = computed({
get() {
return !data.checkList.includes(false)
},
set(newVul: boolean) {
//console.log(newVul)
data.checkList = data.checkList.map(() => newVul)
},
})
</script>
<style lang="less" scoped></style>
07
<template>
<input type="checkbox" v-model="checkAll" />全选/反选
<ul>
<li v-for="(item, index) in list" :key="index">
<input type="checkbox" v-model="checkList" />{{ item }}
</li>
</ul>
</template>
<script lang="ts" setup>
import { computed, reactive, toRefs } from 'vue'
let data = reactive({
list: ['篮球', '足球', '乒乓球', '网球'],
checkList: [false, false, false, false],
})
let { list, checkList } = toRefs(data)
//let checkAll = ref(false)
let checkAll = computed({
get() {
return !data.checkList.includes(false)
},
set(newVul: boolean) {
// data.checkList = data.checkList.map(()=> newVul)
data.checkList = data.checkList.map(() => newVul)
console.log(newVul)
},
})
</script>
<style lang="less" scoped></style>
V-mode的传值
案例一:
父组件
<template>
<child v-model:num="num"></child>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import child from './10-appChild.vue'
let num = ref(100)
</script>
<style lang="less" scoped></style>
子组件
<template>
<p>
子组件
{{ num }}
</p>
<button @click="update">修改</button>
</template>
<script lang="ts" setup>
import { defineProps } from 'vue'
defineProps({
num: {
type: Number,
default: 300,
},
})
const emit = defineEmits<{
(event: 'update:num', n: number): void
}>()
const update = () => {
emit('update:num', 111)
}
</script>
<style lang="less" scoped></style>
案例二
父组件
<template>
<child v-model:num="num"></child>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import child from './10-appChild.vue'
let num = ref(100)
</script>
<style lang="less" scoped></style>
子组件
<template>
<p>
子组件
{{ num }}
</p>
<button @click="update">修改</button>
</template>
<script lang="ts" setup>
import { defineProps } from 'vue'
let pos = defineProps({
num: {
type: Number,
default: 300,
},
})
const emit = defineEmits<{
(event: 'update:num', n: number): void
}>()
let n = pos.num
const update = () => {
n++
emit('update:num', n)
}
</script>
<style lang="less" scoped></style>
插槽
匿名插槽
父组件:
<template>
<child>
<button>按钮</button>
<p>这是中国宜昌</p>
</child>
</template>
<script lang="ts" setup>
import {} from 'vue'
import child from './11-appChild.vue'
</script>
<style lang="less" scoped></style>
子组件
<template>
<p>子组件</p>
<slot></slot>
</template>
<script lang="ts" setup>
import {} from 'vue'
</script>
<style lang="less" scoped></style>
具名插槽
父组件
<template>
<child>
<template v-slot:but>
<button>按钮</button>
</template>
<template v-slot:link>
<p>这是中国宜昌</p>
</template>
</child>
</template>
<script lang="ts" setup>
import {} from 'vue'
import child from './11-appChild.vue'
</script>
<style lang="less" scoped></style>
子组件
<template>
<p>子组件</p>
<slot name="link"></slot>
<slot name="but"></slot>
</template>
<script lang="ts" setup>
import {} from 'vue'
</script>
<style lang="less" scoped></style>
作用域插槽
父组件
<template>
<child>
<template #but="scope">
<button>按钮 {{ scope.title }} {{ scope.myStr }}</button>
</template>
<template v-slot:link>
<p>这是中国宜昌</p>
</template>
</child>
</template>
<script lang="ts" setup>
import {} from 'vue'
import child from './11-appChild.vue'
</script>
<style lang="less" scoped></style>
子组件
<template>
<p>子组件</p>
<slot name="link"></slot>
<slot name="but" title="你好吗" :myStr="str"></slot>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
let str = ref('这是匿名插槽')
</script>
<style lang="less" scoped></style>
Teleport传送门
Vue 3 提供的新组件,可以把组件传输到指定的位置。