vue试题分析

238 阅读7分钟

二、Vue试题分析

  1. v-for可以实现数据遍历显示,不仅可以遍历数组,也可以遍历对象,还可以从数值中取值:
    • v-for='n in 10'
    • n会打印1-10
  2. vue的生命周期钩子:
    • 通用:
      • beforeCreate
      • created
      • beforeMount
      • mounted
      • beforeUpdate
      • updated
      • beforeDestroy
      • destroyed
    • 路由守卫:
      • beforeRouteEnter
      • beforeRouteUpdate (2.2 新增)
      • beforeRouteLeave
    • keep-alive:
      • activated
      • deactivated
  3. v-if v-show
    • v-if是真正的条件渲染,会确保在切换中条件块内的事件监听、子组件都会适当的被销毁和重建
    • v-show总是将节点渲染在dom中,只是基于css:display来控制节点的显示和隐藏
    • v-if有更高的切换开始,v-show有更高的初始渲染开销
    • v-if是惰性的,初始条件为假,就不会渲染
  4. axios相关
    • axios请求的时候不会带上cookie,不会影响带宽,可以通过withCredentials:true来设置
    • 对axios 的请求头进行设置:
    • axios.defaults.headers = {'Content-Type':'...'}
    • vue2.0不在更新维护vue-resource,官方推荐使用axios
    • axios拦截器可以拦截请求和响应,在then、catch之前拦截
  5. 组件实例的作用域是孤立的,意味着不能(不应该)在子组件模板里直接引用父组件的数据,要让子组件使用父组件数据的话,需要通过props来将父组件的数据传递给子组件,子组件不能也不应该修改父组件传入的数据,但是可以通过传入引用类型的数据来实现数据共享
  6. 为了让组件可以组合,我们需要一种方式来混合父组件的内容与子组件自己的模板。这个过程被称为内容分发 (即 Angular 用户熟知的“transclusion”)。Vue.js 实现了一个内容分发 API,参照了当前 Web Components 规范草案,使用特殊的 <slot> 元素作为原始内容的插槽。
  • a-template:
    <p>hello world</p>
    <b>
    	<h1>hello world</h1>
    </b>
    
  • b-template:
    <slot></slot>
    

.... 8. 如果把切换出去的组件保存在内存中,保留状态避免重新渲染,可以使用keep-alive - include exclude 9. 注册方式: - 全局:Vue.component(name,Vue.extend({})) - 局部:{ components:{name:Vue.extend({})} } 10. 事件总线实现非父子组件通信

//创建bus
let bus = new Vue()
//a
new Vue({
	template:'...',
	mounted(){
		bus.$on('emit-a',function(){
			alert(1)
		})
	}
})
//b
new Vue({
	template:'...',
	methods:{
		emitA(){
			bus.$emit('emit-a')
		}
	}
})
//当b组件的emitA方法被调用的时候,A组件就会执行alert(1)
  1. methods和计算属性的区别
    • 假设我们有一个数据为num,还希望拥有一个数据为doublenum,而且希望doublenum的值永远都是num的二倍
  • 方法:
    • 因为是直接显示在模板中,也就是说,我们可以来一个doublenum的方法,这个方法返回num的二倍,将这个方法放到模板中的某个地方执行 {{doublenum()}} 但是,当无关的例如一个str的数据更改的时候,组件会重新创建虚拟dom树,与上一次的虚拟dom树对比之后重新渲染,这个时候在重新渲染模板的时候doublenum函数会被再次的调用,造成不必要的性能浪费
    • 创建一个doublenum数据,使其初始值为num的二倍,然后利用watch来监听这两个数据,在改变的时候更改对应的数据,但是需要初始的为doublenum赋值为num的二倍,如果num是动态获取到的,doublenun赋值会更繁琐
    • computed计算数据,我们可以利用computed来创建一条新的doublenum数据。并且设置它的getter和setter,并与num建立关系,且computed会缓存,在重新渲染的时候,不会重新执行getter和setter
    computed:{
    	doublenum:{
    		get(){
    			return this.num*2
    		},
    		set(val){
    			this.num = val/2
    		}
    	}
    }
    
  1. 绑定class的对象语法和数组语法
