一、vue的双向绑定原理是什么?里面的关键点在哪里
答:采用”数据劫持“结合“发布者-订阅者”模式的方式,通过 ”Object.defineProperty()“方式来劫持各个属性的setter, getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
二、实现水平居中的方式
答: 1、absolute + 负margin
2、absolute + margin auto
position: absolute;; top: 0; left: 0; right: 0; bottom: 0; margin: auto;
3、absolute + calc
position: absolute;; top: calc(50% - 50px); left: calc(50% - 50px);
4、absolute + transform
position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
5、flex
display: flex; justify-content: center; align-items: center;
6、lineheight
display: inline-block; vertical-align: middle; line-height: initial; text-align: left; /* 修正文字 */
三、常用的伪元素有哪一些?
-
伪元素主要是用来创建一些不存在原有dom结构树种的元素
-
伪类表示已存在的某个元素处于某种状态,但是通过dom树又无法表示这种状态,就可以通过伪类来为其添加样式
-
伪元素的操作对象是新生成的dom元素,而不是原来dom结构里就存在的;而伪类恰好相反,伪类的操作对象是原来的dom结构里就存在的元素。
伪元素与伪类的根本区别在于:操作的对象元素是否存在于原来的dom结构里 -
常见的伪类:
:link 应用于未被访问过的链接
:visited 应用于被访问过的链接
:hover 应用于鼠标悬停到的元素
:first-child 选择某元素第一个子元素
:last-child 选择最后一个。。。。。
:disabled 表单元素禁用
:enabled 匹配没有被禁用的元素 -
常见的伪元素:
::first-letter 选择元素文本的第一个字
::first-line 选择元素文本的第一行
::before 在元素内容的最前面添加新内容。
::after 在元素内容的最后面添加新内容。
四、移动端如何适配不同屏幕尺寸
1、利用媒体查询
2、利用js 控制rem
3、利用vw
五、本地存储有哪一些?他们三者有什么区别
答:本地存储一般有三种:cookie、 sessionStorage、localStorage
1、cookie 可以设置过期时间,cookie 在浏览器和服务器间来回传递。而sessionStorage 和localStorage 不会自动把数据发给服务器,仅在本地保存
2、储存大小限制也不同
cookie 数据不能超过4k,同时因为每次http请求都会携带cookie,所以cookie只适合保存很下的数据。如会话标识。而sessionStorage 和 localStorage 虽然也有储存大小的限制,但比cookie大得多,可以达到5M 或者更大
3、数据有效期不同,sessionStorage: 仅在当前浏览器窗口关闭前有效,自然也就不可能持久保存;
localStorage: 始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie在设置的cookie过期时间之前一直有效,即使窗口或者浏览器关闭。
六:cookie有哪些属性?
1、Name/Value
2、Expires属性
3、Path属性
4、Domain属性
5、Secure属性:指定是否使用[HTTPS]安全协议发送Cookie。
6、HTTPOnly 属性
七、js数据类型有哪些?,如何判断js数据类型?
js数据类型:
- Number
- String
- Boolean
- Null
- Undefined
- Object
- Symbol 判断js 数据类型:
1、typeof typeof 100
2、instanceof instanceof运算符需要指定一个构造函数,或者说指定一个特定的类型,它用来判断这个构造函数的原型是否在给定对象的原型链上。 false instanceof Boolean, //false
3、constructor constructor是prototype对象上的属性,指向构造函数。根据实例对象寻找属性的顺序,若实例对象上没有实例属性或方法时,就去原型链上寻找,因此,实例对象也是能使用constructor属性的。
var num = 123; num.constructor==Number, true
4、Object.prototype.toString.call()
可以通过toString() 来获取每个对象的类型。为了每个对象都能通过 Object.prototype.toString() 来检测,需要以 Function.prototype.call() 或者 Function.prototype.apply() 的形式来调用,传递要检查的对象作为第一个参数,称为thisArg。
var toString = Object.prototype.toString;
toString.call(123); //"[object Number]"
八、说一下ES6的新特性有哪些?
1、es6新增了promise(标题) 需要说什么是promise
2、es6新增了模块化 需要说什么是模块化
3、新增了class关键字 需要解释
4、新增了箭头函数 再说箭头函数与普通函数的区别
5、新增了解构赋值 需要解释什么是解构赋值
6、新增了let const关键字 需要说let const var的区别
7、新增了简单数据类型symbol
九、let const var 三者有什么区别?
-
let 是代码块有效 var是全局有效
-
let 是不能重复声明的 var是可以多次声明
-
let不存在变量的提升 var存在变量的提升
-
const存储简单数据类型存储的是常量
十、数据去重有哪些办法?
1、利用Set结构不能接收重复数据的特点
var newArr = [...new Set(arr)]; //利用了Set结构不能接收重复数据的特点
2、利用 filter() + indexOf 去重
filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。item是当前元素的值,index是当前元素的索引值。indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。利用indexOf() 查询到数组的下标,看是否等于当前的下标,相等的话就返回,否则不返回值。
var newArr = arr.filter(function(item,index){
return arr.indexOf(item) === index; // 因为indexOf 只能查找到第一个
});
3、利用for 循环 搭配 indexOf 去重 原理: 定义新数据,判断新数组中有没有字符串值,如果没有则返回 -1
function noRepeat(arr) {
//定义一个新的临时数组
var newArr=[];
//遍历当前数组
for(var i=0;i<arr.length;i++) {
//如果当前数组的第i已经保存进了临时数组,那么跳过,
//否则把当前项push到临时数组里面
if(newArr.indexOf(arr[i]) === -1) { //indexOf() 判断数组中有没有字符串值,如果没有则返回 -1
newArr.push(arr[i]);
}
}
return newArr
}
4、借助新数组 通过 indexOf 方法判断当前元素在数组中的索引,如果与循环的下标相等则添加到新数组中,其原理是判断这个元素是数组中第一个元素,添加进去,后续相等的元素九不添加
function noRepeat(arr) {
var newArr = [];
for (var i = 0; i < arr.length; i++) {
if (arr.indexOf(arr[i]) == i) {
newArr.push(arr[i]);
}
}
return newArr;
}
5、利用includes实现数组去重
function noRepeat(arr) {
let newArr = [];
for(i=0; i<arr.length; i++){
if(!newArr.includes(arr[i])){
newArr.push(arr[i])
}
}
return newArr
}
6、数组对象去重法:
let map = new Map();
for (let item of this.arr) {
map.set(item.id, item);
}
this.arr = [...map.values()];
console.log(this.arr)
十一、说一下深拷贝和浅拷贝的区别,如何实现一个深拷贝?
1、浅拷贝:一个对象里面的所有的属性值和方法都复制给另一个对象
2、把一个对象的属性和方法一个个找出来,在另一个对象中开辟对应的空间,一个个存储到另一个对象中
区别:浅拷贝只是简单的复制,对对象里面的对象属性和数组属性只是复制了地址,并没有创建新的相同对象或者数组。而深拷贝是完完全全的复制一份,空间大小占用一样但是位置不同!!
十二、vue的生命周期有哪一些?说一下他们每个阶段做了什么操作?
1、创建前(beforeCreate)
在这个阶段:vue实例初始化之后,数据观察和事件机制未形成,无法获取到dom节点
2、创建后(create)
在这个阶段,vue 实例创建后,仍然无法获取到dom节点
3、载入前(beforeMount)
在这个阶段,vue挂载的跟节点已经创建,dom 操作将围绕根元素继续进行。
4、载入后(mounted)
在该节点数据和dom 都已经被渲染,常用于异步请求。
5、更新前(beforeUpdate)
该阶段中,vue遵循数据驱动dom的原则,beforeUpdate 函数在数据更新后,其dom中的数据也回改变
6、更新后(updated)
该阶段中,dom会与更新的内容进行同步
7、销毁前(beforeDestory)
在该阶段,是指清除vue实例与dom的关联,在销毁前,会触发beforeDestory钩子函数
8、销毁后(destory)
在销毁vue实例与dom的关联后,会触发destory
拓展:更新前(beforeUpdate)
当修改Vue实例的data时,Vue就会自动帮我们更新渲染视图,在这个过程中,Vue提供了beforeUpdate的钩子给我们,在检测到我们要修改数据的时候,更新渲染视图之前就会触发钩子beforeUpdate。html片段代码我们加上ref属性,用于获取DOM元素。Dom元素上的数据还没改变。
十三、vue 通讯方式有哪些?
1、父组件向子组件传值 prop
2、子组件向父组件传递emit
3、this.$parent 和 this.children
4、provide 和 inject 依赖注入
5、ref / refs 通过获取组件实例获取子组件数据
6、eventBus 事件总线 vue-bus 原理:new vue 把这个对象挂在在项目中vue的对象上,防止全局变量污染。
7、vuex
8、root property 进行访问
十四、vuex 有几个属性及作用
state, getters, mutations, actions, modules
1、state vuex的基本数据,用来储存变量
2、getter 从基本数据state 派生的数据,相当于store的计算属性,getter的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了变化才会被重新计算。
3、mutation:
用于提交更新数据的方法,必须是同步的,如果是异步的需要使用action
4、action:
(1)、这个用于提交的是action 而不是直接变更状态,
(2)、action 可以包含任意异步操作
5、modules:
模块化vuex,可以让每一个模块拥有自己的state,mutation,actio, getters,使得结构非常清晰,管理更为方便。
十五、vue的监听属性和计算属性有什么区别?
总结:
1、计算属性computed在使用时,函数里面的变量都会被监听,只要里面的某一个值变动,便会将整个函数执行一遍,而watch 只是监听某一个值,如果监听的值里面也有很多变量,也会全部监听。
2、计算后的属性可不在data中定义,如果定义会报错,因为对应的computed作为计算属性定义并返回对应的结果给这个变量,变量不可被重新定义和赋值。而watch 监听data中定义的变量变化
各子特点:
conputed特性:
1、是计算值,可用于处理props 或 emit传值
2、具有缓存性,页面重新渲染值不变化,计算属性会立即返回之前的计算结果,而不必再执行函数
watch 特性
1、是观察的动作
2、应用:监听 props , $emit 或本组件的值执行异步操作
3、无缓存性,页面重新渲染时值不变化也会执行
十六、说一下防抖和节流,怎么实现?
二者的本质:为了控制函数在高频事件下的触发次数,降低函数执行频率,节省计算资源,提高性能。
防抖:高频事件下,控制执行最后一次(简单来说,就是设置一个毫秒,频繁触发,重置这个毫秒,到了一定时间在执行函数)
实现:利用闭包,在返回的函数体里,通过不断开启和清除定时器,在限定时间内不断点击,仍然只执行最后一次
// 通过闭包实现防抖
function debounce(fn, delay) {
let timer = null;
return function () {
if (timer !== null) {
clearTimeout(timer);
}
timer = setTimeout(() => {
// 箭头函数没有自己的this,改变指向,使其指向input。同时执行fn函数
fn.call(this);
}, delay);
};
}
节流:高频事件下,控制(函数)执行的次数,也就是一个单位时间内,只允许执行1次。
实现方式:通过控制锁的状态,实现节流
// 通过定时器实现节流
function throttle(fn, wait) {
let lock = true;
return function () {
if (lock) {
// 关锁
lock = false;
// 通过定时器开锁
setTimeout(() => {
lock = true;;
fn();
}, wait);
}
};
十七、vue-router的导航守卫有哪些?
1、全局守卫:router.beforeEach 2、全局解析守卫:router.beforeResolve 3、全局后置钩子:router.afterEach 不会接受 next 函数也不会改变导航本身 4、路由独享守卫:beforeEnter 5、组件内的守卫:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
注意:参数的改变并不会触发路由守卫,可以用watch 监听,或者 beforeRouteUpdate
每个守卫都有三个参数:to,form,next to: 表示将要进入的路由目标 from:表示当前导航正要离开的路由 next: ...
路由独享守卫用法:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
组件内的守卫:
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
//不过,你可以通过传一个回调给 next来访问组件实例。
//在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数。
beforeRouteEnter (to, from, next) {
next(vm => {
// 通过 `vm` 访问组件实例
})
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
离开守卫beforeRouteLeave:
通常用来禁止用户在还未保存修改前突然离开。该导航可以通过 next(false)
来取消:
beforeRouteLeave (to, from , next) {
const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
if (answer) {
next()
} else {
next(false)
}
}
十八、你的登陆拦截怎么实现的?
十九、你是如何封装一个组件的,组件封装设计思想
二十、闭包是什么?如何实现?
定义:闭包是指有权访问另一个函数作用域中的变量的函数
实现闭包:就是函数体内包含一个变量和一个函数,被包含的函数可以访问外部函数体的变量
JS 中闭包的优缺点及特性:
优点:
1、保护函数内的变量安全
2、在内存中维持一个变量
3、逻辑连续,当闭包作为另一个函数调用的参数时,避免你脱离当前逻辑而单独编写额外逻辑
4、方便调用上下文的局部变量。
5、加强封装性,可以达到对变量的保护作用。
缺点:
1、常驻内存,会增大内存使用量,使用不当很容易造成内存泄漏。
2、浪费内存
特性:
1、函数嵌套函数
2、内部函数可以访问外部函数的变量
3、参数和变量不会被回收。