vue2面试题总结

vue中祖孙组件间的通信之使用$attrs和$listeners的方式
$attrs的用法
- 正常情况下:父组件通过v-bind绑定一个数据传递给子组件,子组件通过props接收到就可以在子组件的html中使用了。但是,如果父组件v-bind传递给子组件,子组件没有用props接收呢?
- 注意:这个时候,父组件传递过来的数据就会被挂载(赋值)到这个子组件自带的对象$attrs上面,所以:
$attrs就是一个容器对象,这个容器对象会存放:父组件传过来的且子组件未使用props声明接收的数据
$attrs就是一个容器对象,这个容器对象会存放:父组件传过来的且子组件未使用props声明接收的数据
爷组件传递给孙组件的逻辑流程就是,通过爷组件首先传递给父组件,当然父组件不在props中接收,那么爷组件传递给父组件的数据就会存放到父组件的$attrs对象中里面了,然后,再通过v-bind="$attrs",再把这个$attr传递给孙组件,在孙组件中使用props就能接收到$attrs中的数据了,这样就实现了,祖孙之间的数据传递。
$Listeners的用法
使用$listeners可以实现孙组件的数据传递到爷组件中去,逻辑的话,也是用在中间的桥梁父组件上面去,我的理解就是$listeners可以将子组件emit的方法通知到爷组件。
<template>
<div>
<child
name="名字"
@change="change"></child>
</div>
</template>
<script>
export default {
methods: {
change() {
alert("孙组件传出来的时间")
}
},
}
</script>
child.vue
<template>
<div>
<grand-child
v-bind="$attrs"
v-on="$listeners"></grand-child>
</div>
</template>
<script>
</script>
<template>
<div>
名字:{{name}}
<div @click="btn">
点击事件
</div>
</div>
</template>
<script>
export default {
inheritAttrs :false,
props: {
name: {
type: String,
default: ''
},
},
methods: {
btn() {
this.$emit('change')
}
},
}
</script>
$set的用法
set 是 Vue.js 中的一个全局API,主要用于动态向响应式对象中添加新属性或者修改已有属性,并确保新属性也是响应式的。
如何使用 $set:
this.$set 方法接受三个参数:
- 目标对象target:需要添加属性的对象。
- 键名name/index:你要添加的属性名称或数字的索引。
- 值value:该属性的值或者数组索引的值。
new Vue({
el: '#app',
data: {
userProfile: {
name: 'Alice'
}
},
mounted() {
// 正确的添加响应式属性
this.$set(this.userProfile, 'age', 25);
}
});
vuex
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式
它采用集中式存储管理应用的所有组件的状态
并以相应的规则保证状态以一种可预测的方式发生变化
所以vuex就是一个仓库,用来存放数据的。所以我们使用vuex一般会新建一个store文件夹,store单词的中文意思就是商店、仓库的意思
vuex的应用场景
- 正常数据放到data里面就行了,免得麻烦,一般小项目都很少用到vuex,毕竟vuex的步骤稍微多一点
- 一般公共数据放到vuex中会比较好,毕竟组件有自己的data可以存放数据,公共的变量如用户信息、token等。vuex存一份,localstorage再存一份,取数据直接从vuex里面取,取不到再从localstorage里面去取。
- 跨很多组件层级的数据通信,也可以通过vuex去做管理,毕竟vuex就像一个对象一个,好多组件都指向这个对象,当这个vuex对象发生了变化,所有的组件中对应的内容都会发生变化,这样就能做到实时响应,一个变,大家都变
vuex使用
在上述代码中,我们已经在vuex中的state里面定义了一个msg属性
export default new Vuex.Store({
state:{
msg:'我是vuex哦'
},
// 等...
})
使用mounted中去取用vuex中的数据
<template>
<div class="box">
<h2>{{msg}}</h2>
</div>
</template>
<script>
export default {
data() {
return { msg:'' }
},
mounted() {
this.msg = this.$store.state.msg
},
}
</script>
使用computed去取vuex中的数据
<template>
<div class="box">
<h2>{{msg}}</h2>
</div>
</template>
<script>
export default {
computed: {
msg(){ return this.$store.state.msg }
}
}
</script>
修改vuex中的数据
方法1 一action-->mutation-->state
组件代码如下
<template>
<div class="box">
<h2>{{msg}}</h2>
<el-button @click="changeVuex">修改</el-button>
</div>
</template>
<script>
export default {
methods: {
changeVuex(){
this.$store.dispatch('actionsChange')
},
},
computed: {
msg(){ return this.$store.state.msg }
}
}
</script>
export default new Vuex.Store({
strict:true,
state:{
msg:'我是vuex哦'
},
mutations:{
// 这里第一个形参state就是仓库state,是可以访问到state里的msg的值,即 可以修改state
// 第二个形参params是actions中传过来的数据
mutationsChange(state,params){
console.log(state,params);
state.msg = params
}
},
actions:{
// 这里的形参store对象下面有commit方法
// 可以去告知对应的mutations中的函数执行
actionsChange(store){
console.log(store);
setTimeout(() => {
store.commit('mutationsChange', '规范修改vuex')
}, 500);
}
}
})
方法2 getter
getter中我们可以定义一个函数,这个函数我们用来修改state中的值的,函数接收一个参数state,这个state参数就是当前的state对象,通过这个参数可以加工state中的数据,加工好return出去,以供组件中使用
// vuex
export default new Vuex.Store({
strict:true,
state:{
msg:'我是vuex哦'
},
getters:{
gettersChange(state){
return state.msg + '---getter修改state中的数据'
}
},
})
this.$store.getters.gettersChange
方法3 mapState辅助函数
第一步,假设vuex仓库中有三个数据,我们需要在组件上使用这三个数据
// store.js
export default new Vuex.Store({
state:{
msg1:'辅助函数一',
msg2:'辅助函数二',
msg3:'辅助函数三',
},
}
第二步,从vuex插件中引入辅助函数
import { mapState, mapMutations, mapActions, mapGetters } from 'vuex'
// 方式一,数组形式
computed: {
...mapState(['msg1','msg2','msg3'])
},
// 方式二, 对象形式(vuex模块化比较常用)
computed: {
...mapState({
msg1: state=>state.msg1,
msg2: state=>state.msg2,
msg3: state=>state.msg3,
})
},
<template>
<div>
<h1>{{msg1}}</h1>
<h2>{{msg2}}</h2>
<h3>{{msg3}}</h3>
</div>
</template>
在组件中使用vuex模块化
<template>
<div>
<h2>{{ msg }}</h2>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: "CodeVue",
computed: {
// 正常方式
msg(){
return this.$store.state.vue.module// 找state里的vue模块下的module的值
},
// 使用辅助函数方式,这里用对象的写法
...mapState({
msg:state=>state.vue.module// 找state里的vue模块下的module的值
})
}
};
</script>
不使用辅助函数
<template>
<div>
<h2>{{ msg }}</h2>
<el-button @click="moduleChange">模块化修改值</el-button>
</div>
</template>
<script>
export default {
name: "CodeVue",
computed: {
...mapState({
msg:state=>state.vue.module
})
},
methods: {
moduleChange(){
// 注意,直接提交对应模块的方法即可,commit会自动找到对应vuex下的方法
this.$store.commit('moduleChange','我是参数')
}
},
};
</script>
使用辅助函数
<template>
<div>
<h2>{{ msg }}</h2>
<!-- 我们在点击事件的语句中,把data中定义的参数带过去,去提交mutations -->
<el-button @click="moduleChange(canshu)">模块化修改值</el-button>
</div>
</template>
<script>
import { mapState, mapMutations } from 'vuex'
export default {
name: "CodeVue",
data() {
return {
canshu:'我是参数'
}
},
computed: {
...mapState({
msg:state=>state.vue.module
})
},
methods: {
...mapMutations(['moduleChange'])
},
};
</script>
写法如下
// 不使用辅助函数
moduleChange(){
this.$store.commit('vue/moduleChange'); // 以斜杠分割,斜杠前写对应模块名,斜杠后写对应mutations中的方法名
}
// 使用辅助函数
...mapMutations('vue',['moduleChange']) // 以逗号分割,逗号前写模块名,逗号后是个数组,数组中放置对应mutations中的方法名
//3.别名状态下
...mapMutations({
anotherName:'vue/moduleChange' // 和不使用辅助函数一样
}),
vue实例bus
vue实例bus的用法就相当于一个中间快递小哥,会帮我们在兄弟组件间进行数据传递。
1. EventBus 的基本使用:
创建一个 EventBus
创建一个 EventBus.js 文件(或直接在 main.js 中):
import Vue from 'vue'; export const EventBus = new Vue();
发送消息
// ComponentA.vue
<template>
<div>
<button @click="sendMessage">发送消息</button>
</div>
</template>
<script>
import { EventBus } from './EventBus.js'; // 导入 EventBus
export default {
methods: {
sendMessage() {
EventBus.$emit('message', '来自 ComponentA 的消息');
}
}
}
</script>
接收消息
// ComponentB.vue
<template>
<div>
<p>{{ message }}</p>
</div>
</template>
<script>
import { EventBus } from './EventBus.js'; // 导入 EventBus
export default {
data() {
return {
message: ''
};
},
created() {
// 在组件创建时监听事件
EventBus.$on('message', (msg) => {
this.message = msg;
});
},
destroyed() {
// 组件销毁时移除事件监听
EventBus.$off('message');
}
}
</script>
keep-alive 的作用
keep-alive 主要用于包裹动态组件,使得这些组件在切换时被缓存,而不是销毁。具体的作用如下:
- 缓存组件状态:当组件被缓存后,组件的状态、数据、DOM 等会被保留。当组件再次显示时,不需要重新初始化,而是从缓存中恢复状态。
- 避免重新渲染:如果没有使用
keep-alive,当切换到其他视图时,组件会被销毁并重新渲染,使用keep-alive可以避免这个过程,提高性能。 - 提升性能:对于有较大渲染开销的组件(如表单、列表、图表等),
keep-alive可以显著提升性能,减少重新渲染的次数。 keep-alive还提供了一些属性来定制缓存行为,常见的属性包括:
keep-alive 还提供了一些属性来定制缓存行为,常见的属性包括:
include: 只缓存名称匹配的组件。
<keep-alive :include="['ComponentA', 'ComponentB']"> <component :is="currentComponent"></component> </keep-alive>
exclude: 只排除名称匹配的组件。
exclude 属性则用于排除某些组件不被缓存:
<keep-alive :exclude="['ComponentC']"> <component :is="currentComponent"></component> </keep-alive>
max: 最多缓存的组件个数。
max 属性限制了缓存的组件数量,当缓存的组件超过这个数量时,最不常用的组件会被销毁:
<keep-alive :max="3"> <component :is="currentComponent"></component> </keep-alive>
使
keep-alive 缓存的生命周期
activated:当组件从缓存中被激活时调用,通常用于恢复状态或执行某些操作。
deactivated:当组件被缓存时调用,通常用于暂停或清理一些操作,如停止定时器、解绑事件等。
示例:
<template>
<div>
<keep-alive>
<component :is="currentComponent"></component>
</keep-alive>
</div>
</template>
<script>
export default {
data() {
return {
currentComponent: 'ComponentA'
};
},
methods: {
switchComponent() {
this.currentComponent = this.currentComponent === 'ComponentA' ? 'ComponentB' : 'ComponentA';
}
}
};
</script>
<script>
export default {
name: 'ComponentA',
activated() {
console.log('ComponentA 被激活');
},
deactivated() {
console.log('ComponentA 被缓存');
}
};
</script>
Vuex使用
Vuex 是 Vue.js 的状态管理库,用于集中管理应用的状态。在 Vuex 中有多个核心属性:`state`、`mutations`、`actions`、`getters`、`modules` 等,每个属性都有特定的使用场景。下面是各个 Vuex 属性在实际项目中的常见使用场景:
### 1. **`state`:存储应用的状态**
`state` 是 Vuex 中存储全局共享状态的地方,任何组件都可以访问和修改 `state` 中的数据。适用于需要跨多个组件共享和管理的数据。
#### 使用场景:
- **用户认证状态**:例如存储当前用户的登录信息(如用户 ID、Token、用户名等),让应用的其他部分根据这些信息调整界面展示。
- **示例**:存储用户信息(如 `user` 对象)或权限数据(如 `isLoggedIn`)。
- **购物车信息**:在电商应用中,购物车数据通常存储在 `state` 中,所有页面组件都可以访问和修改购物车的商品列表、数量和价格等信息。
- **示例**:存储 `cart` 数组,包含购物车中的商品。
- **全局配置**:比如语言设置、主题(深色/浅色模式)等,存储这些信息以便全局管理和调整。
- **示例**:存储 `language` 或 `theme` 设置。
```javascript
const store = createStore({
state: {
user: null,
cart: [],
language: 'en'
}
});
```
### 2. **`mutations`:同步修改状态**
`mutations` 是用来修改 `state` 中数据的唯一方式,Vuex 通过 `mutations` 来保证状态变更的可追踪性。`mutations` 是同步操作。
#### 使用场景:
- **更新用户数据**:用户登录后,需要更新用户的认证信息(如用户名、Token 等)。
- **示例**:当用户登录时,通过 `setUser` mutation 更新用户信息。
- **修改UI状态**:在全局状态中管理 UI 的显示或隐藏,避免在多个组件中重复管理。
- **示例**:更新一个加载状态(`isLoading`)或弹出框显示状态(`isModalOpen`)。
- **数据更新**:例如,更新购物车中商品的数量,移除商品等。
- **示例**:`addToCart`、`removeFromCart` 之类的 mutation。
```javascript
const store = createStore({
mutations: {
setUser(state, user) {
state.user = user;
},
addToCart(state, product) {
state.cart.push(product);
}
}
});
```
### 3. **`actions`:异步操作**
`actions` 用于处理异步操作,通常是向服务器请求数据、提交表单或等待某些操作完成后,再通过调用 `mutations` 来修改 `state`。
#### 使用场景:
- **获取远程数据**:请求服务器端的用户数据、商品列表等。
- **示例**:当应用加载时,发起请求获取用户数据,并更新 `state`。
- **处理表单提交**:在提交表单时,进行一些验证或与后端进行异步交互,然后通过 `mutations` 来修改应用状态。
- **示例**:在提交购物车订单时,进行异步请求并在请求成功后更新购物车状态。
- **延时操作**:比如一些需要延时执行的操作(例如动画、轮询请求)通常在 `actions` 中处理。
- **示例**:发起数据请求后,等待返回结果并处理。
```javascript
const store = createStore({
actions: {
async fetchUser({ commit }) {
const response = await fetch('/api/user');
const user = await response.json();
commit('setUser', user);
},
async addToCart({ commit }, productId) {
const response = await fetch(`/api/products/${productId}`);
const product = await response.json();
commit('addToCart', product);
}
}
});
```
### 4. **`getters`:计算派生状态**
`getters` 用于从 `state` 中派生出新的数据,通常用于进行计算、过滤、排序等操作。类似于组件中的计算属性(`computed`)。
#### 使用场景:
- **过滤数据**:例如,获取购物车中所有已选择的商品,或根据某些条件过滤用户数据。
- **示例**:`cartItems` 计算已选商品,`userFullName` 拼接用户的完整名称。
- **计算派生值**:例如,计算购物车中商品的总价格、购物车商品数量等。
- **示例**:获取购物车的总金额(`totalPrice`)或商品数量(`cartCount`)。
- **格式化数据**:对日期、金额等进行格式化显示。
- **示例**:将时间戳格式化为可读日期,或将金额格式化为带有货币符号的字符串。
```javascript
const store = createStore({
getters: {
cartCount(state) {
return state.cart.length;
},
cartTotal(state) {
return state.cart.reduce((total, product) => total + product.price, 0);
}
}
});
```
### 5. **`modules`:模块化管理**
当应用变得复杂时,使用 `modules` 可以将 Vuex store 划分成多个模块,每个模块拥有自己的 `state`、`mutations`、`actions` 和 `getters`,使得管理状态变得更加清晰。
#### 使用场景:
- **大型应用拆分业务逻辑**:对于大型应用,使用模块化可以让每个模块负责独立的业务逻辑,如用户模块、购物车模块、订单模块等。
- **示例**:将 `user`、`cart`、`product` 分拆成不同的模块。
- **避免 state 冲突**:当应用的状态过多时,将状态分隔到不同的模块中,有助于避免命名冲突或过于庞大的状态对象。
- **跨模块共享状态**:可以通过 `root` store 或 `actions` 跨模块访问和操作其他模块的 `state`。
```javascript
const store = createStore({
modules: {
user: {
state: { user: null },
mutations: { setUser(state, user) { state.user = user; } },
actions: { fetchUser({ commit }) { /* fetch logic */ } }
},
cart: {
state: { items: [] },
mutations: { addToCart(state, product) { state.items.push(product); } },
actions: { addProductToCart({ commit }, product) { /* async logic */ } }
}
}
});
```
### 总结
Vuex 属性的使用场景可以概括如下:
- **`state`**:用于存储全局共享的应用状态。
- **`mutations`**:用于同步修改 `state` 中的值,确保状态的可追溯性。
- **`actions`**:处理异步操作,发起 API 请求或执行延时任务,最后通过 `mutations` 修改 `state`。
- **`getters`**:计算派生状态,可以用于过滤、计算、格式化数据等。
- **`modules`**:将 store 分割成多个模块,以便更好地组织和管理复杂应用的状态。
通过合理利用 Vuex 的这些功能,能够让应用的状态管理更加清晰、易于维护。
vuex和pinia的区别
1. 设计理念和目标
-
Vuex:
Vuex是 Vue.js 官方的状态管理库,最初设计用于 Vue 2,并为 Vue 2.x 提供了一个集中式的状态管理解决方案。- 它的设计目标是通过“单一数据源”来管理整个应用的状态,遵循严格的“mutation”和“action”规则,以确保状态的可预测性和调试能力。
-
Pinia:
Pinia是 Vue 3 专为 Vue 3 设计的状态管理库,是 Vuex 的现代替代品,旨在提供更简洁、灵活、易用的状态管理方式。Pinia提供了更好的类型推导支持,更简单的 API,且完全支持 Vue 3 的 Composition API。
2. 支持的 Vue 版本
-
Vuex:
Vuex最初是为 Vue 2.x 设计的,但也提供了 Vue 3 的支持。对于 Vue 3,Vuex 仍然有效,但它并不完全利用 Vue 3 的新特性,比如 Composition API 和响应式 API。
-
Pinia:
Pinia是为 Vue 3 和 Composition API 设计的,充分利用了 Vue 3 的新特性,能够更好地与 Vue 3 集成,推荐在 Vue 3 项目中使用。
3. API 风格
-
Vuex:
Vuex采用了传统的基于store对象的管理方式,需要定义state、mutations、actions和getters。- 操作状态时需要通过
commit(触发 mutation)和dispatch(触发 action),使得 API 相对冗长。
// Vuex 示例
const store = new Vuex.Store({
state: {
count: 0
},
mutations: {
increment(state) {
state.count++;
}
},
actions: {
incrementAsync({ commit }) {
setTimeout(() => {
commit('increment');
}, 1000);
}
},
getters: {
doubleCount(state) {
return state.count * 2;
}
}
});
Pinia:
Pinia使用 Composition API 风格,提供了更简洁、声明式的 API,状态和计算属性(getters)直接在 store 中声明,并且可以直接访问state和getters,无需使用commit和dispatch。-
// Pinia 示例 import { defineStore } from 'pinia'; const useCounterStore = defineStore('counter', { state: () => ({ count: 0 }), actions: { increment() { this.count++; }, incrementAsync() { setTimeout(() => { this.count++; }, 1000); } }, getters: { doubleCount: (state) => state.count * 2 } });
4. 响应性
-
Vuex:
- 在 Vuex 中,
state是响应式的,但你需要通过 mutations 来修改状态。这个过程使得 Vuex 的更新机制相对复杂。 - 如果直接在组件中修改
state,Vuex 不会自动反应更新,必须通过mutation进行状态的修改。
- 在 Vuex 中,
-
Pinia:
Pinia中的状态是响应式的,直接在 store 中修改state即可自动触发视图更新,无需通过额外的 mutations 或 actions。- Pinia 更好地支持 Vue 3 的响应式系统,状态直接绑定在 Vue 组件中时,变更会自动反应。
5. 类型支持
-
Vuex:
- Vuex 对类型支持较弱,尤其是 Vuex 4.x 在 Vue 3 中,虽然有类型支持,但在一些复杂的应用中,类型推导可能并不总是完美。
-
Pinia:
Pinia从一开始就为 TypeScript 提供了良好的支持,类型推导更加准确和友好。你可以直接在 store 中定义类型,Pinia会自动推导出相关类型。
6. 模块化
-
Vuex:
- Vuex 提供了模块化机制,可以将状态拆分成多个模块,每个模块有自己的
state、mutations和actions。
- Vuex 提供了模块化机制,可以将状态拆分成多个模块,每个模块有自己的
// Vuex 模块化示例
const store = new Vuex.Store({
modules: {
counter: {
state: () => ({ count: 0 }),
mutations: {
increment(state) {
state.count++;
}
}
}
}
});
Pinia:
Pinia也支持模块化,每个 store 都是独立的模块,可以方便地按需导入和使用。-
// Pinia 模块化示例 import { defineStore } from 'pinia'; const useCounterStore = defineStore('counter', { state: () => ({ count: 0 }), actions: { increment() { this.count++; } } });
7. 插件支持
-
Vuex:
- Vuex 支持插件,可以通过 Vuex 插件来增强其功能。
-
Pinia:
- Pinia 也支持插件,插件可以用来处理持久化、日志记录、状态恢复等功能,但相比 Vuex 的插件系统更轻量。
8. 持久化
-
Vuex:
- 在 Vuex 中,持久化通常需要使用第三方库(如
vuex-persistedstate)来实现状态的持久化。
- 在 Vuex 中,持久化通常需要使用第三方库(如
-
Pinia:
Pinia可以通过插件轻松实现状态持久化,官方推荐使用 Pinia 的持久化插件来保存状态。
9. 性能
-
Vuex:
- Vuex 在小型项目中足够使用,但随着项目的增大,Vuex 的性能和复杂度可能会成为瓶颈,尤其是在状态更新频繁的情况下。
-
Pinia:
Pinia更加高效,特别是在 Vue 3 的响应式系统下,Pinia在性能方面做了很多优化,尤其是在大规模应用中表现更好。
| 特性 | Vuex | Pinia |
|---|---|---|
| 支持的 Vue 版本 | Vue 2 和 Vue 3 | 仅支持 Vue 3 |
| API 风格 | 基于 mutation 和 action | 基于 Composition API 和简洁的 API |
| 类型支持 | 支持,但不如 Pinia 完善 | 更好的类型推导支持 |
| 响应式支持 | 需要通过 mutations 修改 | 完全支持 Vue 3 的响应式系统 |
| 模块化 | 支持模块化,但较为复杂 | 支持模块化,简单易用 |
| 插件支持 | 支持插件 | 支持插件 |
| 持久化 | 需要第三方插件支持 |
内置持久化插件支持 |
计算属性computed和watch的区别
1. 全局守卫
全局守卫是应用于整个 Vue Router 的守卫,它们会在每次路由跳转时触发。全局守卫包括:
- beforeEach:在路由跳转之前调用。
- beforeResolve:在路由解析阶段之前调用(用于更复杂的路由守卫场景)。
- afterEach:在路由跳转之后调用。
2. 路由独享守卫
路由独享守卫是配置在某个特定路由中的守卫,它只会在该路由触发时执行。包括:
- beforeEnter:在进入路由之前调用。
3. 组件内守卫
组件内守卫是用在 Vue 组件中的守卫,它们是通过组件生命周期钩子来控制的。包括:
- beforeRouteEnter:在路由进入前调用。
- beforeRouteUpdate:在路由参数或路径更新时调用。
- beforeRouteLeave:在离开路由时调用。
路由守卫的作用
-
权限验证与身份认证 在用户访问某些页面之前,你可以检查用户是否已登录或是否有权限访问该页面。如果没有权限或未登录,通常会重定向到登录页面或显示提示信息。
-
数据加载 在某些情况下,进入某个页面时需要加载一些动态数据。你可以在路由守卫中发起异步请求,确保数据在页面渲染之前被加载完毕。
-
路由重定向 有时你可能希望根据某些条件重定向用户到另一个路由。例如,基于用户的角色权限,可能需要将用户从普通页面重定向到管理页面,或反之。
-
清理工作 在离开页面时,你可能需要执行一些清理工作,比如注销事件监听、清除定时器或取消 API 请求等。组件的
beforeRouteLeave守卫可以帮助你在路由跳转时进行清理。 -
动画与过渡控制 你可以在路由守卫中管理页面跳转的过渡效果。例如,在用户跳转到某个页面之前,触发一个页面加载动画,然后在页面加载完成后切换视图。
代码解析
1. 全局守卫 beforeEach
这是最常用的守卫类型,可以应用于所有路由。它在导航发生之前被调用,可以用来做全局性的权限检查或数据预加载。
router.beforeEach((to, from, next) => {
// to: 即将进入的目标路由对象
// from: 当前导航正要离开的路由
// next: 一个回调函数,用来通知Vue Router是否继续进行导航
if (to.matched.some(record => record.meta.requiresAuth)) {
if (!store.getters.isLoggedIn) {
next({
path: '/login',
query: { redirect: to.fullPath }
})
} else {
next()
}
} else {
next()
}
})
2、全局解析守卫 beforeResolve
这个守卫在全局前置守卫之后,但在组建守卫和异步路由组件加载之前被调用。
router.beforeResolve((to, from, next) => {
// 类似于 beforeEach,但是允许访问组件实例 `this`
// 因为当守卫被调用时,组件实例已经被创建了
})
3. 全局后置钩子
next 函数,因此不能影响导航本身。router.afterEach((to, from) => {
// ...
})
4. 路由独享守卫
可以在路由配置中直接定义,只作用于该路由。
const routes = [
{
path: '/secret',
component: SecretComponent,
beforeEnter: (to, from, next) => {
// ...
}
}
]
5. 组件内的守卫
export default {
beforeRouteEnter (to, from, next) {
// ...
}
}
beforeRouteUpdate: 在当前路由改变,但是该组件被复用时调用export default {
beforeRouteUpdate (to, from, next) {
// ...
}
}
如何实现css样式隔离
scoped 是一种简单的样式隔离方式。它通过为组件的每个样式自动加上特定的作用域标识符,使得样式只应用于该组件。<template>
<div class="card">
<p>This is a card component</p>
</div>
</template>
<script>
export default {
name: 'Card'
};
</script>
<style scoped>
.card {
background-color: lightgray;
padding: 10px;
}
</style>
2、使用 CSS 模块化
/* Button.module.css */
.button {
background-color: blue;
color: white;
padding: 10px;
border: none;
}
创建递归组件(TreeItem.vue)
<template>
<ul>
<li v-for="(node, index) in data" :key="node.id">
<span>{{ node.name }}</span>
<!-- 如果该节点有子节点,则递归渲染 -->
<tree-item v-if="node.children && node.children.length" :data="node.children"></tree-item>
</li>
</ul>
</template>
<script>
export default {
name: 'TreeItem',
props: {
data: {
type: Array,
required: true
}
}
}
</script>
<style scoped>
ul {
list-style-type: none;
padding-left: 20px;
}
li {
margin: 5px 0;
}
</style>
使用递归组件
<template>
<div>
<tree-item :data="treeData" />
</div>
</template>
<script>
import TreeItem from './components/TreeItem.vue';
export default {
components: {
TreeItem
},
data() {
return {
treeData: [
{
id: 1,
name: 'Root 1',
children: [
{ id: 2, name: 'Child 1-1', children: [] },
{ id: 3, name: 'Child 1-2', children: [
{ id: 4, name: 'Child 1-2-1', children: [] }
]
}
]
},
{
id: 5,
name: 'Root 2',
children: [
{ id: 6, name: 'Child 2-1', children: [] }
]
}
]
}
}
}
</script>
<style>
/* 可以根据需要设置父组件的样式 */
</style>
$watch侦听器。new Vue({
el: '#app',
data: {
items: [1, 2, 3, 4, 5]
}
});
Vue.js覆盖了数组的7个变异方法,这些方法可以直接触发视图更新。这些方法包括:
push()pop()shift()unshift()splice()sort()reverse()
$watch方法,用于侦听数据的变化。对于数组,$watch可以用来监听整个数组的变化或数组内元素的变new Vue({ el: '#app',
data: {
items: [1, 2, 3]
},
watch: {
items: {
handler(newVal, oldVal) {
console.log('数组变化了:', newVal, oldVal);
},
deep: true // 深度监听
}
}
});
自定义指令如何实现
可以通过vue.directive 来定义一个自定义指令
// main.js
import Vue from 'vue';
Vue.directive('focus', {
// 当绑定元素插入到 DOM 中时调用
inserted(el) {
// 聚焦元素
el.focus();
}
});
new Vue({
el: '#app',
render: h => h(App)
});
template使用
<template>
<div>
<input v-focus />
</div>
</template>
自定义指令的生命周期钩子
自定义指令有一些钩子函数,允许你在不同的阶段进行操作。常用的钩子函数有:
bind:指令和元素绑定时调用,仅调用一次。inserted:指令所在元素被插入父节点时调用。update:绑定的值变化时调用。componentUpdated:指令所在的组件更新时调用。unbind:指令和元素解绑时调用。
可以通过 Vue.directive 全局注册或者在组件中局部注册。指令的钩子函数提供了灵活性,使得你可以根据不同的需求对 DOM 元素进行操作。常见的场景包括动态样式调整、表单验证、权限等。
本文来自博客园,作者:键盘侠客,转载请注明原文链接:https://www.cnblogs.com/dongzi1997/p/18596514

浙公网安备 33010602011771号