高级前端软件工程师知识整理之Vue技术栈篇

1. 什么是MVVM?

MVVM是Model-View-ViewModel的简写,它本质上就是MVC的改进版。MVVM就是将View的状态和行为抽象化,将视图UI和业务逻辑分开,View和Model之间并没有直接的联系,而是通过ViewModel进行交互,它们之间的交互是双向的。

  • Model - 代表数据模型,定义了视图的状态或行为。
  • View - 代表视图,负责将数据模型转化成可视化界面。
  • ViewModel - 负责监听模型数据和视图状态或行为的变化,同步了View和Model的对象,即实现了双向绑定。

以下是Vue技术栈中一个双向绑定的典型例子:

<div id="app6">
    <p>{
   
   {message}}</p>
    <input type="text" v-model="message" />
</div>
<script>
    var app6 = new Vue({
        el: "#app",
        data: {
            message: "HelloWorld"
        }
    });
</script>

示例中当修改input标签中的内容时,p标签的内容也会同步修改。

2. Vue的生命周期函数有哪些?

Vue生命周期:

名称 描述
beforeCreate 实例刚被创建,vue所有属性都还不存在
created 实例创建完成,但$el还不存在
beforeMount 挂载之前
mounted 挂载之后,即data中的数值已经被渲染到元素中
beforeUpdate 更新之前
updated 更新之后
activated <keep-alive>组件被激活时
deactivated <keep-alive>组件移除时
beforeDestroy 实例被销毁前
destroyed 实例被销毁后

示例:https://blog.csdn.net/zeping891103/article/details/78135698

3. Vue实现数据双向绑定的原理是什么?

双向绑定的原理是利用Object.defineProperty()进行数据劫持,然后采用结合发布者-订阅者模式监听数据的变化。当把一个 Javascript 对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty 将它们转为 getter/setter。如第一题中的双向绑定的示例代码,它的数据劫持方式为:

var data = { message: 'HelloWorld' }
Object.defineProperty(data, 'message', {
    get: function () {
        return data.message;
    },
    set: function (newValue) {
    	data.message = 'newValue';
        // data-v-xxxxx为Vue实例在初始化时给dom元素添加的唯一属性值
        // 当message数据发生变化时,通知相关v-model绑定的元素也发生变化            
        document.getElementByAttr('input','data-v-xxxxx','').value = newValue; 
    }
})

另外,当input元素被v-modal绑定时,Vue实例为该元素添加了一个input事件,当内容发生变化时,触发this.$emit('input',' ')函数发出事件告诉Vue实例 data.message发生变化了,实现数据同步。更多有关Object.defineProperty的用法可以参考本系列的基础篇(四)中有介绍。

发布者-订阅者模式的设计思想是发布者管理所有相依于它的订阅者,并且在发布者本身的状态改变时主动发出通知,订阅者接到通知后开始响应变化并刷新。

4.Vue组件间的参数通过什么方法传递?

1.父组件与子组件传参
父组件传给子组件:子组件通过props方法接受参数
子组件传给父组件:$emit方法传递参数

示例:父组件向子组件mycomp传递参数message,并添加对子组件的cbmsg事件监听

<template>
	<div>
		<p>{
   
   {callback_msg}}</p>
		<mycomp :message="message" @cbmsg="cbmsgHandle"  />
	</div>
</template>

<script>
	import mycomp from './vmcomp.vue';

	export default {
		name: '我是父组件',
		data() {
			return {
				message:'父组件向子组件传参',
				callback_msg:''
			}
		},
		methods: {
			cbmsgHandle(response){
				this.callback_msg = response;
			}
		},
		components: {
			mycomp
		}
	}
</script>

子组件通过props属性接收父组件传入的参数,并通过触发cbmsg事件向父组件传递参数

<template>
    <div>
        <p>{
   
   {message}}</p>
        <button @click="clickHandle">click</button>
    </div>
</template>

<script>
    export default {
        props: {
            message: {
                type: String,
                default: ''
            }
        },
        methods: {
            clickHandle() {
                this.$emit('cbmsg', '子组件向父组件传参');
            }
        }
    }
</script>

2.非父子组件间的数据传递,兄弟组件传值

使用事件总线EventBus,创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件。

示例:创建Bus

// vue-bus.js
const install = function(Vue) {
	const Bus = new Vue({
		methods: {
			emit(event, ...args) {
				this.$emit(event, ...args);
			},
			on(event, callback) {
				this.$on(event, callback);
			},
			off(event, callback) {
				this.$off(event, callback);
			}
		}
	});
	Vue.prototype.$bus = Bus;
}
export default install;