<a :class="{a:true,b:false,c:1}"> => </a> => <a class='a c'></a>
data(){
	return {
		c:'c'
	}
}
<a :class = '["a","b",c]'></a> => </a> => <a class='a b c'></a>
	new Vue({
		el:"#example-3",
		methods:{
			say(str){
				alert(str)
			}
		}
	})
  1. 单向数据流
  • prop是单向绑定的,父组件属性变化,传递给子组件,但是,子组件数据变化,不能直接传递给父组件,也就是数据的流行是从父组件流向子组件的,为了防止子组件修改父组件的数据(会让应用的数据流变的更难开发、更新、维护)
  • 使用了vuex工具的时候,store中数据在组件中使用的过程也是单向数据流,state->vue component->actions->mutations->state->vue component
this.$router.push/replace({name:'user',params:{userId:1})
this.$router.push/replace({path:'/register',query:{plan:private})

key相关

  • 当数据改变之后,vue会创建新的虚拟dom来和原来的虚拟dom做对比,在创建新的虚拟的dom的时候,会根据key来查找在原来的虚拟dom中有没有某个部分,如果原来的有,这次的也需要,就会实现复用,而且在做diff对比的时候,如果有key会加快对比的查找速度,提高性能
  • 尽量循环的时候不要将key设置为数组的索引,因为当删除某一个元素的时候,就会导致删除位置下面的所有元素的key值都与上一次虚拟dom的key值不同,导致复用失败,这个时候我们最好使用关键的唯一的,例如id这样的数据作为key
  • 如果数据变化只是值的变化而不是条数和位置的变化,可以使用索引作为key

Vue.use()

  • Vue.use会查找插件对象里的install方法去执行,并且给install方法里传入Vue对象
var a = {
    install(Vue){
        Vue.component("my-a",{...})
    }
}
Vue.use(a)

进入域后根据不同的情况显示不同的页面(PC/MOBILE)

  • 很多情况下,一个应用会有PC和移动端两个版本,而这两个版本因为差别大,内容多,所以不能用响应式开发但是单独开发,而域名只有一个,用户进入域后直接返回对应设备的应用,做法主要有两种:
    1. 前端判断并跳转 进入一个应用或者一个空白页面后,通过navigator.userAgent来判断用户访问的设备类型,进行跳转
    2. 后端判断并响应对应的应用 用户地址栏进入域的时候,服务器能接收到请求头上包含的userAgent信息,判断之后返回对应应用

function foo(){// 第16行
    getName = function(){console.log(1)}
    return this
}
foo.getName = function(){console.log(2)}
foo.prototype.getName = function(){console.log(3)}
var getName = function(){console.log(4)}
function getName(){console.log(5)}


foo.getName()//2
//foo是一个函数,也可以说是一个对象,所以它也可以挂载一些属性和方法,18行在其上挂载了一个getName方法
//执行的结果是

getName()//4
//21行有一个全局函数,全局函数声明提前后被20行的getName覆盖,所以输出4

foo().getName()//1
//foo()执行完成后,将全局的getName也就是window.getName给更改后返回this,而在这里this执行的就是window,所以最后执行的就是window.getName,所以输出1

getName()//1
//在上面已经更改全局的getName,所以依然是1

new foo.getName()//2
//new 操作符在实例化构造器的时候,会执行构造器函数,也就是说,foo.getName会执行,输出2

new foo().getName()//3
//new操作符的优先级较高,所以会先new foo()得到一个实例,然后再执行实例的getName方法,这个时候,实例的构造器里没有getName方法,就会执行构造器原型上的getName方法

new new foo().getName()//3
//先执行new foo()得到一个实例,然后在new 这个实例的getName方法,这个时候会执行这个方法,所以输出3

//除了本地对象的方法,其他的函数都能new