1. v-moudel实现
input本身有个事件叫input,用于监听value的值,在input中监听这个事件,并给它赋值给message
<input type="text" :value="message" @input="message = $event.target.value">
2. vue页面中子组件生命周期执行顺序
加载渲染过程
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
子组件更新过程
父beforeUpdate->子beforeUpdate->子updated->父updated
销毁过程
父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
3. vue从模板到dom经历了什么
创建组件实例 -> 初始化组件实例(调用setup函数并挂载数据,将模板编译成render函数)-> 调用render函数生成vnode -> 没有旧vnode时执行mount挂载dom -> 有旧vnode时 调用patch对新旧vnode进行diff算法然后打补丁
4. 虚拟dom原理流程
- 用javascript模拟dom树,并渲染这个dom树
- 比较新老dom树,得到比较的差异对象
- 把差异对象应用到渲染的dom树
5. 理解vue-loader
简单的说,他就是基于webpack的一个的loader,解析和转换 .vue 文件,提取出其中的逻辑代码 script、样式代码 style、以及 HTML 模版 template,再分别把它们交给对应的 Loader 去处理,核心的作用,就是提取。
至于什么是webpack的loader,其实就是用来打包、转译js或者css文件,简单的说就是把你写的代码转换成浏览器能识别的,还有一些打包、压缩的功能等。
6. vue路由的原理(Hash/History)
Hash路由的原理:
在Hash模式下,url中#后面的部分表示的是一个客户端状态,当这部分发生变化的时候,浏览器本身就不会刷新,在不刷新浏览器的情况下修改浏览器链接,同时通过监听hashChange事件来监听URL中hash值的变化,触发相关函数,改变相关组件。
History路由的原理:
History模式利用了HTML5中history的API,history.pushState和history.replaceState这两个方法可以在不刷新页面的情况下,操作浏览器的历史记录,通过监听popState事件来剪影URL的变化,从而触发相关函数,改变相关组件。
注意:
history模式下,如果你再跳转路由后再次刷新会得到404的错误,这个错误说白了就是浏览器会把整个地址当成一个可访问的静态资源路径进行访问,然后服务端并没有这个文件。
所以history模式下一般情况下,我们都需要配置下nginx,告诉服务器,当我们访问的路径资源不存在的时候,默认指向静态资源index.html
7. vue路由query和params方式的区别
- query在name和path两种传递方式下都是有效的。 params只有name传参是有效的
- params是路由的一部分,必须要在路由后面添加参数名。query是拼接在url后面的参数,没有也没关系。
- query相当于get请求,页面跳转的时候,可以在地址栏看到请求参数,而params相当于post请求,参数不会再地址栏中显示。
8. vue组件中的data为什么是一个函数
- vue中组件是用来复用的,为了防止data复用,将其定义为函数
- 当我们组件的date单纯的写成对象形式,这些实例用的是同一个构造函数,由于JavaScript的特性所导致,所有的组件实例共用了一个data,就会造成一个变了全都会变的结果
- 当我们将组件中的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data,拥有自己的作用域,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据
9. cookie属性
- name: cookie名称
- value: cookie值
- domain: 即可访问此cookie的域名(不同级有不同限制)
- path: 可访问此cookie的页面路径
- expires/Max-Age: cookie超时时间, 默认为Session
- Size: cookie大小
- http: 即httponly属性, true时只有http请求头会带有此信息, 而不能通过document.cookie来访问
- secure: 设置是否只可通过https来传递此条cookie
10. rem响应式计算设置
<style>
html{
// 设计稿宽为375px时,font-size为100px;
// 当改变屏幕宽时,布局会自适应,无论宽高都会等比例响应。
font-size:calc(100vw * 100 / 375);
}
</style>
11. 跳出forEach循环
对于 forEach() ,它是从头走到底的,不仅 return 都是无效的,而且 break 还是直接报错。
这里用抛出异常的方式直接让回调函数报错来实现,但是还要注意一点,最好还要传入一个异常错误的 message ,我这里定为 字符串信息break,因为在运行时还有可能报出别的错误,有了这个标识就能识别处理哪个是正常的跳出循环,哪个是真正的执行错误。
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]
try {
arr.forEach(item => {
if (item == 5) throw 'break'
console.log(`item:${item}`)
})
} catch (err) {
if (err.message === 'break') console.log('break success!')
else console.error(err)
}
12. Map跟Object到底选哪个
Object的key只能是数字、字符串、Symbol;Map的key可以是任意类型;
Map是迭代对象;Object不可以迭代;
Map会记录写入顺序;Object会对key进行序列化后按照字典排序;
Map有内置各种操作函数;Object没有;
性能的表现上,新增、删除、读取的速度,在数量非常少时,Object 的表现可能会稍微好那么一点点点,甚至不太明显能感知得出来。 而在数量非常大的时候,Map 的表现会比 Object 好。
13. http缓存类型
http缓存分为两大类型,强制缓存(强缓存)和协商缓存,存在缓存规则上的不同;
强缓存: 是指在指定时间内(缓存未失效的情况下),客户端将不再发送请求给服务端,而是通过缓存的方式从事先存储的内存或磁盘中获取信息。
协商缓存: 是指在使用本地缓存之前,需要向服务端发起一次GET请求,与之协商当前浏览器保存的数据信息是否过期,通常采用请求资源修改的最后一次时间戳来进行判断,如果未过期服务端返回304,客户端直接中缓存中读取数据,如果已过期,服务端返回最新的数据信息。
14. 获取近N天日期技巧
// 实例为获取今日后7天日期
let myDate = new Date() // 获取系统当前时间
let getDate = myDate.getDate()
let tiemArr = []
for (let i = 0; i < 7; i++) {
let today = new Date() // 每次循环将时间初始为当前时间
let str = getDate + i
today.setDate(str)
const getDay = today.getDay()
tiemArr.push(
`${today.getMonth() + 1}月${today.getDate()}日(${
getDay == 0
? '星期日'
: getDay == 1
? '星期一'
: getDay == 2
? '星期二'
: getDay == 3
? '星期三'
: getDay == 4
? '星期四'
: getDay == 5
? '星期五'
: getDay == 6
? '星期六'
: ''
})`
)
}
console.log(tiemArr)
主要是使用 new Date().setDate() 会比较传入参数是否大于当前月份日期上线,大于则月份加一,余数为下月的日期。
15. 在js里为什么0.1+0.2不等于0.3
计算机的信息全部转化为二进制进行存储的,那么0.1的二进制表示的是一个无限循环小数,该版本的 JS 采用的是浮点数标准需要对这种无限循环的二进制进行截取,从而导致了精度丢失,造成了0.1不再是0.1,截取之后0.1变成了 0.100…001,0.2变成了0.200…002。所以两者相加最后得到的值是0.30000000000000004。
既然0.1不等于0.1了,那为什么我在控制台上输出console.log(0.1)还等于0.1呢
因为在输入内容进行转换的时候,二进制转换成十进制,然后十进制转换成字符串,在这个转换的过程中发生了取近似值,所以打印出来的是一个近似值
16. vue3源码为什么Proxy要配合Reflect使用
Reflect就是对Proxy内部this的一个修正(保证正确的 this 上下文指向)
所以如果你正常老老实实的使用,别玩那么花。那么你的确可以忽略Reflet
针对于 get 陷阱(当然 set 其他之类涉及到 receiver 的陷阱同理)
Proxy 中接受的 Receiver 形参表示代理对象本身或者继承与代理对象的对象
Reflect 中传递的 Receiver 实参表示修改执行原始操作时的 this 指向
不使用Reflects:
const parent = {
name: '孤傲',
get value() {
return this.name;
},
};
const proxy = new Proxy(parent, {
// get陷阱中target表示原对象 key表示访问的属性名
get(target, key, receiver) {
return target[key];
},
});
const obj = {
name: 'Aos',
};
// 设置obj继承与parent的代理对象proxy
Object.setPrototypeOf(obj, proxy);
// log: 孤傲
console.log(obj.value);
使用Reflect:
const parent = {
name: '孤傲',
get value() {
return this.name;
},
};
const handler = {
get(target, key, receiver) {
return Reflect.get(target, key, receiver);
},
};
const proxy = new Proxy(parent, handler);
const obj = {
name: 'Aos',
};
// 设置obj继承与parent的代理对象proxy
Object.setPrototypeOf(obj, proxy);
// log: Aos
console.log(obj.value);
17. 如何解决跳同一路由组件时页面不变?
Vue Router 默认情况下,会复用相同组件的实例,而不是销毁和重新创建它们。
这种复用的机制可以提高性能,并且在大多数情况下是符合预期的。
即 /Details/1 => /Details/2 或者 /Details?id=1 => /Details?id=2 ,这类链接跳转时, 原来的组件实例会被复用。
方式一:
在路由入口上添加key,这样就不会复用组件实例
<RouterView :key="route.fullPath" />
方式二:
watch监听路由变化watch(route, (to) => { // 这里写要更新的东西 }, {immediate: true})