// Vue首次创建实例时一次性引入
import VueBus from '@/assets/js/vue-bus';
Vue.use(VueBus);

new Vue({
	el: '#app',
	...
})

// 组件间使用
this.$bus.on('eventName',function(value){})
this.$bus.emit('eventName', value)

使用Vuex,父组件与子组件共享相同的状态值,配合...mapGetters实现数据同步更新,这时会触发变化组件的updated钩子函数,但并不会重新挂载。这里要加个题外话,在Vuex中状态是存储在一个共享对象里的,所以当有相同getters的时候将会报错,针对这种情况,可以使用命名空间namespaced: true,添加这个属性后,无论是存值、取值还是执行函数都需要加上前缀命名空间,详细可参考:https://blog.csdn.net/weixin_39015132/article/details/84143962

5. Vue的路由实现:hash模式 和 history模式

hash模式:在浏览器显示的URL中带有符号“#”,#以及#后面的字符称之为hash,通过hashChange事件来监听URL的改变,用window.location.hash读取。

特点:hash虽然在URL中,但不被包括在HTTP请求中,因此hash不会重加载页面。hash内容是用来指导浏览器动作,对服务端安全无用。

history模式:在浏览器显示的URL中以“ / ”分割,没有#。这种模式采用HTML5的新特性且提供了两个新方法:pushState(),replaceState()可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更。

特点:前端的 URL 必须和实际向后端发起请求的 URL 一致,如http://www.xxx.com/items/id,后端如果缺少对 /items/id 的路由处理,将返回 404 错误。解决办法:当访问不到页面时,重定向到index.html页面,即app依赖的页面。

6. Vue路由的钩子函数有哪些?

主要有两个:beforeEach,afterEach。用于对路由导航跳转前、后的监听,如跳转前检查是否包括有效Token,没有则返回登录页面。

beforeEach有3个参数to,from,next:

  • to:route即将进入的目标路由对象。
  • from:route当前正要离开的路由对象。
  • next :一定要调用该方法完成路由跳转,默认情况不设参数,跳转至to指定的路由对象;也可以设置把路由对象作为入参传入,跳转到指定页面。

示例:

// Router跳转页面时,验证token
export const SetRouterTransition = function(router, store) {
	/* router before */
	router.beforeEach((to, from, next) => {
		// check this router need auth
		if(to.meta.requireAuth) {
			if(store.state.app.token || getLocalStorage('api_token')) {
				next();
			} else {
				alert('没有找到模拟TOKEN值')
				next({
					path: '/',
					query: {
						redirect: to.fullPath
					}
				})
			}
		} else {
			next();
		}
	});

	/* router after */
	router.afterEach((transition) => {
		let title = transition.name;
		document.title = title;
	});
}

// 在入口文件添加参数router和store
SetRouterTransition(router, store);

7. Vuex是什么?

Vuex是一种用来实现状态管理的机制,它的应用核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。Vuex主要有四个模块组成:

  • state:用来存储组件状态。Vuex使用单一状态树,即每个应用将仅仅包含一个store 实例,但单一状态树和模块化并不冲突。存放的数据状态,不可以直接修改里面的数据。
  • mutations:用于同步修改store中的状态。使用this.$store.commit(mutationsType, ...param);触发。
  • getters:类似Vue的计算属性,主要用来过滤一些数据或者直接返回某个状态值。使用this.$store.getters.xxx获取。
  • action:用于同步修改store中的状态。使用this.$store.dispatch(actionType, ...param) 触发。

8. vue-cli如何新增自定义指令?

自定义指令使用Vue.directive来定义,简单而言,就是从指令赋值中获取对添加该指令元素的操作说明,通过对操作的解析后按要求初始化该元素。

定义指令有5个钩子函数:

  • bind:只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行的初始化动作。
  • inserted:被绑定元素插入父节点时调用。
  • update:所在组件的 VNode 更新时调用,指令的值可能发生了改变也可能没有。
  • componentUpdated:所在组件的 VNode 及其孩子的 VNode 全部更新时调用。
  • unbind:只调用一次,指令与元素解绑时调用。

这些钩子函数具有相同的回调参数:

  • el:指令所绑定的元素,可以用来直接操作 DOM 。
  • binding: 获取外界数值的对象
  • vnode:vue 编译生成的虚拟节点
  • oldVnode:上一个虚拟节点

