web前端常见面试题

web前端常见面试题-Vue

1.什么是vue的生命周期?

Vue实例从创建到销毁的过程,就是生命周期。

也就是从开始创建、初始化数据、编译模板、挂载DOM->渲染、更新->渲染、卸载等一系列过程,我们称这是Vue的生命周期。

2.Vue生命周期总共有几个阶段?分别对应哪些钩子函数

它可以总共分为8个阶段:创建前/后,载入前/后,更新前/后,销毁前/销毁后

生命周期中有多个事件钩子,让我们在控制整个vue实例的过程时更容易形成好的逻辑。

beforecreated:
在实例初始化之后,el 和 data 并未初始化(这个时期,this变量还不能使用,在data下的数据,和methods下的方法,watcher中的事件都不能获得到;)

created:完成了 data 数据的初始化,el没有(这个时候可以操作vue实例中的数据和各种方法,但是还不能对"dom"节点进行操作;)

beforeMount:完成了 el 和 data 初始化 //这里的el是虚拟的dom;

mounted :完成挂载,在这发起后端请求,拿回数据,配合路由钩子做一些事情(挂载完毕,这时dom节点被渲染到文档内,一些需要dom的操作在此时才能正常进行)

beforeUpdate:是指view层数据变化前,不是data中的数据改变前触发;

update:是指view层的数据变化之后,

beforeDestory: 你确认删除XX吗?

destoryed :当前组件已被删除,清空相关内容

3.第一次页面加载会触发哪几个钩子?DOM 渲染在 哪个周期中就已经完成?

第一次页面加载时会触发 beforeCreate, created, beforeMount, mounted 这几个钩子

DOM 渲染在 mounted 中就已经完成了。

4.简单描述每个周期具体适合哪些场景

beforecreate : 可以在这加个loading事件,在加载实例时触发

created : 初始化完成时的事件写在这里,如在这结束loading事件,异步请求也适宜在这里调用

mounted : 挂载元素,获取到DOM节点

updated : 如果对数据统一处理,在这里写上相应函数 beforeDestroy : 可以做一个确认停止事件的确认框 nextTick : 更新数据后立即操作dom;

5.开发中常用的vue指令有哪些?

v-model:一般用在表达输入,很轻松的实现表单控件和数据的双向绑定

v-html:更新元素的innerHTML

v-text:文本插入和更新类似innerText

v-show与v-if:条件渲染,注意二者区别

v-on:click:可以简写为@click,@绑定一个事件。如果事件触发了,就可以指定事件的处理函数

v-for:基于源数据多次渲染元素或模板

v-bind:当表达式的值改变时,将其产生的连带影响,响应式地作用于DOM语法,v-bind:title=”msg”简写:title=“msg”

v-once页面的vue数据只加载一次

6.Vue绑定class的数组用法

1.对象方法v-bind:class="{'orange':isRipe, 'green':isNotRipe}2.数组方法v-bind:class="[class1,class2]"
3.行内v-bind:style="{color:color,fontSize:fontSize+'px'}

7.v-show与v-if的区别

v-show是css切换,v-if是完整的销毁和重新创建
使用频繁切换时用v-show,运行时较少改变时用v-if
V-if=’false’v-if是条件渲染,当false的时候
不会渲染
使用v-if的时候,如果值为false,那么页面将不会有这个html标签生成
v-show则是不管值是为true还是false,html元素都会存在,只是css中的display显示或隐藏
v-show 仅仅控制元素的显示方式,将 display 属性在 block 和 none 来回切换;而v-if会控制这个 DOM 节点的存在与否。当我们需要经常切换某个元素的显示/隐藏时,使用v-show会更加节省性能上的开销;当只需要一次显示或隐藏时,使用v-if更加合理。

8.Vue双向数据绑定的原理

Object.defineProperty 通过 getter 和 setter 劫持了对象赋值的过程,在这个过程中可以进行更新 dom 操作

