2021前端面试题系列: VUE相关的基础面试题
大家好,我是前端岚枫,今天主要跟大家分享我整理的笔记2021前端面试题系列:vue传值方式、vuex、组件封装等等,此方面内容在我们的工作中常用到, 也是面试官经常提问的问题,希望下面文章对大家有所帮助。
vue 传值方式
vue传值
- 父 子 传值 使用props接受
- 子 父 传值 父亲写事件函数 子 $emit触发 传值
- 兄弟传值 $bus 中转站
- 如果组件之间 关系很远 是很多组件都要用的值 vuex
- provide, inject注入方式
vuex 就是一个全局状态数据管理 简单来说 他的数据类似全局变量 哪个组件都可以使用
在项目中使用vuex
- 下载 vuex 包 并导入 use一下
import Vuex from 'vuex'
Vue.use(Vuex)
- 需要new 一下 写上全局数据
// store
new Vuex.Store({
state: {
count:1 //这个count 就是全局的数据
},
mutations: {
},
actions: {
}
})
- 需要挂载到new vue上
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
<template>
<div class="home">
<!-- home啊
<hr>
{{$store.state.m1.m1Name}}
<button @click="add">点击</button> -->
<!-- <hr> -->
<!-- <my-swiper :list="list"></my-swiper> -->
<button @click="getAll">发送请求</button>
home组件啊
<hr>
<h1>count的值:{{$store.state.count}}</h1>
<button @click="addCount">让全局count+1</button>
<hr>
<h2>m1下的全局数据 {{$store.state.m1.m1Name}} </h2>
<button @click="add">点击修改某个模块的数据</button>
<!-- 3 哪个组件要用 就直接 使用注册的组件标签名 -->
<hr>
<!-- 用组件 传了list数据进去 -->
<my-swiper :list="list"></my-swiper>
</div>
</template>
<script>
// 要在组件使用全局数据
// 1 在html范围 直接 $store.state.名字
// 2 在js范围 this.$store.state.名字
// @ is an alias to /src
// import HelloWorld from '@/components/HelloWorld.vue'
import { mapMutations , mapActions ,mapState } from 'vuex'
export default {
name: 'Home',
components: {
// HelloWorld
},
data(){
return {
list:[
{id:1,src:'http://122.51.238.153/images/1.jpg'},
{id:2,src:'http://122.51.238.153/images/2.jpg'},
{id:3,src:'http://122.51.238.153/images/3.jpg'},
{id:4,src:'http://122.51.238.153/images/4.jpg'}
]
}
},
created(){
console.log('created')
console.log('store',this.$store)
},
mounted(){
console.log("home 的 mounted")
},
methods:{
// 这句话的意思是 直接 解构出 全局 m1模块下的 loginMutation
// 把loginMutation 放到this上 并且帮你写好了 commit
// 相当于帮你简化了代码
...mapMutations('m1', ['loginMutation']),
//不是modules的直接写 ...mapMutations( ['loginMutation'])
add(){
// console.log('add',this)
// console.log('add',this.$route.meta)
// this.$store.commit("m1/loginMutation")
// 或者下面的 先mapMutations 相当于帮你写了commit
this.loginMutation()
// this.$store.commit("m1/loginMutation")
// 和刚刚的思路 就是加上一个模块前缀 m1/
// this.$store.dispatch("m1/loginAction")
},
async getAll(){
// http://localhost:8080/
// 请求 http://122.51.238.153/getok.php
// let res=await this.$http.get("http://122.51.238.153/getok.php")
// console.log('res',res)
let res=await this.$http.get("/api/getok.php")
console.log('res',res)
},
addCount(){
// 让全局数据count+1
// 1 正常情况
// dispatch 触发action
// -》commit触发mutation
// -》在mutation修改全局数据
//2 其他情况 可以直接跳过action 但是必须mutation修改
// console.log('$store',this.$store)
// this.$store.dispatch( 'countAction' )
this.$store.commit("countMutation")
}
}
}
</script>
这个步骤是写死的 你可以记一下 下载使用脚手架直接就可以选vuex
他的使用逻辑是什么?
在 store里面的 state 写的数据 是全局数据 所有组件都可以使用
使用逻辑
操作全局vuex的 state数据
正常情况 必须 dispatch (action)—>action去commit触发 mutation–》mutation里面才能修改state全局数据
action--->mutation--->修改state
其他情况 你也可以跳过 action 去 直接 commit mutation–》修改state全局数据
vuex怎么合理规范管理数据,及mutations和actions区别
解析: 此题考查 vuex中数据的管理和数据结构的设计,还有mutations 和actions的区别
**解答**
: 首先要明确一个特别重要的原则, 就是 不是所有的数据都要放在vuex中, 因为vuex有一句名言:假如你并不知道为什么要使用vuex,那就不要使用它 !那么什么样式的数据需要放在vuex中呢 ? 首先这个数据肯定要被多个组件频繁用到, 如果只是被一个组件 用到, 那完全没有任何必要为了使用vuex和使用vuex
举例: 一个网站用户的昵称,账号,资料,像这种系统级别的信息 随时可能在业务中展示,使用, 如果在组件中存储, 那么要获取N次, 所以**系统级别的数据**
是需要放置在vuex中的, 那么系统级别数据 也不能所以的放置,为了让数据看着更有层级结构感,可以按照像下面这样设计,
{
// 系统消息
system: {
user: {},
setting: {}
}
}
上面这种结构,一看 便知道我们应该哪里获取系统数据即 设置数据
如果有些业务数据,也需要共享,最好按照模块的具体业务含义分类 , 比如下面
{
// 系统消息
system: {
user: {},
setting: {}
},
product: {
productList: [], // 商品信息列表
productOrders: [] // 商品订单啊列表
}
}
如上图代码所示,我们很清晰的能够分清楚 每个模块的数据,这样不会导致数据管理的混乱
mutations和 actions 的区别
不同于redux只有一个action, vuex单独拎出了一个mutations, 它认为 更新数据必须是同步的, 也就是只要调用了 提交数据方法, 在mutation里面才可以修改数据
那么如果我们想做 异步请求,怎么做? 这里 vuex提供了专门做异步请求的模块,action, 当然action中也可以做同步操作, 只不过 分工更加明确, 所有的数据操作 不论是同步还是异步 都可以在action中完成,
mutation只负责接收状态, 同步完成
**数据快照**
所以可以认为
state => 负责存储状态
mutations => 负责同步更新状态
actions => 负责获取 处理数据(如果有异步操作必须在action处理 再到mutation), 提交到mutation进行状态更新
vuex模块化module管理,使用的时候有注意事项
分析: 此题考查 当vuex维护的数据越来越复杂的时候, 模块化的解决方案
**解析**
:使用单一的状态树,应用的所有状态都会**集中在一个比较大的对象**
上面,随着项目需求的不断增加,状态树也会变得越来越臃肿,增加了状态树维护的复杂度,而且代码变得沉长;因此我们需要**modules(模块化)**
来为我们的状态树**分隔**
成不同的模块,每个模块拥有自己的state,getters,mutations,actions;而且允许每个module里面嵌套子module;如下:
store
├── index.js # 我们组装模块并导出 store 的地方
├── actions.js # 根级别的 action
├── mutations.js # 根级别的 mutation
├── state.js # 根级别的 state
└── modules
├── module1.js # 模块1的state树
└── module2.js # 模块2的state树
上面的设计中, 每个vuex子模块都可以定义 state/mutations/actions
需要注意的是 我们原来使用
**vuex辅助函数**
mapMutations/mapActions 引入的是 全局的的mutations 和actions , 并且我们vuex子模块 也就是module1,module2 … 这些模块的aciton /mutation 也注册了全局,也就是如果 module1 中定义了 loginMutation, module2中也定义了 loginMutation, 此时, mutation就冲突了
如果重名,就报错了…
如果不想冲突, 各个模块管理自己的action 和 mutation ,需要 给我们的子模块一个 属性
**namespaced: true**
那么 组件中怎么使用子模块的action 和 mutations
// 你可以将模块的空间名称字符串作为第一个参数传递给上述函数,这样所有绑定都会自动将该模块作为上下文
methods:{
...mapMutations('m1', ['loginMutation']),
add(){
console.log('add',this)
// this.$store.commit("m1/loginMutation")
// 或者下面的 先mapMutations 相当于帮你写了commit
// this.loginMutation()
}
}
// 这句话的意思是 直接 解构出 全局 m1模块下的 loginMutation
// 把loginMutation 放到this上 并且帮你写好了 commit
// 相当于帮你简化了代码
...mapMutations('m1', ['loginMutation']),
//不是modules的直接写 ...mapMutations( ['loginMutaton])
store.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// 1 下载vuex 导入 use一下
// 2 new Vuex.Store
// 3 挂载到new vue上
export default new Vuex.Store({
state: {
// 在这里写的就是所有组件都能有 全局数据了
// 名字:值
// 如果我1000个全局数据 有可能重名
count:100
},
mutations: {
countMutation(state){
// state 就是那个全局state
console.log('mutation触发了',state)
state.count++
}
},
actions: {
// action对应的函数
countAction(obj){
console.log('action触发了',obj)
// obj对象 里面有commit
obj.commit("countMutation")
}
},
// modules 在store全局数据 是可以来分模块管理的
// 他可以用来区分每个不同模块的数据
// 15:10 上课
modules: {
// 模块:{ 一套state action mutation }
m1: {
namespaced: true,//开启命名空间大白话 他是m1下的 不会影响其他人
// 模块内容(module assets)
state: { // 模块内的状态已经是嵌套的了,使用 `namespaced` 属性不会对其产生影响
m1Name:"我是m1模块的m1Name"
},
actions: {
loginAction () {
console.log('m1的action')
} // -> dispatch('m1/loginAction')
},
mutations: {
loginMutation () {
console.log('loginMutation-执行啦')
} // -> commit('m1/loginMutation')
}
},
home:{
namespaced: true,
state:{
count:1
}
},
about:{
namespaced: true,
state:{
count:100
},
actions:{
}
},
}
})
此题具体考查 Vuex虽然是一个公共状态, 但是公共状态还可以切分成若干个子状态模块, 也就是moduels,
解决当我们的状态树过于庞大和复杂时的一种解决方案. 但是笔者认为, 一旦用了vuex, 几乎 就认定该项目是较为复杂的
封装Vue组件的步骤
组件是什么?组件是一段功能代码 —大白话 就是一段html +js +css 你可以重复使用
封装轮播图 - 1 新建vue组件 2 Vue.component注册组件 3 在其他组件使用 标签名
参数: 可以传入数据 使用props接受 比如 数组 定时器时间等
分析: 本题考查 对于Vue组件化开发的熟练程度
解析: 首先明确 组件是本质是什么?
组件就是一个单位的HTML结构 + 数据逻辑 + 样式的 操作单元
Vue的组件 继承自Vue对象, Vue对象中的所有的属性和方法,组件可自动继承.
- 组件的要素 template => 作为页面的模板结构
- script => 作为数据及逻辑的部分
- style => 作为该组件部分的样式部分
要封装一个组件,首先要明确该组件要做的具体业务和需求, 什么样的体验特征, 完成什么样的交互, 处理什么样的数据
明确上述要求之后, 着手模板的结构设计及搭建,也就是 常说的html结构部分, 先完成 静态的html结构
结构完成, 着手数据结构的设计及开发, 数据结构一般存储于组件的data属性 或者 vuex 状态共享的数据结构
数据设计完成/ 结构完成 接下来 完成数据和模块的结合 , 利用vuejs中指令和 插值表达式的特性 将静态结构
**动态化**
展现的部分完成, 接下来完成
**交互部分**
,即利用 组件的生命周期的钩子函数 和 事件驱动 来完成 逻辑及数据的处理与操作
最后组件完成,进行测试及使用
常用的组件属性 => data/ methods/filters/ components/watch/created/mounted/beforeDestroy/computed/props
常用组件指令: v-if/v-on/v-bind/v-model/v-text/v-once
Vue中的data是以函数的形式还是对象的形式表示
分析: 此题考查 data的存在形式
解析: 我们在初步学习Vue实例化的时候写的代码时这个样子上面代码中的data 是一个对象, 但是我们在开发组件的时候要求data必须是一个带返回值的函数
new Vue({
el: '#app',
data: {
name: 'hello world'
}
})
export default {
data () {
return {
name: '张三'
}
}
}
为什么组件要求必须是带返回值的函数? 因为 我们的组件在实例化的时候, 会直接将data数据作用在视图上,对组件实例化, 会导致我们组件的data数据进行共享, 好比 现在有两辆新车, 你一踩油门, 不光你的车往前车,另辆车也和你一样往前冲! 这显然不符合我们的程序设计要求, 我们希望组件内部的数据是相互独立的,且互不响应,所以 采用 return {} 每个组件实例都返回新对象实例的形式,保证每个组件实例的唯一性
关注:程序员石磊,获取更多面试资料