vue3.0 知识点整理
vue3.0 知识点整理Composition API1.setup2.ref3.reactive(优化)4.toRefs(再次优化)Composition API1.setup新的option, 所有的组合API函数都在此使用, 只在初始化时执行一次函数如果返回对象, 对象中的属性或方法, 模板中可以直接使用2.ref作用: 定义一个数据的响应式语法: const xxx = ref(initV
·
vue3.0 知识点整理
Composition API
1.setup
新的option, 所有的组合API函数都在此使用, 只在初始化时执行一次
函数如果返回对象, 对象中的属性或方法, 模板中可以直接使用
2.ref
- 作用: 定义一个数据的响应式
- 语法: const xxx = ref(initValue):
- 创建一个包含响应式数据的引用(reference)对象
- js中操作数据: xxx.value
- 模板中操作数据: 不需要.value
- 一般用来定义一个基本类型的响应式数据
<template>
<div>
<button
v-for="(item, index) in girls"
v-bind:key="index"
@click="selectGirlFun(index)"
>
{{ index }} : {{ item }}
</button>
</div>
<div>你选择了【{{ selectGirl }}】为你服务</div>
</template>
<script lang="ts">
import { ref } from "vue";
export default {
// 定义变量时必须用ref包起来,修改值是,必须用.value修改
setup() {
const girls = ref(["大脚", "刘英", "晓红"]);
const selectGirl = ref("");
const selectGirlFun = (index: number) => {
selectGirl.value = girls.value[index];
};
//因为在模板中这些变量和方法都需要条用,所以需要return出去。
return {
girls,
selectGirl,
selectGirlFun,
};
},
};
</script>
<style>
</style>
3.reactive(优化)
使用reactive时,不用ref定义变量,不用.value进行修改,但是tempalte中,必须data.XX进行获取
- 作用: 定义多个数据的响应式
- const proxy = reactive(obj): 接收一个普通对象然后返回该普通对象的响应式代理器对象
- 响应式转换是“深层的”:会影响对象内部所有嵌套的属性
- 内部基于 ES6 的 Proxy 实现,通过代理对象操作源对象内部数据都是响应式的
<template>
<div>
<button
v-for="(item, index) in data.girls"
v-bind:key="index"
@click="data.selectGirlFun(index)"
>
{{ index }} : {{ item }}
</button>
</div>
<div>你选择了【{{ data.selectGirl }}】为你服务</div>
</template>
<script lang="ts">
import { reactive } from "vue";
interface DataProps {
girls: string[];
selectGirl: string;
selectGirlFun: (index: number) => void;
}
export default {
// 使用reactive时,不用ref定义变量,不用.value进行修改,但是tempalte中,必须data.XX进行获取
setup() {
const data:DataProps = reactive({
girls: ["大脚", "刘英", "晓红"],
selectGirl: "",
selectGirlFun: (index: number) => {
data.selectGirl = data.girls[index];
},
});
return {
data,
};
},
};
</script>
<style>
</style>
4.toRefs(再次优化)
使用reactive+toRefs,解决了empalte中,必须用data.XX,使用toRefs()进行解构赋值
<template>
<div>
<button
v-for="(item, index) in girls"
v-bind:key="index"
@click="selectGirlFun(index)"
>
{{ index }} : {{ item }}
</button>
</div>
<div>你选择了【{{ selectGirl }}】为你服务</div>
</template>
<script lang="ts">
import { reactive,toRefs } from "vue";
interface DataProps {
girls: string[];
selectGirl: string;
selectGirlFun: (index: number) => void;
}
export default {
// 使用reactive+toRefs,解决了empalte中,必须用data.XX,使用toRefs()进行解构赋值
setup() {
const data:DataProps = reactive({
girls: ["大脚", "刘英", "晓红"],
selectGirl: "",
selectGirlFun: (index: number) => {
data.selectGirl = data.girls[index];
},
});
const refData = toRefs(data);
return {
...refData,
};
},
};
</script>
<style>
</style>
5.vue-router vuex
5.1安装
npm install vue-router --save
npm install vuex --save
npm i vue-router@next vuex@next -S
5.2使用
router.js
import { createRouter, createWebHashHistory } from 'vue-router'
import store from '/@/store'
import Login from '../views/Login/index.vue'
import Index from "/@/views/Index/index.vue"
import Details from '/@/views/Details/index.vue' //工程信息设置
import Error from '/@/views/Error/index.vue'
import NotFound from '/@/views/NotFound/index.vue'
import System from '/@/views/System/index.vue' //用户管理
import User from '/@/views/System/User/index.vue' //用户管理
import Group from '/@/views/System/Group/index.vue' //工程信息设置
// 需要动态添加的路由
const user = {path: '/system/user', component: User, name: 'user',meta: {requiresAuth: true}}
const group = {path: '/system/group', component: Group, name: 'group',meta: {requiresAuth: true}}
// 动态路由根据名称匹配跳转页面
const ruleMapping = {
'/system/user': user,
'/system/group': group
};
const routes = [{
path: '/',
redirect: "/login"
},
{
path: '/login',
name: 'login',
component: Login
}, {
path: '/index',
name: 'index',
component: Index
},{
path: '/nav/:type/:id',
name: 'nav',
component: Details,
meta: {
requiresAuth: true
} // 开启登录拦截
},
// {
// path: '/system',
// name: 'system',
// component: System,
// redirect:"/system/user",
// children:[{
// path: 'user',
// name: 'user',
// component: User,
// },{
// path: 'group',
// name: 'group',
// component: Group,
// }]
// },
{
path: '/notFound',
name: 'notFound',
component: NotFound
}, {
// 没有路由的访问权限时,访问的页面404
path: '/:pathMatch(.*)*',
name: '404',
component: Error
}
]
const router = createRouter({
history: createWebHashHistory(),
routes
})
/*
路由导航守卫
to 要跳转到哪个界面
from 从哪跳转来的
next 是否要放行
*/
router.beforeEach((to, from, next) => {
if (to.path === '/login') {
// 如果是要跳转登录就直接放行
next()
} else {
// 检查路由元信息,是否开启登录验证
if (to.matched.some(record => record.meta.requiresAuth)) {
const token = store.state.user.token;
// 判断用户是否已经登录
if (!token) {
// 没登陆还是跳转登录页
next('/notFound')
} else {
// 正常情况就放行,设置当前路由地址
window.sessionStorage.setItem('activePath', to.path)
next()
}
} else {
// 没开启登录验证,放行
if(to.matched.some((record) => {return record.name=="404"})&&(to.path=="/system/user"||to.path=="/system/group")){
next(to.path)
}else{
next()
}
}
}
});
// 动态导入路由
export function initRoutes() {
const token = store.state.user.token;
if (!token) {
router.login
} else {
const currentRoutes = router.options.routes; // 获取要添加路由的当前路由
const navList = store.state.navList; // 获取state中缓存的根据权限获取的路由
/*navList =[{
id: 1,
title: '用户管理',
icon: 'iconuser',
path: '/system/user'
}, {
id: 2,
title: '分类管理',
icon: 'icondaohang',
path: '/system/group'
}];*/
if (navList.length > 0) {
const aa = store.state.navList[0].path;
const currentIndex = {path: '/system', component: System, meta: {requiresAuth: true}, redirect: aa, children: []}
currentRoutes.push(currentIndex);
navList.forEach(item => { // 循环获取的路由
const temp = ruleMapping[item.path]; // 获取需要动态添加的路由,对应的跳转页面配置
//temp.meta = item.path; // 将接口返回的路由对应的权限赋给当前路由(在按钮权限控制时使用)
currentIndex.children.push(temp); // 将匹配的路由,添加到当前路由的对应子路由位置
});
for (let x of currentRoutes) {
router.addRoute(x)// 执行动态添加路由方法,完成动态路由添加
}
}
}
}
// 重置路由(退出登录,切换账号)
export function resetRouter() {
const newRouter = createRouter()
router.matcher = newRouter.matcher // the relevant part
}
export default router
vuex.js
import {createStore} from 'vuex'
export default createStore({
state: {
// 用户
user: {
username: window.sessionStorage.getItem('user' || '[]') == null ? '' : JSON.parse(window.sessionStorage.getItem('user' || '[]')).username,
token: window.sessionStorage.getItem('user' || '[]') == null ? '' : JSON.parse(window.sessionStorage.getItem('user' || '[]')).token,
type: window.sessionStorage.getItem('user' || '[]') == null ? '' : JSON.parse(window.sessionStorage.getItem('user' || '[]')).type,
userid: window.sessionStorage.getItem('user' || '[]') == null ? '' : JSON.parse(window.sessionStorage.getItem('user' || '[]')).userid
},
// 动态路由
navList: JSON.parse(window.sessionStorage.getItem('navList') || '[]')
},
mutations: {
// 设置user信息
setUser(state, data) {
state.user = data;
window.sessionStorage.setItem("user", JSON.stringify(data));
},
// 导航
setNavList(state, data) {
state.navList = data;
window.sessionStorage.setItem("navList", JSON.stringify(data));
}
},
getters: {
// 获取user信息
getUser(state) {
return state.user;
}
},
actions: {
},
modules: {}
})
main.js挂载
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import axios from 'axios'
import VueAxios from 'vue-axios'
import api from '/@/api/index'
const app = createApp(App)
app.config.globalProperties.$api = api
app.use(router).use(store).use(VueAxios,axios).mount('#app')
在vue.js文件中使用vue-router vuex $api
<script lang="ts">
import { useRouter } from 'vue-router'
import { reactive,toRefs,getCurrentInstance } from "vue";
import { useStore} from 'vuex'
import {initRoutes} from "/@/router/index.js"//动态添加路由
export default {
name: "login",
setup(){
const { proxy } = getCurrentInstance()
const $api = proxy.$api
const route = useRouter()
const store = useStore();
const data= reactive({
username:"test1",
password:"111111",
savePwd:true,
});
const refData = toRefs(data);
return {
...refData,
};
}
}
</script>
<style lang="scss">
@import "./index.scss";
</style>
6.计算属性与监视
<template>
<h2>App</h2>
fistName: <input v-model="user.firstName"/><br>
lastName: <input v-model="user.lastName"/><br>
fullName1: <input v-model="fullName1"/><br>
fullName2: <input v-model="fullName2"><br>
fullName3: <input v-model="fullName3"><br>
</template>
<script lang="ts">
/*
计算属性与监视
1. computed函数:
与computed配置功能一致
只有getter
有getter和setter
2. watch函数
与watch配置功能一致
监视指定的一个或多个响应式数据, 一旦数据变化, 就自动执行监视回调
默认初始时不执行回调, 但可以通过配置immediate为true, 来指定初始时立即执行第一次
通过配置deep为true, 来指定深度监视
3. watchEffect函数
不用直接指定要监视的数据, 回调函数中使用的哪些响应式数据就监视哪些响应式数据
默认初始时就会执行第一次, 从而可以收集需要监视的数据
监视数据发生变化时回调
*/
import {
reactive,
ref,
computed,
watch,
watchEffect
} from 'vue'
export default {
setup () {
const user = reactive({
firstName: 'A',
lastName: 'B'
})
// 只有getter的计算属性
const fullName1 = computed(() => {
console.log('fullName1')
return user.firstName + '-' + user.lastName
})
// 有getter与setter的计算属性
const fullName2 = computed({
get () {
console.log('fullName2 get')
return user.firstName + '-' + user.lastName
},
set (value: string) {
console.log('fullName2 set')
const names = value.split('-')
user.firstName = names[0]
user.lastName = names[1]
}
})
const fullName3 = ref('')
/*
watchEffect: 监视所有回调中使用的数据
*/
/*
watchEffect(() => {
console.log('watchEffect')
fullName3.value = user.firstName + '-' + user.lastName
})
*/
/*
使用watch的2个特性:
深度监视
初始化立即执行
*/
watch(user, () => {
fullName3.value = user.firstName + '-' + user.lastName
}, {
immediate: true, // 是否初始化立即执行一次, 默认是false
deep: true, // 是否是深度监视, 默认是false
})
/*
watch一个数据
默认在数据发生改变时执行回调
*/
watch(fullName3, (value) => {
console.log('watch')
const names = value.split('-')
user.firstName = names[0]
user.lastName = names[1]
})
/*
watch多个数据:
使用数组来指定
如果是ref对象, 直接指定
如果是reactive对象中的属性, 必须通过函数来指定
*/
watch([() => user.firstName, () => user.lastName, fullName3], (values) => {
console.log('监视多个数据', values)
})
return {
user,
fullName1,
fullName2,
fullName3
}
}
}
</script>
7.setup细节(setup(props, {attrs, slots, emit}))
- setup(props, context) / setup(props, {attrs, slots, emit})
- props: 包含props配置声明且传入了的所有属性的对象
- attrs: 包含没有在props配置中声明的属性的对象, 相当于 this.$attrs
- slots: 包含所有传入的插槽内容的对象, 相当于 this.$slots
- emit: 用来分发自定义事件的函数, 相当于 this.$emit
<template>
<div>
<h3>{{n}}</h3>
<h3>{{m}}</h3>
<h3>msg: {{msg}}</h3>
<h3>msg2: {{$attrs.msg2}}</h3>
<slot name="xxx"></slot>
<button @click="update">更新</button>
</div>
</template>
<script lang="ts">
import {
ref,
defineComponent
} from 'vue'
export default defineComponent({
name: 'child',
props: ['msg'],
emits: ['fn'], // 可选的, 声明了更利于阅读, 且可以对分发的事件数据进行校验
// setup (props, context) {
setup (props, {attrs, emit, slots}) {
console.log('setup', this)
console.log(props.msg, attrs.msg2, slots, emit)
const m = ref(2)
const n = ref(3)
function update () {
// console.log('--', this)
// this.n += 2
// this.m += 2
m.value += 2
n.value += 2
// 分发自定义事件
emit('fn', '++')
}
return {
m,
n,
update,
}
},
})
</script>
8.reactive与ref-细节
- 是Vue3的 composition API中2个最重要的响应式API
- ref用来处理基本类型数据, reactive用来处理对象(递归深度响应式)
- 如果用ref对象/数组, 内部会自动将对象/数组转换为reactive的代理对象
- ref内部: 通过给value属性添加getter/setter来实现对数据的劫持
- reactive内部: 通过使用Proxy来实现对对象内部所有数据的劫持, 并通过Reflect操作对象内部数据
- ref的数据操作: 在js中要.value, 在模板中不需要(内部解析模板时会自动添加.value)
<template>
<h2>App</h2>
<p>m1: {{m1}}</p>
<p>m2: {{m2}}</p>
<p>m3: {{m3}}</p>
<button @click="update">更新</button>
</template>
<script lang="ts">
import {
reactive,
ref
} from 'vue'
export default {
setup () {
const m1 = ref('abc')
const m2 = reactive({x: 1, y: {z: 'abc'}})
// 使用ref处理对象 ==> 对象会被自动reactive为proxy对象
const m3 = ref({a1: 2, a2: {a3: 'abc'}})
console.log(m1, m2, m3)
console.log(m3.value.a2) // 也是一个proxy对象
function update() {
m1.value += '--'
m2.x += 1
m2.y.z += '++'
m3.value = {a1: 3, a2: {a3: 'abc---'}}
m3.value.a2.a3 += '==' // reactive对对象进行了深度数据劫持
console.log(m3.value.a2)
}
return {
m1,
m2,
m3,
update
}
}
}
</script>
9.使用$parent和 $refs( $children已被移除)
9.1$parent
import { getCurrentInstance } from 'vue'
setup (props, ctx) {
const { proxy } = getCurrentInstance()
proxy.$parent.handleFun('我调用父亲')//该方法必须在父组件进行导出
}
9.2 $refs
<template>
<div class="main-box">
<RightBox ref="rightBoxRef" ></RightBox>
</div>
</template>
<script>
import RightBox from '/@/components/Index/RightBox.vue' // 右侧盒子
import {reactive, toRefs, ref,getCurrentInstance, unref} from "vue";
export default {
components: {
RightBox
},
setup() {
const {proxy} = getCurrentInstance()
const rightBoxRef = ref(null);
setTimeout(()=>{
const rightRef = unref(rightBoxRef);
rightRef.openLink()//调用子组件方法,改方法必须在子组件进行导出
},1000)
return {
};
},
}
</script>
<style lang="scss" scoped>
@import './index.scss';
</style>
10. 生命周期
<template>
<div class="about">
<h2>msg: {{msg}}</h2>
<hr>
<button @click="update">更新</button>
</div>
</template>
<script lang="ts">
import {
ref,
onMounted,
onUpdated,
onUnmounted,
onBeforeMount,
onBeforeUpdate,
onBeforeUnmount
} from "vue"
export default {
setup() {
const msg = ref('abc')
const update = () => {
msg.value += '--'
}
onBeforeMount(() => {
console.log('--onBeforeMount')
})
onMounted(() => {
console.log('--onMounted')
})
onBeforeUpdate(() => {
console.log('--onBeforeUpdate')
})
onUpdated(() => {
console.log('--onUpdated')
})
onBeforeUnmount(() => {
console.log('--onBeforeUnmount')
})
onUnmounted(() => {
console.log('--onUnmounted')
})
return {
msg,
update
}
}
}
</script>
11.计算属性与监视
<template>
<h2>App</h2>
fistName: <input v-model="user.firstName"/><br>
lastName: <input v-model="user.lastName"/><br>
fullName1: <input v-model="fullName1"/><br>
fullName2: <input v-model="fullName2"><br>
fullName3: <input v-model="fullName3"><br>
</template>
<script lang="ts">
/*
计算属性与监视
1. computed函数:
与computed配置功能一致
只有getter
有getter和setter
2. watch函数
与watch配置功能一致
监视指定的一个或多个响应式数据, 一旦数据变化, 就自动执行监视回调
默认初始时不执行回调, 但可以通过配置immediate为true, 来指定初始时立即执行第一次
通过配置deep为true, 来指定深度监视
3. watchEffect函数
不用直接指定要监视的数据, 回调函数中使用的哪些响应式数据就监视哪些响应式数据
默认初始时就会执行第一次, 从而可以收集需要监视的数据
监视数据发生变化时回调
*/
import {
reactive,
ref,
computed,
watch,
watchEffect
} from 'vue'
export default {
setup () {
const user = reactive({
firstName: 'A',
lastName: 'B'
})
// 只有getter的计算属性
const fullName1 = computed(() => {
console.log('fullName1')
return user.firstName + '-' + user.lastName
})
// 有getter与setter的计算属性
const fullName2 = computed({
get () {
console.log('fullName2 get')
return user.firstName + '-' + user.lastName
},
set (value: string) {
console.log('fullName2 set')
const names = value.split('-')
user.firstName = names[0]
user.lastName = names[1]
}
})
const fullName3 = ref('')
/*
watchEffect: 监视所有回调中使用的数据
*/
/*
watchEffect(() => {
console.log('watchEffect')
fullName3.value = user.firstName + '-' + user.lastName
})
*/
/*
使用watch的2个特性:
深度监视
初始化立即执行
*/
watch(user, () => {
fullName3.value = user.firstName + '-' + user.lastName
}, {
immediate: true, // 是否初始化立即执行一次, 默认是false
deep: true, // 是否是深度监视, 默认是false
})
/*
watch一个数据
默认在数据发生改变时执行回调
*/
watch(fullName3, (value) => {
console.log('watch')
const names = value.split('-')
user.firstName = names[0]
user.lastName = names[1]
})
/*
watch多个数据:
使用数组来指定
如果是ref对象, 直接指定
如果是reactive对象中的属性, 必须通过函数来指定
*/
watch([() => user.firstName, () => user.lastName, fullName3], (values) => {
console.log('监视多个数据', values)
})
return {
user,
fullName1,
fullName2,
fullName3
}
}
}
</script>
更多推荐
已为社区贡献1条内容
所有评论(0)