全局指令:

Vue.directive('mydir', {
    inserted(el) {
        console.log(el);
    }
})

局部指令:

var app = new Vue({
    el: '#app',
    // 创建指令(可以多个)
    directives: {
        // 指令名称
        mydir: {
            inserted(el) {
                console.log(el);
            }
        }
    }
})

示例:

<!DOCTYPE html>
<html>
 
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script src="../js/libs/vue/2.4.2/vue.js"></script>
	</head>
 
	<body>
		<div id="app">
			<!-- v-myorder:arg.a=value -->
			<!-- arg用于对该指令区别类别 .a表示对该指令类别的修饰符,value类似于值对入参value -->
			<!--如果你不需要arg.a,也可以直接写成 v-myorder=value -->
			<p v-didemo:foo.a="msg">{
   
   {msg}}</p>
			<button @click="change">改变msg</button>
		</div>
	</body>
 
	<script>
		Vue.directive("didemo", {
			bind: function(el, binding, vnode) {
				console.log(1, el, binding);
				el.style.color = "red"; //设置文本字体颜色为红色
			},
			inserted: function(el, binding, vnode) {
				console.log(2, el, binding);
			},
			update: function(el, binding, vnode) {
				console.log(3, el, binding);
			},
			componentUpdated: function(el, binding, vnode) {
				console.log(4, el, binding);
			},
			unbind: function(el, binding, vnode) {
				console.log(5, el, binding);
			}
		});
 
		var app = new Vue({
			el: "#app",
			data: {
				msg: "hello world"
			},
			methods: {
				change: function() {
					this.msg = "i am change";
				}
			}
		});
	</script>
 
</html>

指令内容更新前:

指令内容更新后:

9. vue如何自定义一个过滤器?

通过vue实例的 filters 属性或 Vue.filter() 函数创建过滤器,在值运算中用竖杠 | 表示过滤:

<div id="app">
     <input type="text" v-model="msg" />
     {
   
   { msg | capitalize }}
</div>

局部过滤器:

var vm=new Vue({
    el:"#app",
    data:{
        msg:''
    },
    filters: {
      capitalize: function (value) {
        if (!value) return ''
        value = value.toString()
        return value.charAt(0).toUpperCase() + value.slice(1)
      }
    }
})

全局过滤器:

Vue.filter('capitalize', function (value) {
  if (!value) return ''
  value = value.toString()
  return value.charAt(0).toUpperCase() + value.slice(1)
})

10. 对keep-alive 的了解?

keep-alive是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。在vue 2.1.0 版本之后,keep-alive新加入了两个属性: include(包含的组件缓存) 与 exclude(排除的组件不缓存,优先级大于include) 。

<!-- 逗号分隔字符串,只有组件a与b被缓存。 -->
<keep-alive include="a,b">
  <component></component>
</keep-alive>

该组件也常用于路由导航是否缓存页面内容:

<keep-alive>
  <router-view/>
</keep-alive>

这时,在进入导航页面时将不会重新渲染页面,如果需要更新页面数据可以在生命周期钩子函数 activated 里操作。

11. 什么是事件修饰符?

事件修饰符是指与事件触发相关的修饰符。如要阻止冒泡事件需要用到event.stopPropagation(),然而使用事件修饰符,仅需@click.stop即可。

事件修饰符有以下几种,以click事件为例:

  • @click.stop 阻止继续冒泡
  • @click.capture 由默认冒泡模式转为捕获模式
  • @click.prevent 提交事件不再重载页面
  • @click.self 只当事件在该元素本身触发时触发回调
  • @click.once 仅执行一次

修饰符间可以串联使用,如用 @click.stop.once,表示阻止冒泡并仅执行一次。

12. 什么是按键修饰符?

按键修饰符是指与键盘事件相关的修饰符。如对Enter键的监听@keyup.enter,快捷组合件的监听等。按键修饰符一般与input标签配合使用,有以下几种:

  • .enter
  • .tab
  • .delete (捕获 “删除” 和 “退格” 键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

vue2.x版本后新增了下面几种修饰符:

  • .ctrl
  • .alt
  • .shift
  • .meta

13. Vue中Methods与计算属性computed的区别?

Methods里的函数每次调用都会从头开始执行一遍;computed里的函数只要入参相同,只在首次执行计算过程,其它的会从缓存中直接返回已经计算过的值,不会重新计算。

猜你喜欢

转载自blog.csdn.net/zeping891103/article/details/89377511