1.第一题:Vue监控属性警告问题
子组件为什么不可以修改父组件传递的Prop,如果修改了,Vue是如何监控到属性的修改并给出相应的警告呢?
解答:
因为 vue 是单向数据流。如果一开始没有 created 则可以修改,加上 created 里面的 proxy 就可以阻止子组件 proxy.vue去修改父组件的 info ,当然如果是通过 $emit 就可以。 Proxy.js 是对 Vue 底层处理方式的一个最简化情况。
<template> <div> info: {{ info }} <input :value=""info.name" Qinput="handleChange"/</div> </template> <script> import proxy from "./proxy"; export default { props:{ info: object), created({ this.temp = ( name:""; Object. keys(this.temp).forEach(key >{proxyfthis.info,this.temp,key);); ), methods: { handleChange(e) { //this.info.name = e.target.value; //this.SforceUpdateO); this.$emit("change", e.target.value);) }}}; </script>
proxy.js
const sharedPropertyDefinition = { enumerable: true, configurable: true }; export default function proxy(target,temp,key) { sharedPropertyDefinition.get = function proxyGetter() { return temp[key]; }; sharedPropertyDefinition.set = function proxySetter(val){ temp[key) = val; if (!window.isUpdatingChildComponent) { console.error('不可以直接更改:$ikey'} ; window.isUpdatingChildComponent= false;; Object.defineProperty(target, key,sharedPropertyDefinition);,
2.第二题:this.$emit问题
问题:this.$emit的返回值是什么? --this;--如果需要返回值可以使用回调参数。
解答:
handleChange(e){ const res = this.$emit("change",e.target.value,val →> {console.log(val); }); console.log(res,res =ss this); }, handleEventChange(val,callback){ this.name = val; callback("hello")Areturn "hello"; }
子组件返回了值和回调函数,我们这里就接受了值和回调函数即 callback 则不需要后面的 return 了。
3. 第三题:同名插槽问题
问题:
相同名称的插槽是否合并还是替换?
解答:
Vue2.5版本,普通插槽合并、替换;Vue2.6版本,都是替换;
methods: { validate(phone = "") { return phone 8& /^1[8-9]{10$/. test (phone); } }
4.第四题:为什么index不可用做key?
问题:
为什么不能用index作为key?
解答;
因为index设计到更新DOM性能问题以及会引起状态BUG问题,所以不可以用为key;
<template> <div class="border"> <Children v-for="(key, index) in list" :key=" index"> <button @click="() => handleDe Lete (key)">删除</button> </Children> <button @click="handleAdd">添加</button> </div> </template> <script> import Children from "./Children" ; let key = 1; export default { components:{ Children }, data() { return { list: [] }; }, methods: { handleAdd() { this. list. push(key++); }, handLeDe Lete(key) { const index = this. list. findIndex(k = k === key; this. list. splice(index, 1); } } }; </script>
<template> <div class=" border2"> <input v-model=" phone" type=" number" /> <slot></slot> </div> </template> <script> export default { data() { return { phone:"" }; } }; </script>
如图每次点击添加的时候就会往数组加 1,而删除的时候则是数组变成了长度为 2,index 也跟着变了,那么删除的就是最后一个了,不管点的是哪一个。
修改后:(这样就正常了!!!)
<template> <div class="border"> <Children v-for="key in List"( ey="key"> button @click="() => handleDe Lete( key )">删除</button> </Children> <button @click="handleAdd">添加</ button> </div> </ template> <script> import Children from "./Children" ; let key = 1; export default { components: { Children }, data() { return { list: [] }; }, methods: { handleAdd() { this.list. push(key++); }, }, handleDelete(key) { const index = this. list. findIndex(k = k === key); this.list. splice(index, 1); } }; </script>
5.第五题:底层原理问题
问题:
数组有哪些方法支持响应式更新,如不支持如何处理,底层原理如何实现的?
解答:
- 支持: push(、pop(、shift()、 unshift(、 splice(、 sort(、 reverse()
- 不支持: filter()、concat()、 slice()
- 原理同样是使用Object.defineProperty对数组方法进行改写
对不支持的方法也很简单,只需要更改整个数组,赋值成一个新的数组就行。这里的改写其实就是中间做了一个代理层。
6. 第六题:防抖改造问题
问题:
对Watch1 Demo进行防抖改造,即直到用户停止输入超过500毫秒后,才更新fullName ;
解答:
- setTimeout
- lodash debounce
- Demo 1.5/Wattch1 pro
第一种就是利用定时器做一个 500 毫秒的延迟就行(计算属性无法做到)。另一种就是利用第三方库什么的。
<template> <div> {{ fulUName }} <div>f irs tName: <input v-model="f irs tName" /></div> <div>lastName: <input v-mode L="las tName" /></div> </div> </template> <script> export default { data: function() { return { firstName: "Foo", lastName: "Bar" , fulIName: "Foo Bar" }; }, watch: { firstName: function(val) { clearTimeout(this. firstTimeout); this. firstTimeout = setTimeout() => { this. fullName = val +””+ this. las tName; }, 5000 }, lastName: function(val) { clearTimeout(this. lastTimeout); this. LastTimeout = setTimeout(() => { this. fulName = this. firstName +””+ val; },500); } } }; </script>
7.第七题:设计秒杀倒计时组件
问题:设计一个秒杀倒计时组件;
解答:
<template> <div> <Spike :start-t ime="startTime" :end-t ime="endTime" /> </div> </template> <script> import moment f rom "moment" ; import Spike from "./Spike" ; export default { components: { Spike }, data() { return { startTime: moment("2019-03-10 14:44:00"), endTime: moment("2019-03-08 14:46: 00") }; } }; </scripts>
难点在于如何对时间进行校验(因为时间是可以被修改的),一般是通过获取服务器的时间与本地时间计算一个时间差。
8.第八题:生命周期和指令钩子顺序
问题:
怎么查看组件生命周期和指令周期钩子的顺序?
解答:
新建是先组件再指令,更新是先指令再组件,销毁也是先组件再指令。
<temptate> <div class="border"> <h1>A结点</h1> <button @click="() => changeColor()">改变color</button> <ChildrenB /> <ChildrenC /> <ChildrenD /> </div> </template> <script> import Vue from "vue" ; import ChildrenB from "./ChildrenB"; import ChildrenC from "./ChildrenC"; import ChildrenD from "./ChildrenD"; export default { components: { ChildrenB, ChildrenC, ChildrenD }, provide() { this. theme = Vge. observable({ color: "blue" }); return { theme: this . theme }; }, methods: { changeColor(color) { if (color) { this. theme.color = color; } else { this. theme.color = this. theme.color === "blue" ? "red" : "blue"; } } };
通过 observable 来实现响应式数据。
9.第九题:v-ant-ref指令回调问题
问题:
v-ant-ref指令回调中能不能对更改响应式数据?为什么?
解答:
不能,会死循环!!!
组件更新就会触发回调,如果回调中更改数据又会触发组件更新又会触发回调,一直下去。