前言
- 2019年10月5日 Vue3公布源码
- 2020年09月18日,Vue3正式发布,代号
One Piece
- 2022年02月07日,Vue3正式作为默认版本
由Vue2过渡至Vue3记录,Vue3了解过程中,最大感受就是没有了统一的
data,methods,watch,computed...等属性,而是以对象方式灵活调用,最终可以实现代码模块化,可以将实现同一个功能的参数、属性、方法集中到一起,便于迁移
构建
推荐使用Vite+Vue3方式构建项目Vite构建速度相比webpack大幅度提升
Vite
在Vite官方文档中查看构建方式
数据
ref 响应式变量
Vue3中变量不再默认支持双向绑定,需创建响应式对象
响应式变量声明
ref()
声明使用ref() 赋值使用变量.value模版中修改不需要使用.value
<template>
<h1>{{msg}}</h1>
<h1>{{reve(msg)}}</h1>
<h1>{{num}}</h1>
<button @click="setmsg">点击</button>
<button @click="num++">点击</button>
</template>
<script setup>
import { ref } from 'vue'
let msg = ref('你好世界')
let num = ref(0)
function reve(info){
return info.split('').reverse().join('')
}
function setmsg(info){
console.log(msg)
msg.value = 'Hello world!'
console.log('msg', msg.value)
}
</script>
reactive 响应式对象
使用
ref()可声明响应式对象,但赋值过于繁琐,Vue3提供reactive()用于声明响应式对象
<template>
<!-- ref 声明对象-->
<h1>{{user.name}}</h1>
<h1>{{user.age}}</h1>
<button @click="updateUser">点击</button>
<!-- ref 声明对象-->
<!-- reactive声明对象-->
<h1>{{user1.name}}</h1>
<h1>{{user1.age}}</h1>
<button @click="updateUser1">点击</button>
<!-- reactive声明对象-->
<!-- ref转换reactive -->
<h1>{{user2.name}}</h1>
<h1>{{user2.age}}</h1>
<button @click="updateUser2">点击</button>
<!-- ref转换reactive -->
</template>
<script setup>
import { ref,reactive } from 'vue'
//ref 声明对象
let user = ref({
name:'user',
age:18
})
function updateUser(){
user.value.name = '李大锤'
user.value.age = user.value.age +1
}
//ref 声明对象
// reactive声明对象
let user1 = reactive({
name:'user1',
age:19
})
function updateUser1(){
user1.name = '王小明'
user1.age = user1.age+1
}
// reactive声明对象
// ref转换reactive
//user2为引用类型 指向 user 跟随发生改变
let user2 = reactive(user.value)
function updateUser2() {
user2.name = 'user2'
user2.age = 0
}
// ref转换reactive
</script>
computed 计算属性
调用方式与Vue2不同,基本功能一致 缓存数据优化性能
基本使用
computed传入functionreturn 数据
<template>
<h1>{{msg}}</h1>
<h1>{{reve(msg)}}</h1>
<h1>{{reve(msg)}}</h1>
<h1>{{reve(msg)}}</h1>
<h1>{{resMsg}}</h1>
<h1>{{resMsg}}</h1>
<h1>{{resMsg}}</h1>
</template>
<script setup>
import { ref,computed } from 'vue'
let msg = ref('你好世界')
function reve(info){
console.log('reve调用次数')
return info.split('').reverse().join('')
}
//计算属性
const resMsg = computed(()=>{
console.log('computed调用次数')
return msg.value.split('').reverse().join('')
})
</script>
更新变量
computed传入Object{functionget ,functionset }functionget return 数据 ,functionset 修改数据
<template>
<h1>{{ info }}</h1>
<h1>{{ resInfo }}</h1>
<button @click="UpdateResInfo">修改</button>
</template>
<script setup>
import {ref, computed} from 'vue'
let info = ref('Hello world')
//计算属性
// computed 传入 Object { function get ,function set } function get return 数据 function set 修改数据
const resInfo = computed({
get() {
return info.value.split('').reverse().join('')
},
set(value) {
info.value = value
}
})
let UpdateResInfo = () => {
resInfo.value = '李大锤'
}
</script>
watch 监听
watch可监听dataObjectfunction return Object.data[data,Object,function]
<template>
<h1>{{ info }}</h1>
<button @click="updateInfo">修改</button>
<h1>{{ user.name }}</h1>
<h1>{{ user.sex }}</h1>
<ul>
<li :key="index" v-for="(i,index) in user.log">{{i.title}} {{i.time}}</li>
</ul>
<button @click="updateUser">修改</button>
<button @click="updateUser2">深度修改</button>
</template>
<script setup>
import {ref,reactive, watch} from 'vue'
//watch监听变量
let info = ref('Hello world')
watch(info,(oldData,newData)=>{
console.log('oldData:',oldData,'newData:',newData)
})
function updateInfo(){
info.value = '你好 世界'
}
//watch监听对象
let user = reactive({
name:'李大锤',
sex:'男',
log:[
{
time:'2020.01.01',
title:'修改密码',
},
{
time:'2020.01.01',
title:'删除数据',
}
]
})
//监听整个对象
watch(user,(oldData,newData)=>{
console.log('user oldData:',oldData,'user newData:',newData)
})
//监听对象中的属性 user.name
watch(()=>user.name ,(oldData,newData)=>{
console.log('user.name oldData:',oldData,'user.name newData:',newData)
})
//同时监听多个 user.name,info
watch([()=>user.name,info] ,(oldData,newData)=>{
console.log('user.name,info oldData:',oldData,'user.name,info newData:',newData)
})
function updateUser(){
user.name = '李二锤'
user.sex = '女'
}
function updateUser2(){
user.log[0].title = '更新密码'
}
//watch监听对象
</script>
组件
defineProps 传参
父组件向子组件传参 子组件改用
defineProps对象接收数据
- App.vue
<template>
<userItem :title="i.name" :address="i.address" v-for="i in userList"></userItem>
</template>
<script setup>
import {ref, reactive} from 'vue'
import userItem from './components/userItem.vue'
let userList = reactive([
{
name: '江敏',
address: '澳门特别行政区 离岛 '
},
{
name: '方勇',
address: '海南省 三亚市 '
},
{
name: '方勇',
address: '海南省 三亚市 '
}
])
</script>
- userItem.vue
<template>
<div style="display: flex;padding: 30px;border: 1px solid #ddd;margin-bottom: 20px;justify-content: space-between">
<div>{{props.title}}</div>
<div>{{props.address}}</div>
</div>
</template>
<script setup>
import {defineProps} from 'vue'
const props = defineProps({
title:{
default:'',
type:String
},
address:{
default:'',
type:String
}
})
</script>
defineEmits 注册事件
子组件通过
defineProps注册事件,触发传递到父组件
- App.vue
<template>
<!-- 绑定事件-->
<userItem :title="i.name" :address="i.address" v-for="i in userList" @tap="toPage"></userItem>
</template>
<script setup>
import {ref, reactive} from 'vue'
import userItem from './components/userItem.vue'
let userList = reactive([
{
name: '江敏',
address: '澳门特别行政区 离岛 '
},
{
name: '方勇',
address: '海南省 三亚市 '
},
{
name: '方勇',
address: '海南省 三亚市 '
}
])
// 触发事件执行 function
function toPage(itemInfo){
console.log('itemInfo',itemInfo)
console.log('itemInfo',itemInfo.title)
}
</script>
- userItem.vue
<template>
<div style="display: flex;padding: 30px;border: 1px solid #ddd;margin-bottom: 20px;justify-content: space-between" @click="tapItem(props)">
<div>{{props.title}}</div>
<div>{{props.address}}</div>
</div>
</template>
<script setup>
import {defineProps,defineEmits} from 'vue'
const props = defineProps({
title:{
default:'',
type:String
},
address:{
default:'',
type:String
}
})
//注册事件 数组形式注册多个
const emit = defineEmits(['tap','longTap'])
//抛出事件
function tapItem(itemInfo){
emit('tap',itemInfo)
}
</script>
路由
安装vue-router
npm install vue-router
基本使用
- main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'
let app = createApp(App)
app.use(router)
app.mount('#app')
- App.vue
<template>
<!-- 路由视图位置-->
<router-view></router-view>
</template>
- /src/router/index.js
import {
createRouter,
createWebHashHistory,
createWebHistory,
} from 'vue-router'
//引入组件
import Home from '../views/Home/index.vue'
import User from '../views/User/index.vue'
//配置路由
const routes = [
{
path:'/',
component:Home,
name:'home'
},
{
path:'/user',
component:User,
name:'user'
},
{
path:'/goods/:id',
component:()=>import('../views/goods/index.vue'),
name:'goods'
}
]
//创建路由 传入配置 设置history方式
const router = createRouter({
history:createWebHashHistory(),
routes
})
// 导出router
export default router
- /src/views/User/index.vue
<template>
<div>
Home
<router-link to="/user">去user页</router-link>
</div>
</template>
- /src/views/Home/index.vue
<template>
<div>
Home
<router-link to="/user">去user页</router-link>
<button @click="toPage">去user页</button>
</div>
<div>
goods
<input v-model="id">
<button @click="toGoods">去goods页</button>
</div>
</template>
<script setup>
import {ref} from 'vue'
import { useRoute,useRouter} from 'vue-router'
let route = useRoute()
let router = useRouter()
//user页
function toPage(){
console.log('route',route)
router.push('/user')
}
//user页
//goods页
let id = ref(0)
function toGoods(){
router.push(`/goods/${id.value}`)
}
</script>
- /src/views/goods/index.vue
<template>
goods
<div>{{route.params.id}}</div>
</template>
<script setup>
import {useRoute} from 'vue-router'
console.log('33333')
const route = useRoute()
console.log(route)
</script>
状态管理
组件中的数据 组件销毁时释放 需声明响应式数据
Vuex中的数据 应用销毁时释放 全局响应式数据
缓存中的数据 长久保存,清除缓存后释放 静态数据
Vuex
- main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'
import store from "./store/index";
let app = createApp(App)
app.use(router)
app.use(store)
app.mount('#app')
- /src/store/index.js
import { createStore } from 'vuex'
// 创建一个新的 store 实例
const store = createStore({
state () {
return {
count: 0
}
},
//修改数据
mutations: {
increment (state,data) {
state.count += data
}
},
//计算属性
getters:{
countx5(state){
return state.count * 5
}
},
//异步请求数据
actions:{
// 仓库对象store, 请求参数payload
asyncAdd(store,payload){
// commit 用于触发mutations 中方法
setTimeout(()=>{
console.log(payload)
store.commit('increment',payload)
},1000)
}
}
})
export default store
- /src/views/Home/index.vue
<template>
<div>数量:{{store.state.count}}</div>
<div>数量X5:{{store.getters.countx5}}</div>
<button @click="addGoods">添加</button>
<button @click="asyncAddGoods">异步添加 11</button>
<router-link to="/goods/11">toGoods</router-link>
</template>
<script setup>
import {useStore} from 'vuex'
import {ref} from 'vue'
let store = useStore()
function addGoods(){
//同步操作
store.commit('increment',3)
}
function asyncAddGoods(){
//异步操作
store.dispatch('asyncAdd',11)
}
</script>
- /src/views/goods/index.vue
<template>
<div>数量:{{store.state.count}}</div>
<div>数量X5:{{store.getters.countx5}}</div>
</template>
<script setup>
import {useStore} from "vuex";
let store = useStore()
</script>
后续学习整理中···