1. 解决跨域
jsonp的原理**:ajax 请求受同源策略影响,不允许进行跨域请求,我们利用 script 标签的 src 属性不受同源策略的约束
** nginx是代理** 前后端通常通过 nginx 实现反向代理,优点就是轻量级、启动快、高并发。
**CORS(跨域资源共享)** CORS 全称叫跨域资源共享,主要是后台工程师设置后端代码来达到前端跨域请求的
vue 的时使用 proxy 进行跨域代理
2.jsonp 的原理
ajax 请求受同源策略影响,不允许进行请求,我们利用 script 标签的 src 属性不受同源策略的约束,利用这个特性jsonp需要以下步骤:
使用 document.createElement('script') 创建script 标签 ,写一个fn函数用来接收返回的数据 设置 src 属性 src 中要包含参数 callback= "函数名字" , 将创建好的 script 标签插入到页面中,后端会返回回调函数执行并包裹参数callback(data)
服务端不再返回JSON格式的数据,而是返回回调函数包裹数据(fn({name:'tom',age:18}),在src中进行了调用,这样实现了跨域
3.jsonp的优缺点
优点
它不像XMLHttpRequest对象实现的Ajax请求那样受到同源策略的限制,JSONP可以跨越同源策略;
它的兼容性更好,在更加古老的浏览器中都可以运行,不需要XMLHttpRequest或ActiveX的支持
缺点
1、它只支持GET请求而不支持POST等其它类型的HTTP请求它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。
2、 jsonp在调用失败的时候不会返回各种HTTP状态码。
3、缺点是安全性。万一假如提供jsonp的服务存在页面注入漏洞,即它返回的javascript的内容被人控制的。那么结果是什么?所有调用这个 jsonp的网站都会存在漏洞。于是无法把危险控制在一个域名下…所以在使用jsonp的时候必须要保证使用的jsonp服务必须是安全可信的。
4.为什么会有同源策略?
**非同源策略:**不同协议,不同域名,不同端口以及域名和 ip 地址的访问都会产生跨域。非同源策略会产生跨域
**同源策略**:同协议、同域名、同端口。
JavaScript访问资源,处于安全方面考虑,要限制JS的访问能力,不允许跨域访问资源。如果没有同源限制存在浏览器中的cookie等其他数据可以任意读取,不同域下DOM任意操作,
ajax任意请求的话如果浏览了恶意网站那么就会泄漏这些隐私数据。
5. vue是什么
Vue 是一套用于构建用户界面的渐进式框架
1.库(插件):是一种封装好的特定方法集合,对项目的侵入性较小,提供给开发者使用,控制权在使用者手中,如果某个库无法完成某些需求,可以很容易切换到其它库实现需求
2.框架:是一套架构,会基于自身特点向用户提供一套相当完整的解决方案,而且控制权在框架本身;对项目的侵入性较大,使用者要按照框架所规定的某种特定规范进行开发,项目如果需要更换框架,则需要重新架构整个项目
6.单页面
```
单页面应用(SPA--------single page application),一个web项目只有一个页面(即一个HTML文件);一个项目的所有页面的所有内容被分成了很多的小块(即组件),可以重复利用的,可以任意调整的组件,每个组件就是一个独立的部分(包括html,css和javascript代码)。
```
7.spa
```
单页Web应用(single page web application,SPA),就是只有一张Web页面的应用,是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序。
```
8. vue的优缺点
```
vue两大特点:灵活的组件应用,高效的数据绑定
vue的优势:轻量级框架、简单易学、双向数据绑定、组件化、数据和结构的分离、虚拟DOM、运行速度快。
vue是单页面应用,使页面局部刷新,不用每次跳转页面都要请求所有数据和dom,这样大大加快了访问速度和提升用户体验。而且他的第三方ui库很多节省开发时间。
vue的缺点
1、Vue 不缺入门教程,可是很缺乏高阶教程与文档。同样的还有书籍。
2、VUE不支持IE8
3、生态环境差不如angular和react
4、社区不大
```
9.渐进式框架的理解,vue数据驱动的理解
**渐进式代表的含义是**:主张最少——它是一个轻量级框架,只做了自己该做的事,没有做不该做的事
**每个框架都不可避免会有自己的一些特点,从而会对使用者有一定的要求,这些要求就是主张,主张有强有弱,它的强势程度会影响在业务开发中的使用方式。**
这里的vue数据驱动的是视图,也就是DOM元素,指的是让DOM的内容随着数据的改变而改变框架的理解
10.mvvm.mvc
MVC:是后台的框架模式 分为M:(model模型)、V(view试图)、C(controller控制器)
MVVM 就是 Model-View-ViewModel 的缩写,MVVM 将视图和业务逻辑分开。
**View:视图层,Model 数据模型,而 ViewModel 是把两者建立通信的桥梁。**
**在 MVVM 框架下,View 和 Model 之间没有直接的联系,而是通过 ViewModel 进行交互。View 和 ViewModel 之间以及 Model 和 ViewModel 之间的交互都是双向的,因此 view 数据的变化会同步到 Model 中,而 Model 数据的变化也会立即反映到 View 上。可以说它们两者是实时更新的,互相影响。** ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而 View 和 Model 之间的同步工作完全是自动的,**因此开发者只需要关注业务逻辑,不需要手动操作 DOM,也不需要关注数据状态的同步问题,这些都由 MVVM 统一管理**
11. jq和vue的优缺点
```
jQuery是使用选择器($)选取DOM对象,对其进行赋值、取值、事件绑定等操作,其实和原生的HTML的区别只在于可以更方便的选取和操作DOM对象,而数据和界面是在一起的。比如需要获取label标签的内容:$("lable").val();,它还是依赖DOM元素的值。
Vue则是通过Vue对象将数据和View完全分离开来了。对数据进行操作不再需要引用相应的DOM对象,可以说数据和View是分离的,他们通过Vue对象这个vm实现相互的绑定。这就是传说中的MVVM。优势简单,快速,组合,紧凑,强大而迅速崛起,跨平台
```
12.computed, watch 的区别
watch:
watch 没有缓存性 监听data中的属性 属性值只要发生变化就会执行 可以利用他的特性做一些异步的操作
1、watch 函数是不需要调用的。
2、重点在于监控,监控数据发生变化的时候,执行回调函数操作。
3、当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch
4、函数名就是你要监听的数据名字
computed:
computed 是vue中的计算属性,具有缓存性,当他的依赖值,发生改变的时候才会重新调用
1、一个需要的结果受多个数据影响的时候,比如购物车结算金额(受到很多处的价格结算)。
2、操作某个属性,执行一些复杂的逻辑,并在多处使用这个结果。
3、内部函数中多处要使用到这个结果的。
13. vue底层原理?vue响应式原理?vue的数据双向绑定原理?
vue 作为一种MVVM模式的框架,其数据绑定的底层原理为: **数据劫持 + 发布订阅者模式** 。
是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调从而达到数据和视图同步。
14.vue的指令
⑴v-bind:给元素绑定属性
⑵v-on:给元素绑定事件
⑶v-html:给元素绑定数据,且该指令可以解析 html 标签
⑷v-text:给元素绑定数据,不解析标签
⑸v-model:数据双向绑定
⑹v-for:遍历数组
⑺v-if:条件渲染指令,动态在 DOM 内添加或删除 DOM 元素
⑻v-else:条件渲染指令,必须跟 v-if 成对使用
⑼v-else-if:判断多层条件,必须跟 v-if 成对使用
⑽v-cloak:解决插值闪烁问题
⑾v-once:只渲染元素或组件一次
⑿v-pre:跳过这个元素以及子元素的编译过程,以此来加快整个项目的编译速度
⒀v-show:条件渲染指令,将不符合条件的数据隐藏(display:none)
15.v-if和v-show的区别及使用场景?
v-if 动态的创建或者销毁元素,为true的时候为显示,为false的时候不显示,要使用v-else必须和v-if紧挨着
v-show 是控制元素的显示或者隐藏,在我们的标签上会看到有display:block,none
v-if 有更高的切换消耗,而 v-show 有更高的初始化渲染消耗,一般推荐频繁切换的时候使用 v-show 更好,当我们的判断分支比较多的时候,和首次渲染的时候 使用v-if
16. 什么是生命周期?
beforeCreate() 创建前,这个时候data中的数据,还未定义,所以不能使用
created()创建后 最早开始使用 data和methods中数据的钩子函数
beforeMount()挂载前 指令已经解析完毕内存中已经生成dom树,但是尚未挂载到页面中去,此时页面还是旧的。
mounted()挂载后 dom已经渲染完毕,此时页面和内存中都是最新的数据,最早可以操作DOM元素钩子函数
beforeUpdate()更新前 当视图层的数据发生改变会执行这个钩子 内存更新,但是DOM节点还未更新,数据没有与页面同步
updated()更新后 数据更新完成以后触发的方法,DOM节点已经更新
beforeDestroy()即将销毁 data和methods中的数据此时还是可以使用的,可以做一些释放内存的操作
destroyed()销毁完毕 组件已经全部销毁,Vue实例已经被销毁,Vue中的任何数据都不可用
其他三个:
activated 被 keep-alive 缓存的组件激活时调用。
deactivated 被 keep-alive 缓存的组件停用时调用。
errorCaptured 2.5.0+ 新增当捕获一个来自子孙组件的错误时被调用
17.内置组件有哪些?功能分别是什么?
router-link 生命式导航
router-view vue路由的坑
component组件:有两个属性---is inline-template
渲染一个‘元组件’为动态组件,按照'is'特性的值来渲染成那个组件
transition组件:为组件的载入和切换提供动画效果,具有非常强的可定制性,支持16个属性和12个事件
transition-group:作为多个元素/组件的过渡效果
keep-alive:包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们
slot:作为组件模板之中的内容分发插槽,slot元素自身将被替换
18.vue组件通信方式有哪些?
**父传递子如何传递**
(1)在父组件的子组件标签上绑定一个属性,挂载要传输的变量
(2)在子组件中通过props来接受数据,props可以是数组也可以是对象,接受的数据可以直接使用 props: ["属性名"] props:{属性名:数据类型}
子传递父如何传递
(1)在父组件的子组件标签上自定义一个事件,然后调用需要的方法
(2)在子组件的方法中通过 this.$emit("事件")来触发在父组件中定义的事件,数据是以参数的形式进行传递的
**兄弟组件如何通信**
(1)找到min.js文件,给他vue挂载一个 公共的 $bus Vue.prototype.$bus = new Vue()
(2)传送数据的一方 用this.$bus.$emit('事件名','传送的数据')
(3)在 接收数据的一方用通过 Bus.$on("事件名",(data)=>{data是接受的数据})
19.vuex的工作(执行)流程是什么?
运行机制:Vuex提供数据(state),来驱动视图(这里指的是Vue组件),视图通过Dispatch派发Action,在Action中可以进一步做一些异步的操作(例如通过ajax请求后端的接口数据),然后通过Commit提交给Mutations,由Mutations去最终更改state。那么为什么要经过Mutations呢?这是因为我们要在Vue调试工具(Devtools)中记录数据的变化,这样可以通过插件去进行进一步的调试。所以说Mutations中只能是纯同步的操作,如果是有异步操作,那么就需要在Actions中进行处理。如果说没有异步操作,那么可以直接由组件进行Commit操作Mutations。
```
20.**路由的原理**
**路由就是用来解析URL以及调用对应的控制器,并返回从视图对象中提取好的网页代码给web服务器,最终返回给客户端。**
1.vue路由的跳转方式有几种
<router-link to="需要跳转到页面的路径">
.this.$router.push()跳转到指定的url,并在history中添加记录,点击回退返回到上一个页面
.this.$router.replace()跳转到指定的url,但是history中不会添加记录,点击回退到上上个页面
.this.$touter.go(n)向前或者后跳转n个页面,n可以是正数也可以是负数
21.vue 路由传参数如何实现
query 和 params
主要通过 query 和 params 来实现
(1) query可以使用name和path而params只能使用name
(2) 使用params传参刷新后不会保存,而query传参刷新后可以保存
(3) Params在地址栏中不会显示,query会显示
(4) Params可以和动态路由一起使用,query不可以
(5)to=”/goods?id=1001”this.然后在接收的页面通过 $route.query.id 来接收
22.路由钩子
•一:全局的守卫
无论访问哪一个路径,都会触发全局的钩子函数,位置是调用router的方法 router/index.js
1. router.beforeEach 全局前置守卫 进入路由之前
2. router.beforeResolve 全局解析守卫,在beforeRouteEnter调用之后调用
同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被正确调用
3. router.afterEach 全局后置钩子 进入路由之后
你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 `next` 函数也不会改变导航本身:
二:组件级路由守卫 放在要守卫的组件里,跟data和methods同级
- beforeRouteEnter 进入路由前,此时实例还没创建,无法获取到zhis
- beforeRouteUpdate (2.2) 路由复用同一个组件时
- beforeRouteLeave 离开当前路由,此时可以用来保存数据,或数据初始化,或关闭定时器等等
```javascript
//在组件内部进行配置,这里的函数用法也是和beforeEach一毛一样
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
```
三:单个路由规则独享的守卫 写在路由配置中,只有访问到这个路径,才能触发钩子函数
beforeEnter(){}
**参数**
- **`to: Route`**: 即将要进入的目标 [路由对象](https://link.juejin.cn/?target=https%3A%2F%2Frouter.vuejs.org%2Fzh%2Fapi%2F%23%E8%B7%AF%E7%94%B1%E5%AF%B9%E8%B1%A1)
- **`from: Route`**: 当前导航正要离开的路由对象
- **`next: Function`**: 一定要调用该方法来 **resolve** 这个钩子。执行效果依赖 `next` 方法的调用参数。
当然vue3没有的 next 了 取值用 return 代替
重定向用哪个属性? redirect:”/路径”
23.http 与 https区别?
http的默认端口80 https默认端口443
https加密证书
24.本地存储的区别?
cookie与h5本地存储最大区别:会自动跟随http请求上传到服务器,也是服务器程序可以直接修改的浏览器本地存储。
h5本地存储不可以上传到服务器
25.事件委托?
基于事件冒泡的特性的一种用法,
1、必须是嵌套的父子结构
2、事件类型要一致
26.你对前端的理解?
让用户使用图形化的操作与程序交互
前端将设计师的稿件用代码绘制出来,形成图形程序
前端将产品要求的交互逻辑实现出来,作为效果。
前端将后端的程序ajax作为桥梁交互,实现功能。
27.为何组件的 data 必须是一个函数、
如果不是一个函数,每个组件实例的data都是同一个引用数据,当该组件作为公共组件共享使用,一个地方的data更改,所有的data一起改变,如果data是一个函数,每个实例的data都在闭包中,就不会各自影响了。
【Object是引用数据类型,如果不用function返回,每个组件的data都是内存的同一个地址,一个数据改变了其他也改变了,这就造成了数据污染。如果data是一个函数,每个实例的data都在闭包中,就不会各自影响了】
28.vue 常用的指令、
⑴v-bind:给元素绑定属性 ⑵v-on:给元素绑定事件 ⑶v-html:给元素绑定数据,且该指令可以解析 html 标签 ⑷v-text:给元素绑定数据,不解析标签 ⑸v-model:数据双向绑定 ⑹v-for:遍历数组 ⑺v-if:条件渲染指令,动态在 DOM 内添加或删除 DOM 元素 ⑻v-else:条件渲染指令,必须跟 v-if 成对使用 ⑼v-else-if:判断多层条件,必须跟 v-if 成对使用 ⑽v-cloak:解决插值闪烁问题 ⑾v-once:只渲染元素或组件一次 ⑿v-pre:跳过这个元素以及子元素的编译过程,以此来加快整个项目的编译速度 ⒀v-show:条件渲染指令,将不符合条件的数据隐藏(display:none)
29.v-if/v-show 区别、
1、 v-if通过创建或删除DOM节点来实现元素的显示隐藏,v-show通过css中的display属性来控制
2、v-if更适合数据的筛选和初始渲染 v-show更适合元素的切换 3、v-if会频繁触发组件生命周期,v-show则不会。
【v-if 有更高的切换消耗,而 v-show 有更高的初始化渲染消耗,一般推荐频繁切换的时候使用 v-show 更好,当我们的判断分支比较多的时候,和首次渲染的时候 使用v-if】
30.vue 生命周期
beforeCreate() 创建前,这个时候data中的数据,还未定义,所以不能使用 created()创建后 最早开始使用 data和methods中数据的钩子函数 beforeMount()挂载前 指令已经解析完毕内存中已经生成dom树,但是尚未挂载到页面中去,此时页面还是旧的。 mounted()挂载后 dom已经渲染完毕,此时页面和内存中都是最新的数据,最早可以操作DOM元素钩子函数 beforeUpdate()更新前 当视图层的数据发生改变会执行这个钩子 内存更新,但是DOM节点还未更新,数据没有与页面同步 updated()更新后 数据更新完成以后触发的方法,DOM节点已经更新 beforeDestroy()即将销毁 data和methods中的数据此时还是可以使用的,可以做一些释放内存的操作 destroyed()销毁完毕 组件已经全部销毁,Vue实例已经被销毁,Vue中的任何数据都不可用 其他三个: activated 被 keep-alive 缓存的组件激活时调用。 deactivated 被 keep-alive 缓存的组件停用时调用。 errorCaptured 2.5.0+ 新增当捕获一个来自子孙组件的错误时被调用
31.vue 数据双向绑定原理、
是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter在数据变动时发布消息给订阅者,触发相应的监听回调来渲染视图, 实现数据和视图同步。
在vue**3** 中
Vue3是通过Object.define.proxy 对对象进行代理,从而实现数据劫持。使用Proxy 的好处是它可以完美的监听到任何方式的数据改变,唯一的缺点是兼容性的问题,因为 Proxy 是 ES6 的语法
32.Vue 虚拟 Dom 、vue diff 算法
虚拟dom是用js对象来描述真实的dom,在这个js对象里,体现了真实dom的节点名称,属性名称以及子元素等内容
我们在渲染页面的时候 会对新的虚拟dom和旧的虚拟dom进行对比 只渲染不同的地方,而不再是像之前只要发生变化,全部真实的dom都要重新渲染,所以提高了渲染的效率,vue虚拟dom使用diff算法计算出来的。
Diff算法
diff算法就是进行虚拟节点对比,并返回一个patch对象,用来存储两个节点不同的地方,最后用patch记录的消息去局部更新Dom。
##### 【虚拟 DOM,其实就是用对象的方式取代真实的 DOM 操作,把真实的 DOM 操作放在内存当中,在内存中的对象里做模拟操作。当页面打开时浏览器会解析 HTML 元素,构建一颗 DOM 树,将状态全部保存起来,在内存当中模拟我们真实的 DOM 操作,操作完后又会生成一颗 dom 树,两颗 DOM 树进行比较,根据 diff 算法比较两颗 DOM 树不同的地方,只渲染一次不同的地方。 (个人理解)**虚拟dom**他不并不是真实的 dom ,是根据模板生成一个js对象(使用createElement,方法),根据这个js对象再去生成真实的dom,对复杂的文档DOM结构,提供一种方便的工具,进行最小化的DOM操作 ,是可以快速的渲染和高效的更新元素,提高浏览器的性能, diff 算法是一种通过同层的树节点进行比较的高效算法,比较方式:diff整体策略为:深度优先,同层比较 当data发生改变 会根据新的数据生成一个新的虚拟dom ,新的虚拟dom和旧的虚拟dom进行对比,这个对比的过程就是diff算法,会找到不同地方,只去渲染不同的地方,总的来说就是减少DOM,重绘和回流。】
33.vue 组件通信、vuex、watch 深度监听
1.父传子:
父组件使用v-bind向子组件传递数据,子组件使用props接收父组件传递的数据。
2.子传父:
父组件使用v-on向子组件绑定自定义事件,子组件使用$emit
调用父组件传递的函数名字。
3.兄弟组件传值:
通过main.js初始化一个全局的$bus,在发送事件的一方通过$bus.$emit(“事件名”,传递的参数信息)发送,在接收事件的一方通过$bus.$on("事件名",参数)接收传递的事件
使用同一个父组件作为中间消息传递者实现兄弟通信
4.$attrs和$listeners
如果父组件A下面有子组件B,组件B下面有组件C,这个时候A组件想要传数据给C组件就可以用这种方式实现。适合用于多级组件嵌套传值
在b组件中使用组件c的时候用v-bind绑定一个属性$attrs这样就可以直接在c组件中拿到父组件a传下来的数据了。用v-on绑定一个$listeners属性就可以直接在组件c里调用a组件的方法了。
5.provider和inject
父组件中通过provider来提供变量,然后在子组件中通过inject来注入变量。不论子组件有多深,都可以通过inject来调用provide的数据
但是这种写法传递的数据是不响应的。
6.v-model也能实现组件传值
给子组件绑定v-model,子组件被注入value属性和input事件,在子组件中通过emit调用input事件就能修改父组件的v-model值
7.$parent和$children
在组件内部可以直接通过子组件$parent对父组件进行操作,父组件通过$children对子组件进行操作.$children是一个数组 用的时候加下标
8.Vuex
vuex也可以实现组件之间的传值,把公共的数据放在state中,所有的组件都可以使用
vuex
vuex是一个状态管理工具,所谓状态的是就是数据,采用集中式存储管所有组件的状态,是为了解决中大型项目一个数据共享的问题。vuex 他可以将数据保存到本地,数据是响应式的,能够保持数据页面的共享,提高开发效率。 12中vue通信方式硬核:https://blog.csdn.net/qq_54753561/article/details/122281196?spm=1001.2014.3001.5502
watch深度监听
watch是默认不开启深度监听的,需要手动开启,deep:true 开启后可以深度监听数组,对象
34.vue 中 Computed、Methods、Watch 区别
Watch、Computed 被监听的数据发生改变的时候都能够做出响应、methods是事件方法的集合
computed
computed的工作原理
监听一个数据返回一个数据,且新数据必须被使用才能对被监听数据做观察。
watch
watch的共组原理
就是单纯的监听一个数据,当数据改变后就执行
watch对数据类型的要求
如果是对象/数组则需要开启深度监听,而计算属性没有数据类型的要求
watch每次只能对一个数据监听,而计算可以一次监听多个值,只要其中一个 值发生变化,就会执行
watch可以执行异步操作,当一个数据改变后发起接口请求。但是用为计算属性属于立即执行立即返回,所以只能写同步代码
methods
methods不会被缓存:方法每次都会去重新计算结果。methods 方法表示一个具体的操作,主要书写业务逻辑; 使用 methods 方法编写的逻辑运算,在调用时 add() 一定要加“()”,methods 里面写的多位方法,调用方法一定要有()。methods方法页面刚加载时调用一次,以后只有被调用的时候才会被调用。我们在长度框和宽度框的值输入完以后,点击“+” methods 方法调用一次。这里很明显我们采用 methods 会更节省资源。
35.mvvm 和 mvc
MVVM是为了实现MVC中的V MVVM分为:M(model数据)、V(view试图)、VM(viewModel控制数据的改变和控制试图)
区别:MVC中Controller演变成了MVVM中的viewModel。MVVM主要解决了MVC中大量的DOM操作带来的使页面渲染性能降低,加载速度变慢等问题。MVVM中当和Model频繁发生变化,开发者需要主动更新到View。
(2)MVVM是为了实现MVC中的V MVVM分为:M(model数据)、V(view试图)、VM(viewModel控制数据的改变和控制试图) MVVM与MVC最大的区别就是:它实现了View和Model的自动同步,也就是当Model的属性改变时,我们不用再自己手动操作Dom元素,来改变View的显示,而是改变属性后该属性对应View层显示会自动改变。非常的神奇~这里我们拿典型的MVVM模式的代表,Vue, html部分相当于View层,可以看到这里的View通过通过模板语法来声明式的将数据渲染进DOM元素,当ViewModel对Model进行更新时,通过数据绑定更新到View。 Vue实例中的data相当于Model层,而ViewModel层的核心是Vue中的双向数据绑定,即Model变化时VIew可以实时更新,View变化也能让Model发生变化。 整体看来,MVVM比MVC精简很多,不仅简化了业务与界面的依赖,还解决了数据频繁更新的问题,不用再用选择器操作DOM元素。因为在MVVM中,View不知道Model的存在,Model和ViewModel也观察不到View,这种低耦合模式提高代码的可重用性。 优点:数据源和视图实现了双向绑定,很好的做到了数据的一致性 相比于mvp各层的耦合度更低,一个viewmodel层可以给多个view层共用。 缺点: 因为使用了dataBinding,增加了大量的内存开销,增加了程序的编译时间,项目越大内存开销越大。 数据绑定使得 Bug 很难被调试。你看到界面异常了,有可能是你 View 的代码有 Bug,也可能是 Model 的代码有问题 • (1)mvc 分为M:(model模型)、V(view试图)、C(controller控制器) MVC(Model View Controller)是软件工程中的一种软件架构模式,它把软件系统分为模型、视图和控制器三个基本部分。用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。 【优点】 耦合性低,方便维护,可以利于分工协作 重用性高 【缺点】 使得项目架构变得复杂,对开发人员要求高
36.vue 中的事件修饰符、
.stop 阻止事件冒泡 .cpture 设置事件捕获 .self 只有当事件作用在元素本身才会触发 .prevent 阻止默认事件,比如超链接跳转 .once 事件只能触发一次 .native 触发js原生的事件 .number 把文本框的内容转换为数字 .trim 去除文本框左右空格
37.vue 自定义组件、
在vue 中的 component 中新建组件,定义好<template>视图层,<script>逻辑层,<style>css样式层。,然后在页面引入,在components 中注册组件 ,在页面中作为标签来使用。 在vue中开发,都是用的组件化的思想开发的,组件封装的方式可以使我们的开发效率提高,把单页面的每个模块拆分为一个组件件, 组件封装的方式解决了我们传统项目,开发效率低,难以维护,复用性低等问题。 使用:比如说封装一个 swiper 首先我们要定义一个props要接受传递的数据,写入响应的逻辑,在通过import引入到页面注册作为标签使用即可。
38.vue 自定义指令、
vue中除了核心功能内置的指令外,也允许注册自定义指令。自定义指令又分为全局的自定义指令和局部自定义指令。 ##### *全局自定义指令\****是通过Vue.directive('第一个参数是指令的名称',{第二个参数是一个对象,这个对象上有钩子函数}) ***\*局部自定义指令:\**** 是定义在组件内部的,只能在当前组件中使用 ***\*钩子函数:\**** 一个指令定义对象可以提供如下几个钩子函数 (均为可选): **inserted**:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。 **bind**:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。 **update**:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。 **componentUpdated**:指令所在组件的 VNode 及其子 VNode 全部更新后调用。 **unbind**:只调用一次,指令与元素解绑时调用。
自定义指令使用场景、
拖拽、输入框获取焦点、图片懒加载、对dom进行操作
39.vue 自定义过滤器 filter、
过滤器是对 即将显示的数据做进一步的筛选处理,然后显示,过滤器并没有改变原来的数据,只是在原数据的基础上产生新的数据 全局: Vue.filter(‘过滤器名’,funciton(val){}) 局部过滤器,定义在组件内部 filters 属性上.它只能在此组件内部使用. filters:{过滤器名:funciton(参数){//逻辑代码}} 使用: 过滤时间,过滤金钱
40.vue-router、vue-router 原理、vue 脚手架本地开发跨域请求设置
由于Vue在开发时对路由支持的不足,于是官方补充了vue-router插件。vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。传统的页面应用,是用一些超链接来实现页面切换和跳转的。在vue-router单页面应用中,则是路径之间的切换,实际上就是组件的切换。路由就是SPA(单页应用)的路径管理器。再通俗的说,vue-router就是我们WebApp的链接路径管理系统。 原理 一般源码中,都会用到 window.history 和 location.hash 原理:通过改变浏览器地址URL,在不重新请求页面的情况下,更新页面视图,通过BOM中的location对象,其中对象中的location.hash储存的是路由的地址、可以赋值改变其URL的地址。而这会触发hashchange事件,而通过window.addEventListener监听hash值然后去匹配对应的路由、从而渲染页面的组件 1.一种是# hash,在地址中加入#以欺骗浏览器,地址的改变是由于正在进行页内导航 2.一种是h5的history,使用URL的Hash来模拟一个完整的URL 在根目录创建vue.config.js 在module.exports中配置devserver的内容 主要是通过 proxy devServer: { host:'0.0.0.0', port: 8080,//端口号 open: true,//运行项目自启 proxy:{ '/api':{ target:'http://localhost:3000/',//跨域请求资源地址 ws:false,//是否启用websockets changeOrigin:true,//开启代理:在本地会创建一个虚拟服务端,然后发送请求的数据,并同时接收请求的数据,这样服务端和服务端进行数据的交互就不会有跨域问题 pathRewrite:{ '^/api':''//注册全局路径 } } } }
41.keep-alive
keep-alive是Vue提供给我们一个内置组件,会缓存不活动的组件实例,而不是销毁它们, 作为标签使用 包裹在需要缓存的组件外 在组件切换过程中 把切换出去的组件保留在内存中,防止重复渲染DOM,减少加载时间及性能消耗,提高用户体验性 **作用:** 比如列表页面进入详情,我们想保存列表滚动的位置,我们就可以使用keep-alive保存列表页面的滚动位置。 组件使用keep-alive以后会新增两个生命周期 actived() deactived() activated(组件激活时使用) 与 deactivated(组价离开时调用)
42.v-for 中为何要使用 key
key是给每一个vnode的唯一id,也是diff的一种优化策略,可以根据key,更准确, 更快的找到对应的vnode节点
43.slot、vue 中的 prop 验证
slot就是插槽有三种
默认插槽就是把父组件中的数据,显示到子组件中,子组件通过一个slot插槽标签显示父组件中的数据 具名插槽就是在父组件中通过slot属性,给插槽命名,在子组件中通过slot标签,根据定义好的名字填充到对应的位置 作用域插槽:他是带有数据的插槽,子组件提供给父组件的参数,父组件根据子组件传过来的插槽来进行不同的展现和填充内容,在标签中通过slot-scope来接收数据
单项数据流 所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。 每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。
44.vue 中$nextTick()作用
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM
this.$nextTick()将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上。 可以根据打印的顺序看到,在created()钩子函数执行的时候DOM 其实并未进行任何渲染,而此时进行DOM操作并无作用,而在created()里使用this.$nextTick()可以等待dom生成以后再来获取dom对象,而通过this.$nextTick()获取到的值为dom更新之后的值
45.vue 修改数据页面不更新
xxxxxxxxxx 问题原因:因为 vue 的检查机制在进行视图更新时无法监测 数组中的对象的某个属性值的变化。解决方案如下Object.defineProperty 无法监控到数组下标的变化,导致直接通过数组的下标给数组设置值,不能实施响应。 this.$set()解决vue3没有这个问题因为是 proxy方案一:利用 this.set(this.obj,key,val)
46. vue2 和 vue3 的区别
-
2.双向数据绑定原理发生了改变,vue3的proxy替换vue2的Object.defineProperty
3.Vue3默认使用懒加载
4.Vue3新加入了TypeScript以及PWA支持
5.重构虚拟DOM
6.生命周期也有改变
7.vue3取消了过滤器filters
使用 选项类型API(Options API) 对比Vue3 合成型API(Composition API) vue2 - optionsApi 使用传统api中,新增一个需求,要在data,methods,computed中修改 vue3 - compositionApi 我们可以更加优雅的组织我们的代码,函数,让我们的代码更加有序的组合在一起 随着虚拟 DOM 重写,减少 运行时(runtime)开销。重写将包括更有效的代码来创建虚拟节点。 vue3 没有了过滤器 双向数据绑定 从 Object.defineProperty() 变成了 proxy,通过下标修改数组变化了试图数据没发生变化 this.$set() vue3不需要 1. 双向数据绑定原理发生了改变,使用proxy替换Object.defineProerty,使用Proxy的优势: setup 函数 3.0新加入了TypeScript以及PWA支持 声明周期的变化
-
vue2是选项api 需要什么选项就直接写什么选项 vue3是组合api 所有的代码都写在setup里边 需要什么就要import引入什么
-
-
vue 中的 provide 和 inject (依赖注入)
父组件中通过provider来提供变量,然后在子组件中通过inject来注入变量。不论子组件有多深,都可以通过inject来调用provide的数据
但是这种写法传递的数据是不响应的。
provide / inject 为依赖注入,说是不推荐直接用于应用程序代码中,但是在一些插件或组件库里却是被常用,所以我觉得用也没啥,还挺好用的 provide:可以让我们指定想要提供给后代组件的数据或方法 inject:在任何后代组件中接收想要添加在这个组件上的数据或方法,不管组件嵌套多深都可以直接拿来用 要注意的是 provide 和 inject 传递的数据不是响应式的,也就是说用 inject 接收来数据后,provide 里的数据改变了,后代组件中的数据不会改变,除非传入的就是一个可监听的对象 详细 : https://blog.csdn.net/qq_54753561/article/details/122281196?spm=1001.2014.3001.5502
-
vue 动画 transition
Vue提供了transition的封装组件,在下列情况中,可以给任何元素和组件添加”进入”和”离开”过渡动画。
可以实现过渡和动画标签,是vue的内置组件 v-enter:定义上半场过渡的初始状态;在过渡开始前被添加,在过渡开始时会被移除 v-enter-to:定义上半场过渡的结束状态;在过渡开始时被添加,在过渡完成时会被移除 v-enter-active:这里包含了上面的v-enter、v-enter-to两个时间段,在这里可以对上半场过渡定义过渡时间、曲线等 v-leave:定义下半场过渡的初始状态;在过渡开始前被添加,在过渡开始时会被移除 v-leave-to:定义下半场过渡的结束状态;在过渡开始时被添加,在过渡完成时会被移除 v-leave-active:这里包含了上面的v-leave、v-leave-to两个时间段,在这里可以对下半场过渡定义过渡时间、曲线等
-
vue 中 mixins(混入)的使用
混入 (mixins): 是一种分发 Vue 组件中可复用功能的非常灵活的方式。混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项
在src目录下创建一个mixins文件夹,文件夹下新建一个myMixins.js文件。
在需要调用的组件中引入myMixins.js文件,然后在export default 中引入你需要的对象即可
interview
css
布局方式
1、table布局
2、float布局 浮动元素是脱离文档流的
3、响应式布局
-
响应式布局就是做一个网站同时能兼容多个终端,由一个网站转变成多个网站,为我们大大节省了资源
-
媒体查询
使用 @media 或 @import 规则在样式表中指定对应的设备类型
rem
vh vw
百分比
4.display:flax 弹性布局
flex-direction 容器内元素的排列方向(默认横向排列)
justify-content 元素在主轴(页面)上的排列\
flex-wrap 容器内元素的换行(默认不换行)
align-content 在弹性容器内的元素没有占用交叉轴上所有可用的空间时对齐容器内的各项(垂直)
align-items 元素在主轴(页面)当前行的横轴(纵轴)方向上的对齐方式
rem px % vw vh 的区别
px:表示“绝对尺寸”(这里并非真正的绝对),实际上就是css中定义的像素
em:表示相对尺寸,其相对于元素的父元素文本的font-size
rem:也表示相对尺寸,其参考对象为根元素<html>的font-size
vh、vw:主要⽤于⻚⾯视⼝⼤⼩布局,在⻚⾯布局上更加⽅便简单
如何实现元素⽔平垂直居中?
1.已知宽高盒子:绝对定位top:50%;left:50%;transform:translate(-50%,-50%)
2.位置宽高盒子: 绝对定位上下左右为 margin:auto
3.flex弹性布局:display: flex; justify-content: center; align-items: center;
盒模型
-
标准盒模型
宽=内边距+外边距+内容宽+边框 width = padding + margin + border + width
box-sizing:content-box; 将采用标准模式的盒子模型标准
-
怪异盒模型
宽=外边距+内容宽 width = margin + width
box-sizing:border-box; 将采用怪异模式的盒子模型标准
BFC
1.定义:块级格式化上下文(Block Formatting Context)
2.原理:形成块级区域(行内块),有自己的排列方式
3.触发:
2.浮动元素:float除none以外的值
3.定位元素:position的值为absolute或fixed
4.overflow值不为 visible,为 auto、scroll、hidden
5. display的值为inline-block、inltable-cell、table-caption、table、inline
table、flex、inline-flex、grid、inline-grid
-
利⽤BFC的特性,我们将
BFC
应⽤在以下场景:防⽌margin重叠(塌陷)
清除内部浮动
⾃适应多栏布局
动画 animation
visibility:属性规定元素是否可见
hidden: 元素是不可见的
visible: 元素是可见的
transform: 改变
translate: 移动
rotate:旋转
scale:缩放
transform-origin:设置旋转的中心点
transition:过度效果
(过渡属性、过渡时间、过度延迟时间、过渡形式)
linear:过渡形式表示的是匀速
-
变量 --root: { }
-
浮动:清除浮动
清除浮动主要是为了解决,父元素因为子级元素浮动引起的内部高度为0的问题
额外标签法、父元素添加overflow属性、使用after伪元素清除浮动
-
定位
position:static 静态定位
position:relative 相对定位
position:absolute 绝对定位
position:fixed 固定定位
position:sticky 粘性定位
js
new操作符
简单来说:1.new 能创建一个实例对象; 2.这个对象是给定的构造函数
手动实现new:在一个函数里创建一个空对象,然后把新对象的原型指向构造函数原型对象,然后通过call方法把构造函数的this指向新对象,最后根据返回值进行判断
AJAX原理?如何实现?
优点:可以不用刷新页面就异步调用请求数据,提高用户体验,轻量级的资源传输
原理:通过异步操作向服务器发送请求 服务器返回数据 再通过js来操作dom来更新试图
使用:
-
首先通过创建xmlhttprequest创建核心对象
-
通过这个对象的的open方法与服务器建立连接
-
创建好请求所需的内容 通过send方法向服务器发起请求
-
通过xhlhttprequest的onreadystatechange事件监听回调
-
判断状态码为200表示请求成功 接受返回的数据 渲染页面
使用场景:表单验证是否登入成功、百度搜索下拉框提示或者是快递单号查询
防抖和节流
防抖(throttle)和节流(debounce)的本质是优化高频率执行代码的一种手段,比如说scroll、mousemove这类事件在触发时,会不断的调用绑定在事件上的回调函数,非常浪费资源而且降低性能,所以使用防抖和节流进行一种限制。
防抖就是在n秒后再执行事件,如果n秒内重新触发,就重新计时,
节流就是在n秒内只运行一次,如果n秒内重新触发,也只运行一次
实现方式:防抖用定时器实现,节流用时间戳或者是定时器
使用场景:防抖:表单搜索,手机号邮箱验证,window触发一些方法的时候
节流:拖拽事件,监听滚动
-
axios
官方提供了cancelToken
的方式来拦截请求,大型复杂项目可以采用这种方式
预解析
js的执行过程是从上到下的 预解析其实就是说 var声明的变量具有变量提升 会把var声明的变量提升到最前面
深拷贝和浅拷贝
深拷贝和浅拷贝的区别
1.浅拷贝: 新对象将原对象的数据引用,而不复制原对象本身,新旧对象还是共享同一块内存
深拷贝: 新的对象将原对象的各项属性的“值”拷贝过来,新对象跟原对象不共享内存,修改新对象不会改到原对象
为什么要使用深拷贝?
我们希望在改变新的数组(对象)的时候,不改变原数组(对象)
实现浅拷贝的方式有:1.Objec.assign ( ) 、2.slice ( )、3.concat ( )、4.展开符、5.循环赋值
深拷贝:就是开辟出一个新的栈,两个对象的属性值完全相同,但是对应两个不同的地址,不会相互影响
实现深拷贝的方式有:1.JSON.stringify( )、2.循环递归
js数据类型
js中将数据类型分为两大种,基本类型和引用类型,它俩的区别是基本类型存储在栈内存中,而引用数据类型存储在堆中
基本类型有:String 、Number 、Boolean 、Null 、Undefined 、Symbol
引用类型有:Array 、Object 、Function
(Symbol 值通过Symbol函数生成。它是es6新增加的一种数据类型,生成的变量的特点是值是唯一的,可以用来作为对象的key值使用)。
堆栈区别
复杂数据类型把值存储在堆内存中,堆内存是从下往上存储。生成唯一内存地址。然后在栈内存中把地址赋值给变量。栈内存是从上往下存储的(存放基本数据类型)。之所以如此划分内存主要考虑到特别大的对象进行值传递时的效率问题
js数据类型判断
-
typeof 对于基本数据类型判断是没有问题的,但是遇到引用数据类型(如:Array)是不起作用
-
instanceof 判断 new 关键字创建的引用数据类型,不考虑 null 和 undefined(这两个比较特殊)以对象字面量创建的基本数据类型
-
constructor 完全可以应对基本数据类型和引用数据类型 但如果声明了一个构造函数,并且把他的原型指向了 Array 的原型,这种情况下,constructor 也会力不从心
-
Object.prototype.toString.call() 完美的解决方案
==和===的区别
===三等表示全等,判断左右两边对象或值是否类型相同且值相等。
==二等表示值相等
宏任务和微任务
js是单线程的,里面有同步和异步,先执行同步,异步放在队列里
遇到微任务先执行微任务,在执行宏任务
遇到promise会立即执行,且不会终止
数组的方法
数组常用方法一般来说分为增删改查,有些方法会影响原数组
合并:concat
增: .push() 、.unshift() 、.splice()
删:.pop() 、.shift() 、.splice () 、 .slice(截取不会影响)
改:.splice() 、.join(分割成字符穿格式不会影响) 、.split(转为数组格式)
查:.indexOf() 、.includes() 、.find()
数组去重:1、利用set 2、利用filter和indexOf 3、利用filter和includes
数组扁平化
数组扁平化就是将一个多维数组转换为一个一维数组
实现基本方式
1、对数组的每一项进行遍历。
2、判断该项是否是数组。
3、如果该项不是数组则将其直接放进新数组。
4、是数组则回到1,继续迭代。
5、当数组遍历完成,返回这个新数组。
字符串
大概什么时候二次,jeec
字符串是伪数组的一种
合并:concat
splice 截取
slice 截取
split 转数组
数组转为字符串
toString() 将数组转换成一个字符串
toLcalString() 把数组转换成本地约定的字符串
join() 将数组元素连接起来以构建一个字符串
字符串转为数组
split()
展开运算符 (...)
解构赋值
Array.from
字符串转大小写
oLowerCase 将字符串转为小写
toUpperCase 将字符串转为大写
对象
-
对象初始化的三种方式:
// 字面量创建 对象 var obj = { nane: 'sss' } console.log(obj.nane); // 利用 new Object() 创建对象 var obj1 = new Object(); obj1.name = 'aaa'; console.log(obj1.name); // 利用构造函数创建 function Star(name, xin) { this.name = name; this.xin = xin; } var les = new Star('leis', 'nv') console.log(les.name);
-
对象的合并方法 扩展运算符
-
查找
-
对象的方法
Object.assign()
通过复制一个或多个对象来创建一个新的对象。
Object.create()
使用指定的原型对象和属性创建一个新对象。
Object.defineProperty()
给对象添加一个属性并指定该属性的配置。
Object.defineProperties()
给对象添加多个属性并分别指定它们的配置。
Object.entries()
返回给定对象自身可枚举属性的[key, value]数组。
Object.freeze()
冻结对象:其他代码不能删除或更改任何属性。
Object.is()
比较两个值是否相同。所有 NaN 值都相等(这与==和===不同)。
Object.isExtensible()
判断对象是否可扩展。
Object.isFrozen()
判断对象是否已经冻结。
Object.isSealed()
判断对象是否已经密封。
Object.keys()
返回一个包含所有给定对象自身可枚举属性名称的数组。
Object.values()
返回给定对象自身可枚举值的数组。
作用域链
作用域一般分为三种,全局作用域,局部作用域,还有块级作用域
-
全局作用域就是不在函数或者是大括号中声明的变量,都在全局作用域下,可以任意访问
-
局部作用域,如果在函数内部声明的变量它就是在局部作用域里,只在函数内部访问,不被函数外访问
-
块级作用域是es6引入的let和const关键字,和var不同,在大括号中使用这俩只存在块级作用域中,大括号之外不能访问到这些变量
作用域链:作用域链就是 自己没有这个变量就从上一级作用域查找,直到找到为止,直到找到顶层window,没有的话就报错
对this理解?
1.浏览器里,在全局范围内的this 指向window对象;
2.在函数中,this永远指向最后调用他的那个对象;
3.构造函数中,this指向new出来的那个新的对象;
4.Call、apply、bind中的this被强绑定在指定的那个对象上;
5.箭头函数中this比较特殊,箭头函数this为父作用域的this,不是调用时的this.要知道前四种方式,都是调用时确定,也就是动态的,而箭头函数的this指向是静态的,声明的时候就确定了下来;
6.apply、call、bind都是js给函数内置的一些API,调用他们可以为函数指定this的执行,同时也可以传参。
This的指向
-
在构造函数中指向构造的实例
-
在普通函数中谁调用就指向谁
-
在箭头函数中指向它父级上下文
-
浏览器里,在全局范围内的this 指向window对象;
函数如何改变this指向
-
call.apply.bind可以修改this指向
-
call:参数是单个使用的,
-
apply:参数是一个数组,
-
call和apply都会立刻调用这个函数,bind:只改变this 不会让函数立刻调用
箭头函数和function区别
使用function定义的函数,this的指向随着调用环境的变化而变化的,而箭头函数中的this指向是固定不变的,一直指向的是定义函数的环境。 function是可以定义构造函数的,而箭头函数是不行的。
构造函数与普通函数的区别
-
返回值类型的区别:
-
构造函数是没有返回值类型 的,
-
普通函数是有返回值类型的,即使函数没有返回值,返回值类型也要写上void。
-
函数名的区别:
-
构造函数的函数名必须要与类名一致,
-
普通函数的函数名只要符合标识符的命名规则即可。
-
调用方式的区别:
-
构造函数是 在创建对象的时候由jvm调用的。
-
普通函数是由我们使用对象调用的,一个对象可以对象多次普通 的函数,
-
作用上的区别:
-
构造函数 的作用用于初始化一个对象。
-
普通函数是用于描述一类事物的公共行为的。
var、let、const之间的区别?
1.var声明的变量存在变量提升,let和const不存在变量提升,变量提升
2.let和const存在暂时性死区,(暂时性死区的本质就是块级作用域,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。)
3.let和const在同一作用域不允许重复声明变量。
4.var是函数作用域,let和const是块级作用域,块级作用域就是只要有大括号就会形成块级作用域
5.const声明的是常量,不能修改
本地存储(localStorage、sessionStorage、cookie的区别)
localStorage: localStorage 的生命周期是永久的,关闭页面或浏览器之后 localStorage 中的数据也不会消失
sessionStorage: sessionStorage 的生命周期是仅在当前会话下有效,在关闭了浏览器窗口后就会被销毁
cookie: cookie生命期为只在设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭,存放数据大小为4K左右
媒体标签
自动播放,关于移动端禁用自动播放的问题
语义化标签
代码结构清晰,易于阅读,利于开发和维护
提高用于体验,在样式加载失败时,页面结构清晰
方便其他设备解析(如屏幕阅读器)根据语义渲染网页。
有利于搜索引擎优化(SEO),搜索引擎爬虫会根据不同的标签来赋予不同的权重
<header> 网页或section的头部 <asider> 网页的侧边栏内容 <nav> 定义页面的主要导航部分 <article> 独立完整的内容模块,通常用在博客、论坛、新闻、评论等,区别于section这种分段的标签 <section> 网页文档中的段、节,通常子元素包括标题:h1-h6 <footer> 网页或section底部的内容
上拉加载,下拉刷新
上拉加载就是页面触底或者是快要触底时候的动作,通过scrollTop(滚动高度),clientHeight(可视区域),srcollHeight(body所有元素的总长度)进行一个判断,scrollTop + clientHeight >= scrollHeight - 到达触发的一个点 的时候进行加载
下拉刷新是页面在顶部时用户下拉所触发的动作,分为三步:1、监听touchstart事件记录初始值,2、监听touchmove事件记录并计算滑动的值与初始值的差值,3、监听touchend事件,就是滑到最大值的时候放开,元素回到初始位置
内存泄漏
常见的内存泄漏有闭包,死循环,意外的全局变量或者是this,还有定时器也会造成内存泄漏
说起内存泄漏就得说一下垃圾回收机制,垃圾回收机制就是定期的找出不再使用的变量进行释放,而javascript就具有自动垃圾回收机制,有两种实现方式,1、标记清除;2、引用清除
1、标记清除是最常用的垃圾回收机制,当一个变量进入环境的时候,就被标记为进入环境,而进入环境的变量不能释放,当离开环境的时候就被标记为离开环境
在运行的时候给存在内存中的所有变量加上标记,然后去掉环境中的变量以及被环境中的变量引用的变量的标记,再次被加上标记的会被认为是要删除的变量,最后开始销毁标记的值清除内存
2.引用计数就是跟踪记录每个值被引用的次数,当用到的时候加1,当变为0的时候删除,当不为0且不使用的时候会造成内存泄漏
call、apply、bind 区别?如何实现⼀个bind?
这三个都是用来改变函数的this指向,都可以进行传参,call是参数列表,apply是数组,bind也是参数列表但是可以多次传入,而且它们的第一个参数都是要指向的对象,如果没有参数或者参数是undefined或null,则指向全局window
call和apply的函数是直接执行的,而bind则是返回一个函数然后在想用的时候调用执行
实现bind:1、首先创建一个函数,这个函数需要有原函数的prototype的值 2、然后将this指向这个函数 3、然后合并参数、4、最后返回这个函数
高阶函数
-
函数可以作为参数被传递;
-
函数可以作为返回值输出。
递归
递归就是函数直接或者间接调用自身的一种方法,来解决比较复杂的函数逻辑
优点: 1. 解决重复执行任务 2. 处理不定层级数据
缺点: 1. 时间 空间的消耗较大 2. 重复计算 3. 栈溢出
使用场景:树形菜单,递归组件,快速排序等
forin和forof区别
-
for-in适合遍历对象属性,for-of适合遍历数组
-
for-in循环出的是key值,for-of循环出的是value
-
for-in可以遍历可枚举的属性,for-of遍历的是可迭代的
-
for-of不能直接遍历普通的对象,需要通过Object.keys()搭配使用
src和href的区别
href标识超文本引用,用在link和a等元素上,href是引用和页面关联
src表示引用资源,表示替换当前元素,用在img,script,iframe上
js常用事件绑定方法
1.在DOM元素中直接绑定
2.在DOM元素中直接绑定
3.绑定事件监听函数
map和foreach区别
forEach()方法不会返回执行结果,而是undefined。也就是说,forEach()会修改原来的数组。而map()方法会得到一个新的数组并返回。
如何判断两个对象相等
js提供了一个方法JSON.stringify
,可以将Object和Array转换成JSON字符串
事件冒泡、事件代理、事件捕获
事件冒泡:
在一个对象上触发某类事件,这个事件会向这个对象的的父级传播,从里到外,直至它被处理或者到达了对象层次的最顶层,即document对象。这个过程就是JavaScript的事件冒泡。
事件代理:
“事件代理”即是把原本需要绑定在子元素的响应事件委托给父元素,让父元素担当事件监听的职务。
事件捕获:
当一个事件触发后,从Window对象触发,不断经过下级节点,直到目标节点。在事件到达目标节点之前的过程就是捕获阶段。所有经过的节点,都会触发对应的事件
es5
1.ES5的严格模式 ‘use strict’
2.JSON.parse、JSON.stringify
3.新增Object
接口
4.新增Array
接口
es6
说一下es6新增的特性有那些?
\1. 新增了变量声明方式,也就是let和const > 2. 新增了解构赋值 > 3. 新增了一个数组方法 字符串方法 正则表达的方法 函数的一些写法 对象的方法 > 4. promise > 5. async await > 6. class 以及 继承 > 7. 模块化 > 8. 新的数据类型
原型与原型链
每个函数都有一个prototype属性,被称为显示原型
每个实例对象都会有_ _proto_ _
属性,其被称为隐式原型
每一个实例对象的隐式原型_ _proto_ _
属性指向自身构造函数的显式原型prototype
每个prototype原型都有一个constructor属性,指向它关联的构造函数。
原型链
获取对象属性时,如果对象本身没有这个属性,那就会去他的原型__proto__
上去找,如果还查不到,就去找原型的原型,一直找到最顶层(Object.prototype
)为止。Object.prototype对象也有proto属性,值为null。
let const var
1.var声明的变量存在变量提升,let和const不存在变量提升,变量提升
2.let和const存在暂时性死区,(暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。)
3.var允许重复声明变量。
let和const在同一作用域不允许重复声明变量
4.var是函数作用域,let和const是块级作用域,块级作用域就是只要有大括号就会形成块级作用域
5.const声明的是常量,不能修改
set map Javascript如何实现继承?
在es5中的继承方式有原型链继承,构造函数继承,还可以两者混和继承
-
原型链继承就是让子类函数通过prototype继承父类构造函数的属性和方法,
-
构造函数就是通过.call()或.apply()把父类构造函数引入子类函数并且自执行,就继承了父类
-
混和继承也就是原型链和构造函数的混合,结合了两种继承的有点,传参和复用,
优点是继承了父类原型上的属性,可以传参可以复用,每个实例引入的构造函数属性都是私有的
缺点是耗内存,因为调用了两次父类构造函数,子类的构造函数会代替原型上的那个父类构造函数
es6继承
es6提供了类的这个概念,在es5中是没有类的这个概念,如果想在es5中实现一个类型,我们只能构造函数的方式去创建一个类,而es6给我们提供一个更方便 的方.法,那就是class,这个class理解为是构造函数的语法糖. > > 我们创建一个类只需要用过关键词class去声明就可以了 , 他的调用方式和构造函数的调用方式是一样的 > > 通过es6的类还给我们提供一个extends这样的一个关键字,来实现继承
你是怎么理解ES6中 Promise的?使⽤场景?
首先promise是es6提供一种异步解决方案. 通过promise能够解决回调地狱问题. 所谓的这个回调地狱指的当我们执行完一个操作之后在接受着操作的结果只能通过回调函数的方式进行接受,使用回调函数的方式存在的弊端就是写法非常臃肿,并且后期难以维护,所谓es6给我提供了一种新的解决方案,就是promise来进行解决,promise可以通过链式调用的方式来解决层层嵌套的问题,但是写法上也不是非常好,所以我们最终的替代方案是使用async和await
promise是一种解决异步的方案,把回调函数的嵌套改成链式调用,避免了回调地狱
它有三种状态,pending(进行中)、fulfilled(已成功)、rejected(已失败),
promise实例的api有then()、catch()、finally()
then方法是状态改变为成功时的回调函数,返回的是一个新的promise实例,也是promise能链式书写的原因
catch方法是状态改变为失败时的回调,
finally⽅法是不管 Promise 对象最后什么状态,都会执⾏的操作
如果要使用promise,我们需要对promise进行实例化,在实例化的构造函数里面有一个回调函数,这个回调函数里面有那个参数,分别是resolve和reject,我们可以通过promise的实例化对象调用.then或者.catch方式接受结果
它的缺点是无法取消,而且内部的错误不会反应到外面,在pending状态的时候,会不知道进行到了哪里
promise的缺点,
1.请求一旦开始就无法取消,
只要不调用返回结果中的resolve和reject,那么返回结果中的promise就是传入的promise。而当我们调用了返回结果中的resolve或者reject,那么传入的promise在也不会生效了,由此达到来取消它的目的
2.无法进度追踪
Promise与async、awite的区别
1.async函数的返回值是Promise对象,可以用then方法指定下一步的操作。 async函数可以看做多个异步操作,包装成一个Promise对象,await命令就是内部then命令的语法糖。 2.async函数返回一个Promise对象,可以使用then方法添加回调函数。 当函数执行的时候,一旦遇到await就会先返回,等到异步操作完成,再接着执行函数体后面的语句。
准确来说asyns-await是基于promise的, promise可以理解为一个对象,而asyns- await可以当做一种方法,两者都是让异步代 码看起来像是同步代码,两者的区别在于返 回的结果,让代码看起来更加整洁
ajax 和 axios 区别
axios:是通过promise实现对ajax技术的一种封装,就像jQuery实现ajax封装一样。 简单来说: ajax技术实现了网页的局部数据刷新,axios实现了对ajax的封装。
模板字符串
1.模板字符串中,所有的空格、换行或缩进都会被保留在输出之中。
2.输出 ` 和 \ 等特殊字符
3.只要最终可以得出一个值的就可以通过 ${} 注入到模板字符串中。
解构赋值class类
解构赋值:解构赋值就是从目标对象或数组中提取自己想要的变量。最常用的场景是:element-ui,vant-ui按需引入,请求接口返回数据,提取想要的数据。
class类
在ES6中,class (类)作为对象的模板被引入,可以通过 class 关键字定义类。 class 的本质是 function。 它可以看作一个语法糖,让对象原型的写法更加清晰、更像面向对象编程的语法。 基础用法 类定义 可以作为类表达式以匿名或命名。 类声明 注要意要点: 不可重复声明。类定义不会被提升,这意味着,必须在访问前对类进行定义,否则就会报错。 类中方法前后不能加function 关键字 全部定义在class的protopyte属性中。 方法间不能加分号。 ES5中的类 ES5中如果要生成一个对象实例,需要先定义一个构造函数,然后通过new操作符来完成。
构造函数生成实例的执行过程:
2.将构造函数的作用域给新对象,(即new Object()创建出的对象),而函数体内的this就代表new Object()出来的对象。 3.执行构造函数的代码。 4.返回新对象(后台直接返回);
ES6中的类
注意项:
1.在类中声明方法的时候,千万不要给该方法加上function关键字 2.方法之间不要用逗号分隔,否则会报错**
ES5中的继承 (组合继承:原型链继承 + 借用构造函数) 原型链继承: 父类的示例作为子类的原型
组合继承: 既能调用父类实例属性,又能调用父类原型属性
ES6中的 class继承 父类(基类) 子类 extends 关键字
块级作用域
全局作用域和函数作用域
块作用域由 { } 包括,if语句和for语句里面的{ }也属于块作用域。
暂时性死区
暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。
模块化
简单地说,模块化就是有组织地把一个大文件拆成独立并互相依赖的多个小模块。
好处
1.高内聚低耦合,有利于团队作战
2.可重用,方便维护
3.通过 exports 暴露接口。
4、通过 require 引入依赖
闭包
Symbol
Symbol 值通过Symbol函数生成。它是es6新增加的一种数据类型,生成的变量的特点是值是唯一的,可以用来作为对象的key值使用。
Symbol函数可以接受一个字符串作为参数,表示对 Symbol 实例的描述
如果 Symbol 的参数是一个对象,就会调用该对象的toString方法,将其转为字符串,
Symbol 值可以显式转为字符串,Symbol 值也可以转为布尔值,但是不能转为数值
ts
-
10个数据类型
boolean、number、string、array、tuple(元组)、enum(枚举)、any、void、null、undefined
-
interface和type
-
断言
-
联合类型和泛型
dom
-
创建dom 删除dom 更新 修改
-
所有的标签都有onload和onerror事件
-
箭头dom被修改的事件 onMutation
-
事件的绑定与解绑
-
事件冒泡与捕获
事件冒泡:浏览器默认行为,事件下向上开始传播
-
默认事件行为
dom和bom的区别
BOM是浏览器对象模型,DOM是文档对象模型,前者是对浏览器本身进行操作,而后者是对浏览器内容进行操作
dom对象
document
dom属性
添加属性 获取属性
dom事件
js事件绑定的方式有三种:
-
在DOM元素中直接绑定事件 比如onclick
-
在Script代码中先获取节点然后绑定事件
-
用 addEventListener() 来绑定事件监听函数
dom冒泡/默认行为
事件循环(Event Loop)
因为js是一个单线程,异步io语言。单线程意味着堵塞,为了解决堵塞问题,js把任务分成了同步和异步任务,它们会分别进入不同的执行“场所”,同步进入主线程,异步进入任务队列。主线程内的任务执行完毕为空,就去任务队列读取对应的函数,进入主线程执行。只要主线程空了,就会读取任务列队,前面的过程会不断重复,也就是常说的Event Loop(事件循环)。
但是,JS异步还有一个机制,就是遇到宏任务,先执行宏任务,将宏任务放入宏任务队列,然后再执行微任务,将微任务放入微任务队列,但是,这两个队列不是一个队列。当你往外拿的时候先从微任务队列里拿这个回调函数,然后再从宏任务的队列里拿宏任务的回调函数。
也就是咱们看代码执行顺序的时候是 :主线程(同步任务) > 微任务(promise,async,await) > 宏任务(定时器,ajax,事件等)
常见的微任务有 .then回调,async 和 await 也是异步 会让后面的代码进入微任务当中 ;
宏任务有定时器、网络请求。
事件代理
原理是:找到事件元素的父级元素,然后给父元素定义事件监听子元素的冒泡事件,然后使用event.target(事件源)来定位触发事件冒泡的子元素
优点是减少内存消耗,动态的绑定事件,提高性能;
缺点是有一些局限性
bom
window对象,整个的浏览器宿主对象
滚动条
历史记录
window.history
窗口的大小监听事件
window.onresize
消息弹窗
alert
框架
vue
0.vue的生命周期
beforeCreate() 创建前,这个时候data中的数据,还未定义,所以不能使用 created()创建后 最早开始使用 data和methods中数据的钩子函数
beforeMount()挂载前 指令已经解析完毕内存中已经生成dom树,但是尚未挂载到页面中去,此时页面还是旧的。 mounted()挂载后 dom已经渲染完毕,此时页面和内存中都是最新的数据,最早可以操作DOM元素钩子函数
beforeUpdate()更新前** 当视图层的数据发生改变会执行这个钩子 内存更新,但是DOM节点还未更新,数据没有与页面同步 updated()更新后 数据更新完成以后触发的方法,DOM节点已经更新
beforeDestroy()即将销毁 data和methods中的数据此时还是可以使用的,可以做一些释放内存的操作 destroyed()销毁完毕 组件已经全部销毁,Vue实例已经被销毁,Vue中的任何数据都不可用
其他三个: activated 被 keep-alive 缓存的组件激活时调用。 deactivated 被 keep-alive 缓存的组件停用时调用。 errorCaptured 2.5.0+ 新增当捕获一个来自子孙组件的错误时被调用
Vue3.0中的生命周期做了一些改动:
beforeCreate -> setup() 开始创建组件之前,创建的是data和method
created -> setup()
beforeMount -> onBeforeMount 组件挂载到节点上之前执行的函数。
mounted -> onMounted 组件挂载完成后执行的函数
beforeUpdate -> onBeforeUpdate 组件更新之前执行的函数。
updated -> onUpdated 组件更新完成之后执行的函数。
beforeDestroy -> onBeforeUnmount 组件挂载到节点上之前执行的函数。
destroyed -> onUnmounted 组件卸载之前执行的函数。
vue created钩子函数不能获取到dom元素,可以在mounted里面进行获取dom元素的操作
1.Vue项⽬中有封装过axios吗?主要是封装哪⽅⾯的?
axios是什么:axios 是一个轻量级的HTTP客户端,基于XMLHttpRequest来执行HTTP请求,也就是ajax的封装,它有很多特性,比如:从浏览器中创建XMLHttpRequest,从node.js中创建http请求,支持Promise APi,拦截请求和响应,转换请求数据和响应数据,能取消请求,自动转换json数据
如何封装:在封装的时候需要先和后端商量好,因为有些配置需要后端,比如说:设置接口请求前缀就利用node环境变量来判断,还要在config.js中配置代理跨域;;再比如说设置请求头和超时时间,大多数时候请求头是固定的,如果用到特殊的请求头,就进行传参覆盖;还有封装请求方法,将封装好的方法在要调用的接口重新封装成一个方法暴露出去还有就是请求拦截器和响应拦截器
axios的常用方法有get、post、delete、put
在vue项目中,和后台交互获取数据这块,我们通常使用的是axios库,它是基于promise的http库,可运行在浏览器端和node.js中。他有很多优秀的特性,例如拦截请求和响应、取消请求、转换json
2.vue双向绑定原理v.2,v.3
在vue2中
是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter在数据变动时发布消息给订阅者,触发相应的监听回调来渲染视图,实现数据和视图同步。
在vue3 中
Vue3是通过Object.define.proxy 对对象进行代理,从而实现数据劫持。使用Proxy 的好处是它可以完美的监听到任何方式的数据改变,唯一的缺点是兼容性的问题,因为 Proxy 是 ES6 的语法
3.vue组件之间的通信方式(组件通讯)
1.props/$emit:
这个一般用于父子组件之间的通信,父组件通过props
的方式向子组件传递数据,子组件可以通过$emit
的方式向父组件进行通信。
2.$parent/$Children
通过$parent
和$children
就可以访问到对应组件的实例
3.ref
如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例
4.provide/inject
provide/ inject 是vue2.2.0新增的api, 简单来说就是父组件中通过provide来提供变量, 然后再子组件中通过inject来注入变量。并且不论子组件嵌套有多深, 只要调用了inject 那么就可以注入provide中的数据
5.eventBus
使用$on
订阅事件,$emit
发布事件
6.$attrs/$listeners
解决跨级组件使用props与emit来通信的话
引入了$attrs
和$listeners
, 新增了inheritAttrs
选项
7.vuex
8.localStorage/sessionStorage
使用localStorage/sessionStorage也能够进行通信,缺点就是不易维护
localStorage: localStorage 的生命周期是永久的,关闭页面或浏览器之后 localStorage 中的数据也不会消失
sessionStorage: sessionStorage 的生命周期是仅在当前会话下有效,在关闭了浏览器窗口后就会被销毁
cookie: cookie生命期为只在设置的cookie过期时间之前一直有效,存放数据大小为4K左右
vue常见指令
v-if
:是动态的向DOM树中添加或者删除元素;
v-else
是搭配v-if使用的,它必须紧跟在v-if或者v-else-if后面,否则不起作用
v-show
:是通过标签的CSS样式display的值是不是none,控制显示隐藏
v-for
: v-for是根据遍历数据来进行渲染,要配合key使用。
v-on`:用来绑定一个事件或者方法,简写方式是`@click=""
v-bind
:v-bind用来动态的绑定一个或者多个属性。
v-model
只能适用于在表单元素上,可以实现数据双向绑定 ,
4、vue中如何解决跨域?
协议、域名、端口都相同才同域(同源协议),否则都是跨域
而解决跨域的方法有三种:jsonp、cors、proxy
-
本地跨域是通过在vue.config.js文件里面的devServer属性里面的proxy属性里面配置,一共配置三个属性,分别是代理名称 代理地址 开启跨域 重写路径
-
Jsonp,实现原理主要是利用动态创建 script 标签,设置src属性,
3.cors,它使用额外的 HTTP 头来告诉浏览器让运行在一个origin 上的Web应用被准许访问来自不同源服务器上的指定的资源。
5、vue中用过哪些修饰符?这两个什么 意思 .sync .lazy
.prevent:阻止默认行为
.stop:阻止冒泡
.once:事件只触发一次
.capture:在捕获阶段触
.self:事件作用在元素本身触发
.native:自定义组件中使用,告诉Vue当前触发的是js的原生事件
.number 把用户输入的内容,自动转换为数字
.trim 过滤输入内容左右空格。
lazy在我们在表单中填完信息,光标离开标签的时候,才会将值赋予给value
,也就是在change
事件之后再进行信息同步
sync能对props
进行一个双向绑定,子组件传递的事件名格式必须为update:value
,其中value
必须与子组件中props
中声明的名称完全一致, 不能和v-bind一起使用
6、created 和 mounted的应用场景?
-
created:通常用于初始化某些属性值,例如data中的数据,然后再渲染成视图。
-
mounted:通常在初始化页面完成后,对html的dom节点进行需要的操作。
7、vue3
1、响应系统的变动 由原来的Object.defineProperty 的getter 和 setter,改变成为了 Proxy 作为观察机制。 Proxy的优势:消除了以前存在的警告,使速度加倍,并节省了一半的内存开销。 2、虚拟DOM重写 虚拟 DOM 从头开始重写,减少运行时开销。重写将包括更有效的代码来创建虚拟节点。 3、组件渲染的优化 Vue2当中在父组件渲染同时,子组件也会渲染。 Vue3就可以单独渲染父组件、子组件。 4、静态树提升 使用静态树提升,这意味着 Vue 3 的编译器将能够检测到什么是静态组件,然后将其提升,从而降低了渲染成本。
8、vue项目中,接手别人代码的,如何去分析?
-
首先对于Vue Cli搭建的项目,知道项目的目录结构
-
查看 package.json 配置文件,了解项目引用了哪些额外插件和框架
-
查看 router 文件,可以快速梳理项目脉络
-
查看 vuex 文件(如果项目使用了 vuex,那vuex在其中一定扮演着非常重要的角色 ,时不时一些数据就是从vuex中取得的),通过这点可以大概明白整体项目的数据流向;除此之外通过vue devtool查看vuex也是个方法
-
一定要看的main.js入口文件,其中vue.use()和import 引入的文件都对梳理项目架构很重要
-
还有src目录下的components组件
9、mixin
Mixin
是面向对象程序设计语言中的类,提供了方法的实现。其他类可以访问mixin
类的方法而不必成为其子类
Mixin
类通常作为功能模块使用,在需要该功能时“混入”,有利于代码复用又避免了多继承的复杂
Mixins:可以定义共用的变量,在每个组件中使用,引入组件中之后,各个变量是相互独立的,修改值在组件中不会相互影响。
与公共组件的区别
组件:在父组件中引入组件,相当于在父组件中给出一片独立的空间供子组件使用,然后根据props来传值,但本质上两者是相对独立的。
Mixins:则是在引入组件之后与组件中的对象和方法进行合并,相当于扩展了父组件的对象与方法,可以理解为形成了一个新的组件。
10、为什么data是一个函数?
如果不是一个函数,每个组件实例的data都是同一个引用数据,当该组件作为公共组件共享使用,一个地方的data更改,所有的data一起改变,如果data是一个函数,每个实例的data都在闭包中,就不会各自影响了。
闭包
闭包就是用来让外部函数访问内部函数作用域中的变量。闭包就是函数嵌套函数,函数内部return出里面的局部变量
优点是可以隔离作用域,不造成全局污染,缺点是因为闭包的特性会使闭包长期占用内存,导致内存泄漏,解决这个问题的方法就是将暴露出来的闭包变量设为null
一般用在封装组件,或者是for循环和定时器一起使用,也可以用在防抖节流中
内存泄漏
常见的内存泄漏有闭包,死循环,意外的全局变量或者是this,还有定时器也会造成内存泄漏
说起内存泄漏就得说一下垃圾回收机制,垃圾回收机制就是定期的找出不再使用的变量进行释放,而javascript就具有自动垃圾回收机制,有两种实现方式,1、标记清除;2、引用清除
1、标记清除是最常用的垃圾回收机制,当一个变量进入环境的时候,就被标记为进入环境,而进入环境的变量不能释放,当离开环境的时候就被标记为离开环境
在运行的时候给存在内存中的所有变量加上标记,然后去掉环境中的变量以及被环境中的变量引用的变量的标记,再次被加上标记的会被认为是要删除的变量,最后开始销毁标记的值清除内存
2.引用计数就是跟踪记录每个值被引用的次数,当用到的时候加1,当变为0的时候删除,当不为0且不使用的时候会造成内存泄漏
防抖和节流
防抖(throttle)和节流(debounce)的本质是优化高频率执行代码的一种手段,比如说scroll、mousemove这类事件在触发时,会不断的调用绑定在事件上的回调函数,非常浪费资源而且降低性能,所以使用防抖和节流进行一种限制。
防抖就是在n秒后再执行事件,如果n秒内重新触发,就重新计时,
节流就是在n秒内只运行一次,如果n秒内重新触发,也只运行一次
实现方式:防抖用定时器实现,节流用时间戳或者是定时器
使用场景:防抖:表单搜索,手机号邮箱验证,window触发一些方法的时候
节流:拖拽事件,监听滚动
-
axios
官方提供了cancelToken
的方式来拦截请求,大型复杂项目可以采用这种方式
11、动态给vue的data添加⼀个新的属性时会发⽣什么?怎样解决
vue开发中动态给data添加一个新的属性会遇到数据更新,但是页面没有更新的情况。
因为,由于vue2
是用Object.defineProperty
实现数据响应式
当我们设置a
值的时候都能够触发setter
与getter,
但是我们为obj
添加新属性的时候,却无法触发。
*原因是一开始obj
的a
属性被设成了响应式数据,而后面新增的属性,并没有通过Object.defineProperty
设置成响应式数据**
-
Vue.set()
通过Vue.set向响应式对象中添加一个property,并确保这个新 property同样是响应式的,且触发视图更新
-
Object.assign()
创建一个新的对象, 使用Object.assign()合并原对象和混入对象的属性
-
$forcecUpdated()
$forceUpdate强制更新,可以让Vue 实例重新渲染
13、什么是虚拟DOM?如何实现⼀个虚拟DOM?
虚拟dom是用js对象来描述真实的dom,在这个js对象里,体现了这个真实dom节点的节点名称,属性名称以及子元素等内容
我们在渲染页面的时候会对新的虚拟dom和旧的虚拟dom进行对比只渲染不同的地方,而不再是像之前只要发生变化,全部的真实dom都要重新渲染,所以提高了渲染的效率
diff算法
-
用js对象来表示真实的DOM树结构,创建一个虚拟DOM对象
-
当数据发生改变的时候,创建一个新的js的虚拟DOM对象
-
比较新旧对象的差异,记录下来,最终更新到真实的DOM树结构上。
14、你有写过⾃定义指令吗?⾃定义指令的应⽤场景有哪些?
全局: vue.directive:{"",{}} 局部:directives:{指令名:{钩子函数}} bind(){} 只调用一次,指令第一次绑定到元素时调用 inserted(){} 被绑定元素插入父节点时调用 update(){} 被绑定元素所在的模板更新时调用,而不论绑定值是否变化 componentUpdated(){} 被绑定元素所在模板完成一次更新周期时调用 unbind(){}只调用一次, 指令与元素解绑时调用
钩子函数参数有
el
:指令所绑定的元素,可以用来直接操作 DOM。
binding
:一个对象,包含property:
除了 el
之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建议通过元素的dataset 来进行
应⽤场景有:
防抖
图⽚懒加载
⼀键 Copy的功能
15、Vue中的过滤器了解吗?过滤器的应⽤场景有哪些?
过滤器主要用来对数据进行格式的修改
过滤器分为 全局过滤器
和 局部过滤器
。
全局过滤器:全局过滤器在任何一个组件中可以直接使用
局部过滤器:只能在注册了的组件中使用。
过滤器默认第一个参数就是需要过滤的内容
{{ msg | filterA }}单个使用。
{{ msg | filterA| filterB }}多个连用
在什么地方会用到过滤器?
比如在后台取出来的时间戳可以用过滤器过滤成为准确时间
可以在购物车的价格或者单价中使用给价格加上‘¥’
16、SPA⾸屏加载速度慢的怎么解决?
-
什么是⾸屏加载
⾸屏时间(First Contentful Paint),指的是浏览器从响应⽤户输⼊⽹址地址,到⾸屏内容渲染完成的时间,此时整个⽹⻚不⼀定要全部渲染完成,但需要展示当前视窗需要的内容,⾸屏加载可以说是⽤户体验中最重要的环节
-
加载慢的原因
在⻚⾯渲染的过程,导致加载速度慢的因素可能如下:
⽹络延时问题
资源⽂件体积是否过⼤
资源是否重复发送请求去加载了
加载脚本的时候,渲染内容堵塞了
-
解决⽅案
常⻅的⼏种SPA⾸屏优化⽅式
减⼩⼊⼝⽂件体积
静态资源本地缓存
UI框架按需加载
图⽚资源的压缩
组件重复打包
开启GZip压缩
使⽤SSR
17、 v-if和v-for的优先级是什么?
当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级,这意味着 v-if 将分别重复运行于每个 v-for 循环中。所以,不推荐v-if和v-for同时使用。 如果v-if和v-for一起用的话,vue中的的会自动提示v-if应该放到外层去
18、说说你对keep-alive的理解是什么?
keep-alive是Vue提供给我们一个内置组件, 作用:保存我们路由切换时组件的状态 , 比如列表页面进入详情,我们想保存列表滚动的位置,我们就可以使用keep-alive保存列表页面的滚动位置。
组件使用keep-alive以后会新增两个生命周期 actived() deactived(),该钩子在服务器端渲染期间不被调用。
有三个参数
include - 包裹的组件名会被缓存
exclude 包裹的组件名都不会被缓存
max定义缓存组件上限,超出上限使用LRU的策略置换缓存数据。
19、你知道vue中key的原理吗?说说你对它的理解?
用来区分和识别一个元素是否有改变的,有了这个 key 时在后续的排序、修改等更新操作时性能更快。
如果没有设置 key 的时候,会认为比较的两个节点为同一个节点,会导致频繁的更新不同的元素,导致了频繁的 DOM 操作
20、请描述下你对vue⽣命周期的理解?
1.创建 beforeCreate() 创建前的阶段,这个时候data中的数据还未定义,所以不能使用 created() 最早开始使用 data和methods中数据的钩子函数 2.挂载 beforeMount() 指令已经解析完毕,内存中已经生成dom树,还没有渲染到本地 mounted() dom已经渲染完毕,最早可以操作DOM元素的钩子函数 3.更新 beforeUpdate() 当data的数据发生改变会执行这个钩子 内存更新,但是DOM节点还未更新 updated() 数据更新完成以后触发的方法,DOM节点已经更新 4.销毁 beforeDestroy() 即将销毁 data和methods中的数据此时还是可以使用的,可以做一些释放内存的操作 destroyed() 已经销毁完毕
5.使用keep-alive后
activated
deactivated
6.子组件错误
errorCaptured 子组件有错误的调用
21、Vue中的$nextTick有什么作⽤?
Vue的数据更新是采用延迟异步更新
的,就是说当我们修改了数据之后,vue响应式的改变一个值以后,此时的dom并不会立即更新,如果需要在数据改变以后立即通过dom做一些操作,可以使用$nextTick获得更新后的dom 。
和$set的区别, $nextTick是dom加载完毕之后执行的,$set是直接赋值给数组的
22、vue要做权限管理该怎么做?如果控制到按钮级别的权限怎么做?
1.多个用户可以隶属于一个角色,一个角色可以拥有多个权限,每个用户登陆进来看到的左侧权限但是不一样的,对应的左侧的菜单也是不一样的因为数据的格式就是三层
//按钮权限实现思路:1.不同用户进来,后台会返回一个按钮权限列表 2.在前端写自定义指令,在指令函数里获取按钮权限列表跟页面传入的那个是否匹配,如果匹配不上就不显示该按钮(通过display,none把当前节点隐藏删除掉)。这样当达到了更细一级的按钮控制
23、v-show和v-if有什么区别?使⽤场景分别是什么?
共同:v-if 和 v-show 都是控制一个元素是否显示。
区别:v-if 如果是 false 就不渲染这个元素,页面中没有这个元素
v-show 无论 true 和 false 都会渲染这个元素,页面中始终有这个元素,
v-if 与 v-show 都能控制 dom 元素在⻚⾯的显示
v-if 相⽐ v-show 开销更⼤的(直接操作 dom 节点增加与删除)
如果需要⾮常频繁地切换,则使⽤ v-show 较好
如果在运⾏时条件很少改变,则使⽤ v-if 较好
24、 说⼀下watch和computed的区别?
1、computed是计算属性;watch是监听,监听data中的数据变化。 2、computed支持缓存,return,当其依赖的属性的值发生变化时,计算属性会重新计算,反之,则使用缓存中的属性值;watch不支持缓存,当对应属性发生变化的时候,响应执行。 3、computed不支持异步,有异步操作时无法监听数据变化;watch支持异步操作。 4、computed第一次加载时就监听;watch默认第一次加载时不监听。
11.http 与 https区别?
http的默认端口80 https默认端口443 https加密证书
methods不处理数据逻辑关系,只提供可调⽤的函数
methods 是没有缓存的,只要调用,就会执行,一般结合事件来使用
监听的属性:
immediate:开启立即监听
handler:需要具体执行的方法
deep:开启深度监听
什么是监听器?
在 Vue 中使用 watch
属性来定义一个监听器函数,当依赖的数据发生变化时触发函数
watch 没有缓存性,监听data中的属性,属性值只要发生变化就会执行,可以利用他的特性做一些异步的操作
监听器的主要用途:当依赖改变函数时,一个函数重点在干一件事,这件事通常比较复杂,比如:当搜索条件改变时,重新调用后端接口等
什么是计算属性?
在 Vue 中使用 computed
来定义计算属性,每个计算属性就是一个函数,这个函数需要有一个返回值。
computed 具有缓存性,依赖于属性值,只有属性发生改变的时候才会重新调用
计算属性主要用途:得到一个经过计算的数据
并且当依赖的数据改变时重新计算,重点在于得到数据
插槽
\1. 默认插槽就是把父组件中的数据,显示在子组件中,子组件通过一个slot插槽标签显示父组件中的数据
\2. 具名插槽是在父组件中通过slot属性,给插槽命名,在子组件中通过slot标签,根据定义好的名字填充到对应的位置。
\3. 作用域插槽是带数据的插槽,子组件提供给父组件的参数,父组件根据子组件传过来的插槽数据来进行不同的展现和填充内容。在标签中通过v-slot来接受数据。
25、说说你对vuex的理解?
全局状态管理系统,是用来存储数据的一个仓库,用于多个组件共用一个数据
使用:
1:新建了一个目录store.js
2:在main.js引入store.js,并注入到vue实例中。
场景有:
单页应用中,组件之间的状态。音乐播放、登录状态、加入购物车
vuex五大核心概念
1、state 所有的数据都存储在state中, state是一个对象 2、mutations(谬忒神死) 可以直接操作state中的数据 3、actions(艾克神死) 只能调用mutations的方法 4、getters(改嘚死) 类似计算属性实现对state中的数据做一些逻辑性的操作 5、modules (毛都死)将仓库分模块存储
Vuex 页面刷新数据丢失怎么解决?
需要做 vuex 数据持久化,一般使用本地储存的方案来保存数据,可以“自己设计存储方案,也可以使用第三方插件。 推荐使用 vuex-persist (脯肉赛斯特)插件,它是为 Vuex 持久化储存而生的一个插件。不需要你手动存取 storage,而是直接将状态保存至 cookie 或者 localStorage中。
vuex的工作流程
通过diapatch 调用action,
在action中可以执行异步或者同步操作,然后通过commit调用mutation,让mutation去修改state
26、webpack的打包流程或者运行机制
webpack打包流程:
1.首先通过配置的entry入口,找到入口文件main.js
2.通过配置的各种loader(css-loader配合正则找所有css样式文件,file-loader配合正则找图片文件转成base64,vue-loader找所有.vue文件 )统一打包成.css的和.js的chunk文件
3.通过插件(html-webpack-plugin插件)把这种chunk文件(打包生成的文件)自动嵌入到index.html里
27、$set是干嘛用的?
vue在创建实例的时候把data深度遍历所有属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。让 Vue 追踪依赖,在属性被访问和修改时通知变化。所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。
当你在对象上新加了一个属性newProperty,当前新加的这个属性并没有加入vue检测数据更新的机制(因为是在初始化之后添加的),vue.$set是能让vue知道你添加了属性, 它会给你做处理。
28、mvvm和mvc的区别
mvc:不能影响响应式更新、单项数据流
model:表示模型
view:表示视图
Controller:表示的是控制器
MVVM:数据双向绑定,响应式更新。
mvc 中 Controller演变成 mvvm 中的 viewModel,
mvvm 通过数据来显示视图层而不是节点操作。
mvvm主要解决了: mvc中大量的DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。
MVVM 是把 MVC 的 Controller 和 MVP 的 Presenter 改成了 ViewModel 。View 的变化会自动更新到 ViewModel , ViewModel 的变化也会自动同步到 View 上显示。这种自动同步是因为 ViewModel 中的属性实现了 Observer ,当属性变更时都能触发对应的操作。
ssr
通过服务端的渲染,把每一个路由组件渲染成页面
29、vue路由有几种,路由原理及区别(路由模式)
hash:使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载,其显示的网路路径中会有 “#” 号,有一点点丑。这是最安全的模式,因为他兼容所有的浏览器和服务器。 history:history模式 使用了HTML5中的pushstate和replicestate这两个来实现的,pushstate可以改变URL地址且不会发送请求,replicestate可以读取历史记录,还可以对浏览器进行修改,同时不会像hash有一个#,更加的美观。 abstract:适用于所有JavaScript环境,例如服务器端使用Node.js。如果没有浏览器API,路由器将自动被强制进入此模式。
区别:
hash,你只能改变#后面的url片段,改变地址之后不会刷新
history模式则会将URL修改得就和正常请求后端的URL一样
路由跳转方式:
-
router-link
-
this.$router.push()
-
this.$router.replace()
-
this.$router.go()
路由传参:
三种:
分别是query,params,动态路由传参
接收:
通过query方式传递过来的参数一般是通过this.$route.query接收
通过params方式传递过来的参数一般是通过this.$route.params接收
通过动态路由传参方式传递过来的参数一般是通过this.$route.params接收
query使用path和name传参跳转都可以,而params只能使用name传参跳转。
传参跳转页面时,query不需要再路由上配参数就能在新的页面获取到参数,params也可以不用配,但是params不在路由配参数的话,当用户刷新当前页面的时候,参数就会消失。
也就是说使用params不在路由配参数跳转,只有第一次进入页面参数有效,刷新页面参数就会消失。
路由守卫:
2.路由守卫使用的方式有几种? 全局的 单个路由独享的 组件级的
3.vue-router全局有三个守卫:
router.beforeEach 全局前置守卫 进入路由之前
router.beforeResolve 全局解析守卫(2.5.0+) 在beforeRouteEnter调用之后调用 router.afterEach 全局后置钩子 进入路由之后
组件内的守卫:
beforeRouteEnter
beforeRouteUpdata(2.2新增)
beforeRouteLeave
-
路由守卫钩子函数里面的三个参数分别是什么?
to,from,next 这三个参数:
to和from是将要进入和将要离开的路由对象,路由对象指的是平时通过this.$route获取到的路由对象。
next:Function 这个参数是个函数,且必须调用,否则不能进入路由(页面空白)。
next() 进入该路由。
next(false): 取消进入路由,url地址重置为from路由地址(也就是将要离开的路由地址)。 next 跳转新路由,当前的导航被中断,重新开始一个新的导航。
30、父子生命周期执行顺序
父子组件的加载顺序为 父beforeCreated ->父created ->父beforeMounted ->子beforeCreated ->子created ->子beforeMounted ->子mounted -> 父mounte
子组件更新顺序为 父beforeUpdate->子beforeUpdate->子updated->父updated
父子组件销毁顺序为 父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
31、单向数据流的理解
父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解
单向数据流的使用场景
多个组件会共享状态时,共享状态和组件间(兄弟组件)通信变的不容易。我们把共享状态抽取出来,用单向数据流的方式会变得容易
一、当url输入到页面发生了什么
大致过程是:
浏览器的地址栏输入URL并按下回车,
查找当前的URL是否存在缓存,并比较缓存是否过期,
DNS解析URL对应的IP,
根据IP建立TCP连接(三次握手),
HTTP发起请求,服务器处理请求,浏览器接收HTTP响应,
渲染页面,构建DOM树,
关闭TCP连接(四次挥手)。
三次握手:
第一次:建立连接时,客户端发送syn包到服务器,等待服务端确认
第二次:服务器收到syn包,必须确认客户的syn,同时也发送一个syn包,即syn+ACK包
第三次:客户端收到服务器的syn和ack包,向服务器发送确认包ack,发送完毕,客户端和服务端连接成功,完成三次握手
四次挥手:
第一次:浏览器发送完数据后,发送fin请求断开连接
第二次:服务器发送ack到客户端,确认客户端的断开请求
第三次:服务器请求断开fin的请求
第四次:客户端确认服务器的断开ack
33、vue和jquery有什么区别
vue相当于是mvvm框架的一种,它实现了数据的双向绑定
jquery是mvc框架的一种模式,获取视图的话是单项数据绑定,获取玩数据的话还得去找对象再去更新DOM,更多的是DOM的操作
34、vue的优缺点
既然现在流行vue他的优点肯定大于他的缺点,
优点是双向数据绑定
性能好
简单易用
前后端分离
单页面应用用户体验好
缺点是单页面,单页面也有解决方法,单页面他不合适多页面,不适合做内容网站,比如知乎,CSDN内容更新的,需要搜索引擎支持优化的,他实现起来优点麻烦,当然也有解决方法通过nice.jss服务端的渲染大概了解但是没有上手过,看过这种文章
35、vue的两个核心点
数据驱动
数据驱动视图让我们脱离需要手动改变DOM来使得视图更新
组件化开发
封装组件很方便,一个页面可以多个模块使用
36、动态路由如何实现?
1.在全局路由守卫中,先判断token值有没有。有的话先看是否存储过,如果存储过直接,页面调用渲染,如果没有,就请求接口,把路由表存储下 。除非没有token,跳转登录页面 2.路由表里-把那些常规路由(不需要权限的路由,事先都写到路由表里)。把需要权限的路由通过router.addRoute()动态填加到对应的子路由里 。3.动态填加的路由需要处理下。因为后端传给你的是树状结构,前端需要把树结构处理成列表结构(通过递归,不断的获取路径,名字那些信息),填加到路由表里。
37、query和params的区别
params传值的参数是路由的一部分,所以跳转必须加参数值才能跳转
query传参和路由配置没有关系获取方式是不一样的 query this.$route.query.参数名 params是 this.$route.params.参数名
区别:简单说query相当于get请求,页面跳转的时候,可以在地址栏看到请求参数,浏览器刷新页面不会消失,而params相当于post请求,参数不会在地址栏中显示,浏览器刷新页面后消失。
query传参是拼接在url后的,如果传的值是对象类型的则数据会丢失,如果传的值是字符串则不会丢失。
路由传参能传对象吗
在路由跳转传参的时候参数可能会是一个对象,但首次跳转成功接受成功后这个参数会出现,但是一旦刷新这个参数就会变成 [object,object] 。可以在路由跳转传递参数的时候用 JSON.stringify() 将参数转换为字符串,在接受这个参数的时候用 JSON.parse() 进行转换
38. Vue2和vue3的区别?
-
Vue2采用的时选项Api,vue3采用了组合Api
-
双向数据绑定vue2使用object.definpropty, vue3使用了proxy 对数据进行了代理
-
Vue2中template需要跟标签包裹,vue3中不需要,
-
生命周期发生了一些变化
39、常见的Vue性能优化有哪些?
-
响应式数据对象层级不要过深,非响应式数据不要放在data里面或者使用
Object.freeze()
冻结数据 -
合理使用v-if 和 v-show ,v-if适用于切换不频繁的场景,v-show适用于切换频繁的场景
-
computed 和 watch 区分使用场景,能使用computed实现的就不用watch(computed具有缓存效果)
-
v-for 遍历必须加 key,key 最好是 id 值,并且避免同时使用 v-if
-
大数据列表和表格性能优化-虚拟列表/虚拟表格
-
防止内部泄漏,组件销毁后还应该把全局变量和事件销毁
-
图片懒加载
-
路由懒加载
-
第三方插件的按需引入
-
适当采用 keep-alive 缓存组件
-
防抖、节流运用
-
服务端渲染 SSR 或者 预渲染
隐式转换
有时我们遇到当运算符在运算时,如果两边数据类型不统一,CPU无法计算,这是编译器会自动将运算符两边的数据做一个数据类型转换,转换成一样的数据类型在进行运算,这种无需程序员手动转换,而由编译器自动转换的方式就称为隐式转换。
watch和watchEffet的区别
相同点:他们都可以监听多个值
不同点:watchEffect不需要写监听,只能得到修改后的数据,不能拿到旧数据
工厂模式
可以理解为构造函数,可以通过new来调用,每调用一次都会创建一个实例对象,工厂函数中的this指向你new出来的新对象,改变其中一个不会影响到其他new出来的对象
重绘和重排
重排比重绘大
重绘不一定导致重排,但重排一定会导致重绘。
重排也叫回流,简单的说就是重新生成布局,重新排列元素。
使用场景: 1.添加删除dom 2.改变元素位置 3.改变浏览器窗口位置
重绘 当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程
重排的代价是高昂的,会破坏用户体验,并且让UI展示非常迟缓
sass的常用api
render () 和 renderSync () render () 函数是将 Sass 文件异步编译为 CSS ,并在渲染完成时调用传入的回调函数,
w3c规范
万维网联盟
万维网联盟标准不是某一个标准,而是一些列标准的集合。网页主要有三部分组成:结构(Structure)、表现(Presentation)、行为(Behavior)。
jq对象和原生dom对象区别
dom对象是我们用原生js获得的对象,jQuery对象就是用jQuery的类库选择器获得的对象。jQuery对象和原生对象不可混用
链式调用
链式调用,或者也可以称为方法链(Method Chaining),从字面意思上来说就是将一些列的操作或函数方法像链子一样穿起来的 Code 方式。
网络协议
-
场景的状态码
200:请求成功,浏览器会把响应体内容(通常是html)显示在浏览器中;
404:(客户端问题)请求的资源没有找到
400: 语义有误,当前请求无法被服务器理解。
401: 当前请求需要用户验证
403: 服务器已经理解请求,但是拒绝执行它。
500:(服务端问题)请求资源找到了,但服务器内部发生了不可预期的错误;
301/302/303:(网站搬家了,跳转)重定向
逻辑
-
前端性能优化
模式
-
单例模式
-
工厂模式
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。它提供了一种创建对象的最佳方式。 在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
-
发布订阅
浏览器兼容问题
Css**兼容性问题:**
1.不同浏览器的标签默认的**margin和**padding不同
解决办法:可以通过设置全局样式来解决这个问题
2.图片默认有间距
解决办法:可以通过使用float
属性为img
布局
http与https的区别
1、https比http更安全
2、HTTP和HTTPS使用的是完全不同的连接方式,用的端口也不一样。前者是80,后者是443。
http缓存机制
缓存分为两种:强缓存和协商缓存
1.强缓存:不会向服务器发送请求,直接从缓存中读取资源,
2.协商缓存:向服务器发送请求,服务器会根据这个请求的request header的一些参数来判断是否命中协商缓存,
共同点:都是从客户端缓存中读取资源; 区别是强缓存不会发请求,协商缓存会发请求。
SEO
搜索引擎优化。利用搜索引擎的规则提高网站在有关搜索引擎内的自然排名
算法
-
冒泡排序
Nginx
他是反向代理软件,把端口号自动找到,不同的端口号找到不同的网站进行分发
nginx是反向代理软件,它可以监听不同端口ip地址指向服务器里不同目录,达到同一个ip地址不同端口号访问不同网站目的。
区别:jsonp是线上处理跨域,cors后台处理,proxy线下处理,nginx服务器处理跨域
webpack脚手架有几种环境
开发环境(development)、测试环境(staging)、正式环境(production)
开发中的问题
-
token
一般的后端接口设置的token是有时效的,超时后就会失效,失效之后的处理策略,一般会做两种处理,一种是直接跳转到登录页面,重新登录。另外一种如果返回 token失效的信息,自动去刷新token,然后继续完成未完成的请求操作。
-
打包发布白屏
如果发布到线上的网址包含了二级以上目录,本地的项目配置文件需要在publicPath手动添加二级的地址,然后在重新打包
-
css动画页面闪白,动画卡顿
1.尽可能地使用合成属性transform和opacity来设计CSS3动画,不使用position的left和top来定位
2.开启硬件加速
H5新增特性和css3新增特性?
H5新增特性:
-
新增语义化标签: header,nav,article footer,section,aside。
-
在表单⽅⾯,为了增强表单,为 input 增加了 color,email,data ,range,number 等类型。
-
localStorage 没有时间限制的数据存储; sessionStorage, session 的数据存储,当用户关闭浏览器窗口后,数据会被删除
-
在多媒体⽅⾯规定了⾳频和视频元素 audio 和 video。
-
html5 新增的表单属性:
required:是一个 boolean 属性。要求填写的输入域不能为空
pattern:描述了一个正则表达式用于验证 input 元素的值
min 和 max:设置元素最小值与最大值
autofocus:是一个 boolean 属性。规定在页面加载时,域自动地获得焦点
-
html5 新事件:
onresize:当调整窗口大小时触发
ondrag:当拖动元素时触发
onscroll:当滚动元素滚动元素的滚动条时触发
onmousewheel:当转动鼠标滚轮时触发
onerror:当错误发生时触发
onplay:当媒介数据将要开始播放时触发
onpause:当媒介数据暂停时触发
css3新增特性:
1.选择器:
常规选择器::last-child /* 选择元素最后一个孩子 */ :first-child /* 选择元素第一个孩子 */ :nth-child(1) /* 按照第几个孩子给它设置样式 */ :nth-child(even) /* 按照偶数 */ :nth-child(odd) /* 按照奇数 */ :disabled /* 选择每个禁用的dom元素 */ :checked /* 选择每个被选中的dom元素 */ :not(selector) /* 选择非 selector 元素的每个元素 */ ::selection /* 选择被用户选取的元素部分 */
伪类和伪元素:
伪类:用于向某些选择器添加特殊的效果(没有创建新元素)
:last-child /* 选择元素最后一个孩子 */ :first-child /* 选择元素第一个孩子 */ :nth-child(1) /* 按照第几个孩子给它设置样式 */ a:link {color: #FF0000} /* 未访问的链接 */ a:visited {color: #00FF00} /* 已访问的链接 */ a:hover {color: #FF00FF} /* 鼠标移动到链接上 */ a:active {color: #0000FF} /* 选定的链接 */
伪元素:创建了 html 中不存在的元素,用于将特殊的效果添加到某些选择器
::before {} /* 选择器在被选元素的前面插入内容和定义css,使用 content 属性来指定要插入的内容。 */ ::after {} /* 选择器在被选元素的后面插入内容和定义css,使用 content 属性来指定要插入的内容。 */ :first-letter /* 选择该元素内容的首字母 */ :first-line /* 选择该元素内容的首行 */ ::selection /* 选择被用户选取的元素部分 */
-
背景:
background-size:规定背景图片的尺寸(cover:填充;100% 100%:拉伸) background-origin:规定背景图片的定位区域 对于 background-origin 属性,有如下属性 背景图片可以放置于 content-box、padding-box 或 border-box 区域
边框:
border-radius:圆角 box-shadow / text-shadow:阴影 border-image:边框图片
3.文本效果
text-shadow:向文本添加阴影
text-justify:规定当 text-align 设置为 “justify” 时所使用的对齐方法
text-emphasis:向元素的文本应用重点标记以及重点标记的前景色
text-outline:规定文本的轮廓
text-overflow:规定当文本溢出包含元素时发生的事情
text-wrap:规定文本的换行规则
word-break:规定非中日韩文本的换行规则
word-wrap:允许对长的不可分割的单词进行分割并换行到下一行
text-decoration:文本修饰符:overline、line-through、underline 分别是上划线、中划线、下划线
-
渐变,CSS3新增了渐变效果,包括 linear-gradient(线性渐变)和 radial-gradient(径向渐变)
node.js
node.js:Node.js 不是一门新的编程语言,也不是一个 JavaScript 框架,它是一套 JavaScript 运行环境,用来支持 JavaScript 代码的执行。 前后端编程环境统一,可以大大降低开发成本
NodeJs超强的高并发能力
Node.js是一个用于开发各种web服务器的开发工具
webpack
Webpack是一个前端打包和构建工具
小程序
微信小程序生命周期
应用生命周期:
onLaunch用户首次打开小程序。小程序初始化完成时(全局只触发一次); onShow 监听小程序显示。小程序启动,或从后台进入前台显示时 onHide监听小程序隐藏。小程序从前台进入后台时。 onError错误监听函数,小程序发生脚本错误,或者API调用失败时触发,会带上错误信息 onPageNotFound 页面不存在监听函数,小程序要打开的页面不存在时触发,会带上页面信息回调该函数
页面生命周期:
onLoad 页面加载 onReady 页面初次渲染完成,一个页面只会调用一次。 onShow 显示页面 onHide 页面隐藏 onUnload页面卸载
小程序登录流程
1.wx.login获取code码
2.调用后端接口,使用code码来获取openid(微信用户的唯一id)sessioKey,并且存入本地
3.判断用户是否授权登录
4.获取用户的微信账号信息
5.使用openid请求后端接口得到token值,把token存入本地,用于后续的请求做校验
支付流程
1.pc支付,扫码支付,后端返回也是一个字符串的url地址。前端使用qrcode生成二维码,当二维码生成完毕后,开启一个轮询请求状态奇接口,问后端用户是否支付,如果支付成功或跳转失败跳到对应的页面
2.手机的h5支付,请求支付接口后,后端返回一个url连接,使用window.location.herf=url,页面跳转到支付宝或微信支付页面即可,回执页面(跳回来的页面,是在第三方支付程序中定义好的)
3.小程序支付
微信小程序中的支付,使用订单id调用wx.requestPayment方法,还自动的唤起微信内置的支付页面
小程序运行机制
-
热启动
:假如用户已经打开了某个小程序,在一定时间内再次打开小程序的话,这个时候我们就不再需要重新启动了,这需要把我们的后台打开的小程序切换到前台来使用。 -
冷启动
:用户首次打开小程序或被微信主动销毁再次打开的情况,此时小程序需要重新加载启动。如何封装小程序请求
-
封装
wx.request
请求传递需要的参数(url
,data
,method
,success 成功回调
,fail 失败回调
) , 封装常用方法POST
,GET
,DELETE
,PUT
.... 最后导出这些方法 -
然后新建一个
api.js
文件,导入封装好的方法,然后调取相应的方法,传递数据。app.json
全局配置文件描述-
pages
: 用于存放当前小程序的所有页面路径 -
window
: 小程序所有页面的顶部背景颜色,文字颜色配置。 -
tabBar
: 小程序底部的Tab
,最多5个,最少2个。
简述下
wx.navigateTo()
,wx.redirectTo()
,wx.switchTab()
,wx.navigateBack()
,wx.reLaunch()
区别-
wx.navigateTo()
: 保留当前页面,跳转到应用内的某个页面。但是不能跳到tabbar
页面 -
wx.redirectTo()
: 关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到tabbar
页面 -
wx.switchTab()
: 跳转到TabBar
页面,并关闭其他所有非tabBar
页面 -
wx.navigateBack()
: 关闭当前页面,返回上一页面或多级页面。可通过getCurrentPages()
获取当前的页面栈,决定需要返回几层 -
wx.reLaunch()
: 关闭所有页面,打开到应用的某个页面。
小程序有哪些传递数据的方法
1. 使用全局变量
-
在
app.js
中的this.globalData = { }
中放入要存储的数据。 -
在
组件.js
中, 头部 引入const app = getApp();
获取到全局变量 -
直接使用
app.globalData.key
来进行赋值和获取值。
2. 使用 路由
-
wx.navigateTo
和wx.redirectTo
时,可以通过在url
后 拼接 + 变量, 然后在目标页面
通过在onLoad
周期中,通过参数来获取传递过来的值。
小程序怎么实现下拉刷新
-
通过在
app.json
中, 将"enablePullDownRefresh": true,
开启全局下拉刷新。 -
或者通过在
组件 .json
, 将"enablePullDownRefresh": true,
单组件下拉刷新。
小程序
WXSS
与CSS
的区别WXSS
-
wxss
背景图片只能引入外链,不能使用本地图片 -
小程序样式使用
@import
引入 外联样式文件,地址为相对路径。 -
尺寸单位为
rpx
,rpx
是响应式像素,可以根据屏幕宽度进行自适应。
小程序怎么跟随事件传值
在 页面标签上通过 绑定
dataset-key = value
, 然后绑定点击通过e.currentTarget.dataset.key
来获取标签上绑定的值。小程序关联微信公众号如何确定用户的唯一性?
使用wx.getUserInfo方法 withCredentials为true时,可获取encryptedData,里面有union_id.后端需要进行对称解密。
url参数过长
eventChannel (e文特切喔)新增页面间通信接口,用于监听被打开页面发送到当前页面的数据
-
-
git操作
git操作命令
-
git init
初始化git仓库 (mac中Command+Shift+. 可以显示隐藏文件) -
git status
查看文件状态 -
git add ``文件列表
追踪文件 -
git commit -m ``提交信息
向仓库中提交代码 -
git log
查看提交记录
回退任意版本信息
git reset --hard 35851ba - 35851ba 索引值
reset 命令的三个参数 :
--soft 仅仅在本地库移动 HEAD 指针
--mixed 在本地库移动head 指针 重置暂存区
--hard 在本地库移动head 指针 重置暂存区 重置工作存区
回退上一版本
git reset --hard HEAD^ - 回退到上一个版本
git 团对开发
-
访问远程代码托管中心(这里用的是gitee)
-
在代码托管中心创建远程仓库(项目经理)
-
创建本地仓库(项目经理)
-
将本地仓库与远程仓库连接(项目经理)
-
将远程仓库克隆到本地(团队开发成员)
-
将本地仓库代码推送到远程仓库(团队开发成员)
-
合并代码(项目经理)
解决冲突
导致冲突原因:两位开发者在同一个文件内修改同一行代码并且提交时产生冲突。
解决方法: 1.直接在编辑器打开文件修改,删除多余的符号 或者 2.直接在命令行输入vim demo.txt 按i 进入编辑模式 删除多余的符号
怎么创建新分支
1.首先进入本地git仓库目录下,打开git bash 环境
2.使用git branch命令可以查看到,当前目录下只有一个master分支 $ git branch
3.使用git branch 分支名称创建分支,创建完成后通过git branch可以看到本地已经多出了一个新建的分支
前端热门题
1.vue中data发生变化,视图不更新如何解决?
因为Vue实例中的数据是响应式的,而我们新增的属性并不是响应式的,由于受现在JavaScript的限制,Vue无法检测到属性的新增或删除。所以有时无法实时的更新到视图上。 所以我在项目中遇到这类问题的时候一般是通过this.$set方法去解决. this.$$set方法一共有三个参数,分别是目前属性,新增属性,新增的值.
2.简单说下vue中的$nextTick的作用?
当修改data不能马上获去修改后得值,这个时候需要调用$nextTick回调,让修改后的data更新到dom元素中才能获取到
3.如何对app内的h5页面做性能优化?你有哪些不同的思考角度
1.减少js加载体积,能用cdn尽量使用cdn
2,。尽量使用较轻量级的ui组件库
3.图片压缩
4.减少网络请求次数
5.尽量把大的js文件分割成小的js文件
6.lazyload懒加载
7.减少使用定位属性
8.尽量不使用闭包、定时器,必要时一定要清空
4.项目中不用vuex,有什么其他替代方案吗?
浏览器缓存:sessionStorage/localStorage
mixin混入
provide/inject提供与注入
pinia
5.vue中data为什么要return一个对象
举个例子,写个点击加一的组件,然后调用三次,如果data是个对象,那么点击其中任何一个组件,其他两个也会跟这加一,如果
data是个函数则不会出现这种问题
6.vue的顶层原理有多少了解
7.vue如何获取dom
先给标签设置一个ref值,在通过this.$refs.domName获取,这个操作要在mounted阶段进行
8.jq和vue区别其他开源框架,有什么优势
vue的核心概念是绑定,内存字段对应Dom节点
jq的核心概念就是短(减少api长度和获取dom次数),jq算库不算框架
react核心概念是渲染,