首先我们为每个vue属性用Object.defineProperty()实现数据劫持,为每个属性分配一个订阅者集合的管理数组dep;
 然后在编译的时候在该属性的数组dep中添加订阅者,v-model会添加一个订阅者,{{}}也会,v-bind也会,只要用到该属性的指令理论上都会;
  接着为input会添加监听事件,修改值就等于为该属性赋值,则会触发该属性的set方法,在set方法内通知订阅者数组dep,订阅者数组循环调用各订阅者的update方法更新视图。
Vue数据绑定这样做的好处:组件数据改变时,不会修改存储prop的子组件数据,只是以子组件数据为媒介,完成对prop的双向修改。

9.简述一下,你理解的MVVM模式

M-model,model代表数据模型,也可以在model中定义数据修改和操作的业务逻辑

V-view,view代表UI组件,它负责将数据模型转化为UI展现出来

VM-viewmodel,viewmodel监听模型数据的改变和控制视图行为、处理用户交互,简单理解就是一个同步view和model的对象,连接model和view

10.Vue中computed和watch有什么区别

computed

computed是计算属性,也就是计算值,它更多用于计算值的场景
computed具有缓存性,computed的值在getter执行后是会缓存的,只有在它依赖的属性值改变之后,下一次获取computed的值时重新调用对应的getter来计算
computed适用于计算比较消耗性能的计算场景

watch

watch更多的是[观察]的作用,类似于某些数据的监听回调,用于观察props $emit或者本组件的值,当数据变化时来执行回调进行后续操作
无缓存性,页面重新渲染时值不变化也会执行

总结:当我们要进行数值计算,而且依赖于其他数据,那么把这个数据设计为computed
如果你需要在某个数据变化时做一些事情,使用watch来观察这个数据变化。

11.vue组件的scoped属性的作用

在style标签上添加scoped属性,以表示它的样式作用于当下的模块,很好的实现了样式私有化的目的;
但是也得慎用:样式不易(可)修改,而很多时候,我们是需要对公共组件的样式做微调的;
解决办法:

①:使用混合型的css样式:(混合使用全局跟本地的样式) 
<style> /* 全局样式 */ </style><style scoped> /* 本地样式 */ </style>

②:深度作用选择器(>>>)如果你希望 scoped 样式中的一个选择器能够作用得“更深”,例如影响子组件,你可以使用 >>> 操作符:<style scoped> .a >>> .b { /* ... */ } </style>

12.vue是渐进式的框架的理解

Vue的核心的功能,是一个视图模板引擎

我们可以通过添加组件系统、客户端路由、大规模状态管理来构建一个完整的框架。

更重要的是,这些功能相互独立,你可以在核心功能的基础上任意选用其他的部件,不一定要全部整合在一起。

可以看到,所说的“渐进式”,其实就是Vue的使用方式,同时也体现了Vue的设计的理念
渐进式代表的含义是:主张最少。视图模板引擎
每个框架都不可避免会有自己的一些特点,从而会对使用者有一定的要求,这些要求就是主张,主张有强有弱,它的强势程度会影响在业务开发中的使用方式。

比如说,Angular,它两个版本都是强主张的,如果你用它,必须接受以下东西:
必须使用它的模块机制- 必须使用它的依赖注入- 必须使用它的特殊形式定义组件(这一点每个视图框架都有,难以避免)
所以Angular是带有比较强的排它性的,如果你的应用不是从头开始,而是要不断考虑是否跟其他东西集成,这些主张会带来一些困扰。

Vue可能有些方面是不如React,不如Angular,但它是渐进的,没有强主张,你可以在原有大系统的上面,把一两个组件改用它实现,当jQuery用;也可以整个用它全家桶开发,当Angular用;还可以用它的视图,搭配你自己设计的整个下层用。也可以函数式,都可以,它只是个轻量视图而已,只做了自己该做的事,没有做不该做的事,仅此而已。

13.vue.js的两个核心是什么?

数据驱动和组件系统

数据驱动:Object.defineProperty和存储器属性: getter和setter(所以只兼容IE9及以上版本),可称为基于依赖收集的观测机制,核心是VM,即ViewModel,保证数据和视图的一致性。

组件系统:

1)能够把页面抽象成多个相对独立的模块

2)实现代码重用,提高开发效率和代码质量,使得代码易于维护

3) 组件可以扩展HTML元素,封装可重用代码

● 在较高层面上,组件是自定义元素,Vue.js的编译器为他添加特殊功能

有些情况下,组件也可以表现用js特性进行了扩展的原生的HTML元素

14.v-on可以监听多个方法吗?

可以,一个元素绑定多个事件的两种写法,一个事件绑定多个函数的两种写法,修饰符的使用。

<a style="cursor:default" v-on='{click:DoSomething,mouseleave:MouseLeave}'>doSomething</a>
<button @click="a(),b()">点我ab</button>

15.Vue 组件中 data 为什么必须是函数

vue组件中data值不能为对象,因为对象是引用类型,组件可能会被多个实例同时引用。
如果data值为对象,将导致多个实例共享一个对象,其中一个组件改变data属性值,其它实例也会受到影响

16.vue等单页面应用及其优缺点

缺点:

不支持低版本的浏览器,最低只支持到IE9;
不利于SEO的优化(如果要支持SEO,建议通过服务端来进行渲染组件);
第一次加载首页耗时相对长一些;
不可以使用浏览器的导航按钮需要自行实现前进、后退。

优点:

无刷新体验,提升了用户体验;
前端开发不再以页面为单位,更多地采用组件化的思想,代码结构和组织方式更加规范化,便于修改和调整;
API 共享,同一套后端程序代码不用修改就可以用于Web界面、手机、平板等多种客户端
用户体验好、快,内容的改变不需要重新加载整个页面。

17.vuex是什么?怎么使用?哪种功能场景使用它?

Vuex是Vue框架中状态管理,

有五种,分别是 State、 Getter、Mutation 、Action、 Module
使用场景:单页应用中,组件之间的状态。音乐播放、登录状态、加入购物车

vuex的State特性
A、Vuex就是一个仓库,仓库里面放了很多对象。其中state就是数据源存放地,对应于一般Vue对象里面的data
B、state里面存放的数据是响应式的,Vue组件从store中读取数据,若是store中的数据发生改变,依赖这个数据的组件也会发生更新
C、它通过mapState把全局的 state 和 getters 映射到当前组件的 computed 计算属性中

vuex的Getter特性
A、getters 可以对State进行计算操作,它就是Store的计算属性
B、 虽然在组件内也可以做计算属性,但是getters 可以在多组件之间复用
C、 如果一个状态只在一个组件内使用,是可以不用getters

vuex的Mutation特性
改变store中state状态的唯一方法就是提交mutation,就很类似事件。
每个mutation都有一个字符串类型的事件类型和一个回调函数,我们需要改变state的值就要在回调函数中改变。
我们要执行这个回调函数,那么我们需要执行一个相应的调用方法:store.commit。

Action 类似于 mutation,不同在于:Action 提交的是 mutation,而不是直接变更状态;
Action 可以包含任意异步操作,Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,
因此你可以调用 context.commit 提交一个 mutation,
或者通过 context.state 和 context.getters 来获取 state 和 getters。
Action 通过 store.dispatch 方法触发:eg。
store.dispatch('increment')

vuex的module特性
Module其实只是解决了当state中很复杂臃肿的时候,module可以将store分割成模块,
每个模块中拥有自己的state、mutation、action和getter

18.Vue深入组件传值

vue组件传值在日常开发中比较常见,
一般有三种传值方式:1.父传子、2.子传父、3.兄弟组件之间通信
父子组件其实就是组件包含关系
A组件中包含B组件,A是父组件,B是子组件
一般会在子组件里面定义props来做接收,这是比较常见的情况

1.父传子

这是父组件

<template>
  <div>
    <div>我是父组件</div>
    <div>我发送给第一个组件的信息是:{{msg}}</div>
    <div>
      <div id="child1">
        <ChildOne :msg="msg" />
      </div>
    </div>
  </div>
</template>

<script>
import ChildOne from "../components/children1";
import ChildTwo from "../components/children2";
export default {
  components: {
    ChildOne,
    ChildTwo
  },
  data() {
    return {
      msg: "我是父组件,我给你发消息",
    };
  }
};
</script>

可以看到父组件上面传入了一个msg,

那么在子组件上就需要定义一个props用来接收传进来的参数msg
子组件

<template>
  <div>
    <div id="title">我是第一个子组件</div>
    <div>我接受到的父组件的消息是:{{msg}}</div>
  </div>
</template>

<script>
export default {
  props: {
    msg: {
      type: String
    }
  }
可以简写为 props:['msg']
};
</script>

2.子传父

需要利用vue中的$emit将想要传递的值通过函数的形式传出,在父组件接收

this.$emit(arg1,arg2) 

arg1:方法名字,arg2:要传出的值

这是子组件

<template>
  <div>
    <div id="title">我是子组件</div>
    <div>我要发送给父组件的值:{{msg}}</div>
    <button @click="toParent">向父组件发送信息</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      msg: "我是第二组件,我要给父组件传值",
    };
  },
  methods: {
    toParent() {
      this.$emit("toParent", this.msg);
    }
  }
};
</script>

在button上绑定了一个点击事件,

函数里面传出了一个方法名为toParent的方法,

这时候我们就要去父组件接收这个函数,

它会带一个返回值,这个返回值就是我们需要从子组件传的值。
这是父组件

<template>
  <div>
    <div>我是父组件</div>

    <div>我即将接收第二组件传值是:{{child2Msg}}</div>
    <div>
      <div id="child2">
        <ChildTwo @toParent="getMag" />
      </div>
    </div>
  </div>
</template>

<script>
import ChildOne from "../components/children1";
import ChildTwo from "../components/children2";
export default {
  components: {
    ChildOne,
    ChildTwo
  },
  data() {
    return {
      child2Msg: ""
    };
  },
  methods: {
    getMag(msg) {
      this.child2Msg = msg;
    }
  }
};
</script>

在父组件里面定义了一个

@toParent方法这个名称要和子组件里面this.$emit(arg1)的命名一样,用来接收。

在getMag里面接收一个参数就是当前传回的值。

3.兄弟组件传值

组件互相不包含,其实这种兄弟传值完全可以使用vuex来做,下边会说到

在vue文件main.js中,我们利用 
`Vue.prototype.bus=new Vue()` 来定义,
此时我们就有了一个中间量。在组件中需要使用this.bus来调用
import Vue from 'vue'
export default new Vue

export default是不能省略的
定义第一个组件传递值

<template>
  <div>
    <div id="title">我是第一个子组件</div>
      我要给第二个兄弟发信息,内容是:
      <input type="text" v-model="to" />
    </div>
    <button @click="toBrother">点我给兄弟传值</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      to: "哈喽兄弟"
    };
  },
  methods: {
    toBrother() {
      this.bus.$emit("toBrother", this.to);
    }
  }
};
</script>

在button上绑定了一个方法,在方法内部使用中间变量bus中的$emit来传递值,参数同子传父的参数一致。

定义第二个组件用于接收值

<template>
  <div>
    <div id="title">我是第二个子组件</div> 
    <div>我得到的兄弟组件信息是:{{get}}</div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      get: ""
    };
  },
    使用钩子函数去接收 ,在创建vue之前就接收数据,后边必须使用箭头函数,普通函数是无效的
  beforeCreate() {
    this.bus.$on("toBrother", msg => {
      this.get = msg;
    });
  }
};
</script>

在第二个子组件里面通过beforeCreate生命周期来获得传过来的值,

这时候需要用this.bus.$on来接收,

第一个参数是this.bus.$emit定义的第一个方法名,

第二个参数是一个方法,此方法带一个返回参数。此时的方法需要使用箭头函数。

19. Vuex制作组件传值

首先引入vuex

  npm install vuex --save
  或者
  npm install --save vuex 
  或者
  npm i vuex -S

然后创建store/store.js用于存储配置参数
最后需要在main.js中导入store/store.js

import  store  from '@src/store/store'
或者
import  store  from '../store/store.js' //这个可根据自己路径修改
new Vue({
      el: '#app',
      store,//像router一样挂载进vue实例中
      template: '<App/>',
      components: { App }
    })

store/store.js配置内容

 import Vue from 'vue';
 import Vuex from 'vuex';
 Vue.use(Vuex);
 // 实际上,可以直接写入Store实例中,但是这种方式更加简洁易读
 const state = {
	// input框中的数据
	inputVal : '张三',
	// 数组数据
	list:['lucy','lily','polly'],
}
// 定义同步方法修改state状态
const mutations = {
	addTr(state,inputVal){
		// 数组的添加
		state.list.push(inputVal);
		state.inputVal = ''
	},
	delTr(state,index){
		// 数组的删除
		state.list.splice(index,1)
	}
}
//定义异步方法修改state状态
// 异步方法  参数一般都是 context 与 {commit}
const actions = {
	addTrAction({commit},inputVal){
		return commit('addTr',inputVal)
	},
	delTrAction({commit},index){
		return commit('delTr',index)
	},
}
// 定义Vuex的Store模式对象
export default new Vuex.Store({
	state,
	mutations,
	actions,
	// 除state,mutations和actions之外,vuex还有getterrs和modules对象属性,可以参见我另外一篇博客,路径不给你了,自己找吧(*^_^*)
})

写好vuex配置后,
看下组件使用state状态数据
组件一(可以是父子、兄弟的组件关系)

<template>
	<div id="list">
		<h1>这是list组件,数据展示如下:</h1>
		<!-- 注意。如果需要vuex中使用双向数据绑定,那么只能使用第一种方式 -->
		<input type="text" v-model="$store.state.inputVal">
		<!-- <button @click="addTr(inputVal)">点击添加列表项</button> -->
		<button @click="addTrAction(inputVal)">点击添加列表项</button>
		<!-- 直接获取store.js的list数据 -->
		<p>{{list}}</p>
		<br><br>
		<table border="1" align="center" width="500px">
			<tr>
				<th>序号</th>
				<th>内容</th>
				<th>操作</th>
			</tr>
			<tr v-for="(item,index) in list">
				<td v-text="index+1"></td>
				<td v-text="item"></td>
				<td v-text>
					<!-- <button @click="delTr(index)">删除</button> -->
					<button @click="delTrAction(index)">删除</button>
				</td>
			</tr>
		</table>
		
		<div style="height: 12.5rem;"></div>
		
	</div>
</template>

<script>
	import {mapState,mapMutations,mapActions} from 'vuex'
	export default{
		name:'list',
		computed:{
			...mapState(['inputVal','list'])
		},
		methods:{
			// ...mapMutations(['addTr','delTr']),
			...mapActions(['delTrAction','addTrAction'])
		}
		
		
	}
</script>

<style>
	/* odd 奇数  可以使用2n+1 */
	/* tr:nth-child(odd){
		background-color: #AAD5E4;
	}
	tr:nth-child(even){
		background-color: lightpink;
	} */
</style>

20.vue中router以及route,routes的使用

route,它是一条路由。

{ path: '/home', component: Home }

routes,是一组路由。

const routes = [
  { path: '/home', component: Home },
  { path: '/about', component: About }
]

router可以理解为一个容器,或者说一种机制,它管理了一组route。简单来说,route只是进行了URL和函数的映射,而在当接收到一个URL之后,去路由映射表中查找相应的函数,这个过程是由router来处理的。

  const router = new VueRouter({
          routes // routes: routes 的简写
    })

$route为当前router跳转对象里面可以获取name、path、query、params等。
r o u t e r 为 V u e R o u t e r 实 例 , 想 要 导 航 到 不 同 U R L , 则 使 用 router为VueRouter实例,想要导航到不同URL,则使用 routerVueRouterURL使router.push方法,返回上一个history使用 r o u t e r . g o 方 法 。 跟 上 面 说 的 一 样 , 这 里 的 router.go方法。跟上面说的一样,这里的 router.gorouter就管理路由的跳转,英文里er结尾的都表示一种人,这里你可以把这个想象中一个管理者,他来控制路由去哪里(push、go),这样就比较容易记。

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页