Vue前端面试题

Vue前端面试题

前言:带*都是重点

Vue相关

一、 *vue双向数据绑定

采用数据劫持结合观察-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter。

在数据变动时发布消息给订阅者,触发相应的监听回调来渲染视图,实现数据和视图同步。

vue2源码

1.模版引擎 正则 替换muastache里面的内容渲染成dom

2.数据响应式原理 Vue 会把普通对象变成响应式对象,响应式对象 getter 相关的逻辑就是做依赖收集

3.虚拟dom 由h函数产生

4.diff算法 只比较同一层级,不跨层比较
tag不同,直接删除重建,不再深度比较
tag和key,两者都相同,则认为是相同节点,不再深度比较

具体步骤:

模版引擎 数据响应式 虚拟dom diff算法

  1. 需要Observer(观察者)(数据监听器)对数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter。给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化,通知Watcher(订阅者)
  2. Compile(模板解析器)解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
  3. Watcher(订阅者)是Observer和Compile之间通信的中介,主要做的事情是:
    1. 在自身实例化时往属性订阅器(dep)里面添加自己
    2. 自身必须有一个update()方法、
    3. 待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调
  4. MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果
简述MVVM和MVC

(1)MVC:是后台的框架模式
分为M:(model模型)、V(view视图)、C(controller控制器)
(2)MVVM是为了实现MVC中的V
MVVM分为:M(model数据)、V(view视图)、VM(viewModel控制数据的改变和控制试图)

Vue的响应式系统

响应式系统简述:

  • 任何一个Vue Component都有一个与之对应的Watcher实例

  • Vue的data上的属性会被添加getter和setter

  • 当Vue Component render函数被执行的时候,data上会被touch,即被读,getter方法会被调用,此时 Vue 会去记录此 Vue component 所依赖的所有 data。(这一过程被称为依赖收集)

  • data 被改动时(主要是用户操作), 即被写, setter 方法会被调用, 此时 Vue 会去通知所有依赖于此

    data 的组件去调用他们的 render 函数进行更新

二、 *vue虚拟dom,diff算法

想要理解虚拟dom首先要知道什么是虚拟dom?

通过js创建一个Object对象(AST节点树)来模拟真实DOM结构,这个对象包含标签名 (tag)、属性 (attrs) 和子元素对象 (children) 三个属性,通过vue中的render()函数把虚拟dom编译成真实dom,在通过appendChild()添加到页面中。
虚拟dom可以简单的用一句话概括,就是用普通的js对象来描述DOM结构,因为不是真实DOM,所以称之为虚拟DOM。
为什么要用虚拟DOM来描述真实的DOM呢?
创建真实DOM成本比较高,如果用 js对象来描述一个dom节点,成本比较低,另外我们在频繁操作dom是一种比较大的开销。所以建议用虚拟dom来描述真实dom。

Diff算法

diff的过程就是调用名为patch的函数,比较新旧节点,一边比较一边给真实的DOM打补丁
• 比较只会在同层级进行, 不会跨层级比较
• 在diff比较的过程中,循环从两边向中间比较

Diff算法的步骤:

用 JavaScript 对象结构表示 DOM 树的结构;然后用这个树构建一个真正的 DOM 树,插到文档当中。
当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较(diff),记录两棵树差异
把第二棵树所记录的差异应用到第一棵树所构建的真正的DOM树上(patch),视图就更新了

5.既然Vue通过数据劫持可以精准探测数据变化,为什么还需要虚拟DOM进行diff检测差异?

考点: Vue 的变化侦测原理

前置知识: 依赖收集、虚拟 DOM、响应式系统

现代前端框架有两种方式侦测变化,一种是pull,一种是push

  • pull: 其代表为React,我们可以回忆一下React是如何侦测到变化的,我们通常会用setStateAPI显式更

新,然后React会进行一层层的Virtual Dom Diff操作找出差异,然后Patch到DOM上,React从一开始就

不知道到底是哪发生了变化,只是知道「有变化了」,然后再进行比较暴力的Diff操作查找「哪发生变

化了」,另外一个代表就是Angular的脏检查操作。

  • push: Vue的响应式系统则是push的代表,当Vue程序初始化的时候就会对数据data进行依赖的收集,

一但数据发生变化,响应式系统就会立刻得知。因此Vue是一开始就知道是「在哪发生变化了」,但是这

又会产生一个问题,如果你熟悉Vue的响应式系统就知道,通常一个绑定一个数据就需要一个Watcher,

一但我们的绑定细粒度过高就会产生大量的Watcher,这会带来内存以及依赖追踪的开销,

而细粒度过低会无法精准侦测变化,因此Vue的设计是选择中等细粒度的方案,在组件级别进行push侦测的

方式,也就是那套响应式系统,通常我们会第一时间侦测到发生变化的组件,然后在组件内部进行Virtual

Dom Diff获取更加具体的差异,而Virtual Dom Diff则是pull操作,Vue是push+pull结合的方式进行变

化侦测的。

三、 *Vue 组件间通信有哪些方式?

1.父传子:
1.在父组件的子组件标签上绑定一个属性,挂载要传输的变量。在子组件中通过props来接受数据,props可以是数组也可以是对象,接受的数据可以直接使用props
2.父组件调用子组件的方法通过ref在DOM元素上使用 r e f s 可 以 迅 速 进 行 d o m 定 位 , 使 用 t h i s . refs可以迅速进行dom定位,使用this. refsdom使this.refs.paramsName能更快的获取操作子组件属性值或函数

2.子传父:
vue2.0只允许单向数据传递,我们通过触发自定义事件来改变组件的数据
在父组件的子组件标签上通过绑定自定义事件,接受子组件传递过来的事件。子组件通过$emit触发父组件上的自定义事件,发送参数(第一个是要改变的属性值,第二个是要发送的参数)

3.兄弟组件传值:
通过main.js初始化一个全局的 b u s , 在 发 送 事 件 的 一 方 通 过 b u s . b u s . b u s . e m i t ( “ 事 件 名 ” , 传 递 的 参 数 信 息 ) 发 送 , 在 接 收 事 件 的 一 方 通 过 bus,在发送事件的一方通过b u s . bus.bus.emit(“事件名”,传递的参数信息)发送,在接收事件的一方通过 bus,bus.bus.bus.emit()bus. o n ( “ 事 件 名 ” , 参 数 ) 接 收 传 递 的 事 件 B u s . on(“事件名”,参数)接收传递的事件 Bus. on(,)Bus.on(“事件名”)

四、 *Vuex

1.vuex :是一个专为vue.js开发的状态管理工具,采用集中式存储的所有组件状态,通过vuex我们可以解决组件之间数据共享的问题,后期也方便我们管理以及维护
有五个属性分别是: state、getters、mutations、actions、module
state属性: 存放状态,例如你要存放的数据
getters:类似于共享属性,可以通过this. s t o r e . g e t t e r s 来 获 取 存 放 在 s t a t e 里 面 的 数 据 m u t a t i o n s : 唯 一 能 改 变 s t a t e 的 状 态 就 是 通 过 提 交 m u t a t i o n s 来 改 变 , t h i s . store.getters来获取存放在state里面的数据 mutations:唯一能改变state的状态就是通过提交mutations来改变,this. store.gettersstatemutationsstatemutationsthis.store.commit()
actions: 异步的mutations,可以通过dispatch来分发从而改变state
modules:模块化管理store(仓库),每个模块拥有自己的 state、mutation、action、getters

2.基本使用:我通过是在根目录下新建一个store文件夹,里面创建一个index.js文件,最后在main.js中引入,并挂载到实例上,之后那个组件中需要用到vuex就调用就行
3.高级用法-数据持久化
vuex里面存放的数据,页面一经刷新会丢失:
解决办法: 存放在localStorage或者sessionStorage里面,进入页面时判断是否丢失,丢失再去localStorage或者sessionStorage里面取;
在vuex中可以通过安装vuex-persistedstate [pərˈsɪstɪd steɪt] 插件,进行持久化的配置就行
4.高级用法-辅助函数(语法糖)

有4个辅助函数(
mapState,mapActions,mapMutations,mapGetters
辅助函数可以把vuex中的数据和方法映射到vue组件中。达到简化操作的目的
如何使用:
Import { mapActions, mapGetters, mapMutations, mapState } from ‘vuex’

Pinia

五、 *自定义指令,自定义过滤器

vue中的自定义指令:
vue中除了核心功能内置的指令外,也允许注册自定义指令。自定义指令又分为全局的自定义指令和局部自定义指令。
全局自定义指令是通过Vue.directive(‘第一个参数是指令的名称’,{第二个参数是一个对象,这个对象上有钩子函数})

 Vue.directive('focus', {
		// el:指令所绑定的元素,可以用来直接操作 DOM。
		//binding:一个对象,包含以下 property:
      inserted: function (el) { vNode参数
        el.focus();
      }
    });

局部自定义指令:
是定义在组件内部的,只能在当前组件中使用

directives: {
        // 指令名称
        dir1: {
            inserted(el) { // inserted 表示被绑定元素插入父节点时调用
                // 指令中第一个参数是当前使用指令的DOM
                console.log(el);
                console.log(arguments);
                // 对DOM进行操作
                el.style.width = '200px';
                el.style.height = '200px';
                el.style.background = '#000';
            }
        },
        color: { // 为元素设置指定的字体颜色
          bind(el, binding) {
            el.style.color = binding.value;
          }
        }
	}

自定义指令的钩子函数:
一个指令定义对象可以提供如下几个钩子函数 (均为可选):
inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
bind:只调用一次,指令第一次绑定到元素时调用。
update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前
componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
unbind:只调用一次,指令与元素解绑时调用。

钩子函数中的参数有:
el指令所绑定的元素,可以用来直接操作 DOM
binding:一个对象,里面有以下参数:
name:指令名,不包括 v- 前缀。
value:指令的绑定值,例如:v-my-directive=“1 + 1” 中,绑定值为 2。

使用场景:input输入框自动聚焦使用自定义指令 v-focus,在script中使用directives注册v-focus指令 自定义指令图片懒加载

vue中自定义过滤器
• 过滤器是对即将显示的数据做进一步的筛选处理,然后显示,过滤器并没有改变原来的数据,只是在原数据的基础上产生新的数据
• 过滤器分为全局过滤器和局部过滤器
全局过滤器
全局过滤器是通过Vue.filter()来定义的,定义好后,它在所有组件中都可以使用。第一个是过滤器名称 第一个参数是需要过滤的值 第二个参数是给过滤器传递的值

// global-filter是过滤器名称
// 函数第一个参数是需要过滤的数据.
// 函数第二个参数是给过滤器传递的值.
  Vue.filter('global-filter',(val,...args)=>{
    console.log(`需要过滤的数据是:${val}`)
    return val + ' 过滤器追加的数据'
  })

局部过滤器
局部过滤器,定义在组件内部 filters 属性上.它只能在此组件内部使用.
过滤器的使用方式是,在双花括号或v-bind中通过一个管道符 ‘|’ 来拼接,
过滤器在vue3中被移除了 功能需要使用 计算属性代替

局部过滤器
局部过滤器,定义在组件内部 filters 属性上.它只能在此组件内部使用.
过滤器的使用方式是,在双花括号或v-bind中通过一个管道符 ‘|’ 来拼接,
过滤器在vue3中被移除了 功能需要使用计算属性代替

六、 *vue-router(路由原理?路由守卫?传参)

r o u t e 和 route和 routerouter区别

router是VueRouter的实例,使用$ router.push方法导航。返回上一个历史history用$router.to(-1)
$route为当前router跳转对象。里面可以获取当前路由的name,path,query,parmas等。

路由原理

通过改变 URL,在不重新请求页面的情况下,更新页面视图。
路由分为History模式和Hash模式

History模式 前端的URL必须和实际向后端发起请求的URL一致 如果后端缺少对路由处理,将返回404错误
Hash模式在浏览器中符号的“#”,以及#后面的字符称之为hash hash虽然出现在URL中,但不会被包括在HTTP请求中,对后端完全没有影响,因此改变hash不会重新加载页面。
window.hashchange监听hash值的改变,

history模式监听路径的改变

路由传参:

三种:分别是query,params,动态路由传参
接收:
通过query方式传递过来的参数一般是通过this.route.query接 收

通过params方式传递过来的参数一般是通过this.route.params接收 需要指定目标路由的name属性

路由规则开启props传参,路由组件接收并使用路由参数 props可以是箭头函数 对象 数组

通过动态路由 /user/:id 传参方式传递过来的参数一般是通过this.$route.params接收
Router-link路由传参 URL后面传参,通过斜线进行传参

路由导航守卫:
路由守卫使用的方式有几种? 全局的 单个路由独享的 组件级的
vue-router全局有三个守卫:

router.beforeEach 全局前置守卫 进入路由之前 场景:动态路由权限添加
router.beforeResolve 全局解析守卫(2.5.0+) 在beforeRouteEnter调用之后调用

router.afterEach 全局后置钩子 进入路由之后 没有next

组件内的守卫:

进组组件前的守卫 beforeRouteEnter 没有办法获取this,当前组件没有创建
路由更新时的守卫 beforeRouteUpdata(2.2新增)
离开组件时的守卫 beforeRouteLeave

路由守卫钩子函数里面的三个参数分别是什么?

to,from,next 这三个参数:
to和from是将要进入和将要离开的路由对象,路由对象指的是平时通过this.$route获取到的路由对象。
next:Function 这个参数是个函数,且必须调用,否则不能进入路由(页面空白)。
next() 进入该路由。
next(false): 取消进入路由,url地址重置为from路由地址(也就是将要离开的路由地址)。 next 跳转新路由,当前的导航被中断,重新开始一个新的导航。

路由跳转方式 一共四种方式

router-link (不带参数)
this. r o u t e r . p u s h ( ) ( 函 数 里 面 调 用 ) t h i s . router.push() (函数里面调用) this. router.push()()this.router.replace() (用法同push)
this.$router.go(n)go返回几级页面(正数是往前跳转页面,负数是往后跳转页面)
引入项目,在项目里面怎么使用(后台管理,token,白名单)

6.1、什么是nextTick

在下次DOM更新循环结束后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的DOM。使用场景是:可以在created钩子函数中拿到dom节点
无法获取的原因:
vue的reader渲染函数是异步的,例如将变量修改,数据改变引起虚拟dom对比,如果立刻获取真实dom,无法获取,因为数据改变引起虚拟dom对比,立即获取真实dom是undefined,可以使用定时器、 n e x t T i c k 使 用 场 景 : 假 如 定 义 一 个 变 量 开 关 , 修 改 开 关 变 量 让 按 钮 和 输 入 框 来 回 切 换 , 切 换 到 i n p u t 直 接 获 取 d o m 为 其 绑 定 自 动 聚 焦 , 是 不 可 以 获 取 d o m 的 , 因 为 数 据 的 变 化 引 起 了 虚 拟 d o m 对 比 , 立 即 获 取 真 实 d o m 是 u n d e f i n e d , 可 以 使 用 定 时 器 、 nextTick 使用场景: 假如定义一个变量开关,修改开关变量让按钮和输入框来回切换,切换到input直接获取dom为其绑定自动聚焦,是不可以获取dom的,因为数据的变化引起了虚拟dom对比,立即获取真实dom是undefined,可以使用定时器、 nextTick使inputdomdomdomdomundefined使nextTick
给ele-input绑定自定义指令v-focus,不起作用,因为ele-input被封装了,el-input绑定原生事件要加.native

6.2、vue修改数据页面不重新渲染

如果为对象添加少量的新属性,可以直接采用Vue.set()
如果需要为新对象添加大量的新属性,则通过创建新对象的方式Object.assign()
如果你需要进行强制刷新时,可采取$forceUpdate() (不建议)

方案一:利用 this.set(this.obj,key,val) target:要修改的对象或数组
例:this.set(this.obj,‘k1’,‘v1’)

方案二:就利用 Object.assign({},this.obj)创建新对象 (额 晒恩)
如果是数组就 Object.assign([],this.obj)
如果是对象就 Object.assign({},this.obj)。

添加到对象的新属性不会触发更新
应创建一个新的对象,合并原对象和混入对象的属性

$forceUpdate如果你发现你自己需要在 Vue中做一次强制更新,99.9% 的情况,是你在某个地方做错了事
$forceUpdate迫使Vue 实例重新渲染

七、 *Vue生命周期(几个?每一个生命周期的特点,可以做什么)

生命周期让我们在控制整个vue时更容易形成更好的逻辑,可以分为四个阶段,创建阶段,挂载阶段,更新阶段,销毁阶段
分别有:
创建前:beforeCreate() 数据代理前,只有一些实例本身的事件和生命周期函数,无法通过vm访问data中的数据和methods中的方法
创建后:Created() 是最早使用data和methods中数据的钩子函数
挂载前:beforeMount() 指令已经解析完毕,内存中已经生成dom树 不能对dom进行操作
挂载后:Mounted() dom渲染完毕页面和内存的数据已经同步
更新前:beforeUptate() 当data的数据发生改变会执行这个钩子,内存中的数据是新的,页面是旧的
更新后:Updated() 数据和页面都是新的
销毁前:beforeDestroy() 即将销毁data和methods中的数据此时还是可以使用的,可以做一些释放内存的操作
销毁后:Destroyed() 已经销毁完毕

八、 自定义组件

自定义组件分为全局自定义组件和局部自定义组件,全局组件可以全局使用,可以在所有的页面中调用引入
局部组件仅限当前引入页面
全局自定义组件
写好组件在main文件直接引入,这种是最简单的方式

import myTabItem from ‘@/components/myTabItem/myTabItem.vue’
Vue.component(‘my-tab-item’, myTabItem) // 这种注册组件的方式叫做全局自定义组件html建议短横线分隔不建议驼峰

全局自定义组件是使用 Vue.component(‘组件名’, 组件模板)//组件模板就是引入组件路径定义的名字
局部自定义组件
在一个组件通过配置项 components注册的组件

九、 *常见的指令,事件修饰符,按键修饰符
Vue常用指令

在vue中提供了一些对于页面 + 数据的更为方便的输出,这些操作就叫做指令,指令中封装了一些DOM行为, 结合属性作为一个暗号, 暗号有对应的值,根据不同的值,框架会进行相关DOM操作的绑定
vue中的指令有很多,我们平时做项目常用的有:

v-if:是动态的向DOM树中添加或者删除元素

v-else是搭配v-if使用的,它必须紧跟在v-if或者v-else-if后面,否则不起作用
v-show:是通过标签的CSS样式display的值是不是none,控制显示隐藏
v-if和v-show区别:
v-if更适合数据的筛选和初始渲染 v-show更适合元素频繁的切换

v-for: v-for是根据遍历数据来进行渲染,要配合key使用。要注意的是当v-for和v-if同处于一个节点时,v-for的优先级比v-if更高。这意味着v-if将运行在每个v-for循环中 在Vue3中v-if优先级更高
v-on:用来绑定一个事件或者方法,简写方式是@click=“”
v-bind: v-bind用来动态的绑定一个或者多个属性。没有参数时,可以绑定到一个包含键值的对象。常用于动态绑定class和style。以及href等。简写的方式是“:属性名=“””

v-cloak v-html v-text

v-model 只能适用于在表单元素上,可以实现数据双向绑定 ,

数据双向绑定实现的原理:
是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter在数据变动时,发布消息给订阅者,触发相应的监听回调来渲染视图。
Vue3.0中Proxy并使用Reflect.set,可以实现对整个对象的劫持,可以在用到数据的时候再进行对下一层属性的劫持。Vue2递归对对象数据代理。

自定义组件的 v-model

一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value attribute 用于不同的目的。

model 选项可以用来避免这样的冲突:

Vue.component('base-checkbox', {
  model: {
    prop: 'checked',
    event: 'change'
  },
  props: {
    checked: Boolean
  },
  template: `
    
  `
})

1.将一个值以v-model的形式绑定到base-checkbox组件上,值的名称为checked,类型为Boolean

2.在组件上指定将哪个值用于于父组件绑定(model: { prop: ‘checked’, event: ‘change’ })

3.将checked绑定到了input上面(v-bind:checked=“checked”)

4.监听单选框的值的变化然后触发自定义事件返回给父组件

(v-on:change=“$emit(‘change’, $event.target.checked)”)

5.现在在这个组件上使用 v-model 的时候:

<base-checkbox v-model="lovingVue">base-checkbox>

这里的 lovingVue 的值将会传入这个名为 checked 的 prop。同时当 触发一个 change 事件并附带一个新的值的时候,这个 lovingVue 的 property 将会被更新。

事件修饰符:

• .stop :阻止事件冒泡
• .self :当事件作用在元素本身,触发回调
• .once :只执行一次
• .prevent: 阻止默认事件
• .capture :事件捕获
• ·passive:告诉浏览器你不想阻止事件的默认行为
• ·trim:自动过滤用户输入的首尾空格
语法:@事件名.修饰符=“方法名”0

为什么v-for使用key

key是给每一个vnode的唯一id,也是diff的一种优化策略,可以根据key,更准确, 更快的找到对应的vnode节点
有输入类的dom 进行unshift 头部数据插入删除一般不使用index 作为key

Props验证类型都有哪些(8个)

Number、bollean、string、object、array、function、date、symbol Symbol函数
Props是单线程的传递
prop 数据单项传递,父影响子,子不影响父
不能在组件中直接修改 prop 传递过来的值,Vue 会给出警告
prop 验证时,会在实例创建之前进行验证,所以实例的属性 (如 data、computed 等) 在 default 或 validator 函数中是不可用的
非 prop 特性,组件可以接受任意的特性,而这些特性会被添加到这个组件的根元素上。

  • 混入mixin:可以把多个组件共用的配置提取成一个混入对象 全局混入:Vue.mixin(xxx) 局部混入:mixins:['xxx']
  • 插件:用于增强Vue 包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。 给vue原型添加方法 自定义指令

Vue2和vue3的区别

1.双向数据绑定用原理发生了改变,
  • 使proxy替换Object.defineProerty, 通过 Reflect(反射): 动态对被代理对象的相应属性进行特定的操作
  • 使用Proxy的优势:可直接监听数组类型的数据变化,监听的目标为对象本身,不需要像Object.defineProperty一样遍历每个属性,有一定的性能提升,可直接实现对象属性的新增/删除
  • 再说一下vue2.x中如何监测数组变化
  • 使用了函数劫持的方式,重写了数组的方法,Vue将data中的数组进行了原型链重写,指向了自己定义的数组原型方法。这样当调用数组api时,可以通知依赖更新。如果数组中包含着引用类型,会对数组中的引用类型再次递归遍历进行监控。这样就实现了监测数组变化。
2.Composition Api 选项api变成组合api 有了hooks写法 同时支持render JSX 写法

​ 例如 ref reactive watch computed toRefs toRaws

3.Vue3中 Fragments template里面不需要有唯一的根节点
4.Teleport写的组件挂载到任何你想挂载的DOM上, 场景Dialog

5.Suspense

5.破坏式更新

Vue3中不再支持过滤器filterr

sync修改符已移除, 由v-model代替

vue3: v-if 优先级高于 v-for 因为vue2先循环再判断 耗费性能

6.底层性能优化
  • 默认使用懒加载
  • 在2.x版本里。不管数据多大,都会在一开始就为其创建观察者,在数据很大时,就会造成性能的问题。
  • 在3.x中,只会对渲染出来的数据创建观察者,而且3.x的观察者更高效。
  • 刚开始写vue3 记住 ref响应式和 .value reactive 让数据变成响应式

6.Vue3 Tree shaking
简单来讲,就是在 保持代码运行结果不变的前提下,去除无用的代码

在Vue2中,无论我们使用什么功能,它们最终都会出现在生产代码中。主要原因是Vue实例在项目中是单例的,捆绑程序无法检测到该对象的哪些属性在代码中被使用到

而Vue3源码引入tree shaking特性,将全局 API 进行分块。如果你不使用其某些功能,它们将不会包含在你的基础包中

就是比如你要用watch 就是import {watch} from ‘vue’ 其他的computed 没用到就不会给你打包减少体积

Progressive Web App(PWA)支持

7.重构Virtual DOM

模板编译时的优化,将一些静态节点编译成常量
Slot优化,将slot编译为lazy函数,将slot的渲染的决定权交给子组织

8.生命周期有了一定的区别

Vue2--------------vue3
beforeCreate -> setup() 开始创建组件之前,创建的是data和method
created -> setup()
beforeMount -> onBeforeMount 组件挂载到节点上之前执行的函数。
mounted -> onMounted 组件挂载完成后执行的函数
beforeUpdate -> onBeforeUpdate 组件更新之前执行的函数。
updated -> onUpdated 组件更新完成之后执行的函数。
beforeDestroy -> onBeforeUnmount 组件挂载到节点上之前执行的函数。
destroyed -> onUnmounted 组件卸载之前执行的函数。
activated -> onActivated 组件卸载完成后执行的函数
deactivated -> onDeactivated

9.vue2和vue3的脚手架vite一个最主要的区别:

在vue脚手架在4.5.15的时候,vue3还是会向下兼容vue2的命令,但是vue的脚手架一旦升级成为5.0.1以后vue3就会舍弃掉现有的命令行,不会再向下兼容vue2版本,

但是在创建项目的时候5.0.1版本就会结合vite来创建项目,

vite有一个优点就是创建项目的时候启动的非常快和vue的4.5.15版本不太一样,在vue的4.5.15它会在创建项目的时候把所有的依赖(vuex、vue-router等)全部安装完毕,但是5.0.1版本它是冷启动(什么是冷启动,就是什么依赖都不会去装)你需要哪个就去下载哪个,所以它启动的非常迅速

十一、 Keep-alive

keep-alive 是 Vue 的内置组件,当它包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。

keep-alive 是一个抽象组件:它自身不会渲染成一个 DOM 元素,也不会出现在父组件链中。
在组件切换过程中 把切换出去的组件保留在内存中,防止重复渲染DOM,减少加载时间及性能消耗,提高用户体验性,性能优化 。

  • include - 字符串或正则表达式。只有名称匹配的组件会被缓存。
  • exclude - 字符串或正则表达式。任何名称匹配的组件都不会被缓存。
  • max - 数字。最多可以缓存多少组件实例。

被包含在 keep-alive 中创建的组件,会多出两个生命周期的钩子: activated keep-alive 组件激活时调用与 deactivated keep-alive 组件停用时调用

十二、 多环境变量Docker

在不同环境,需要连接不同的资源:
比如dev环境,可能使用的数据库连接是某个远端的url
到了test环境,数据库连接可能存在一些变化——比如使用内网地址或库名有些变化……

这里希望达到的效果是,通过部署脚本来配置后端资源(数据库、缓存等)
这样各环境可以使用相同的构建物(docker image),从而保证代码一致性
这样在测试环境测试没问题的docker image,可以直接打标签部署到生产环境
毕竟没人能保证每次两次构建是完全一致的。

十三、 对axios封装(url统一管理、axios请求拦截、响应拦截、函数封装)

首先要安装axios,一般我会在项目的src目录中,新建一个utils文件夹,作为我们的网络请求模块,然后在里面新建一个http.js和一个api.js文件和一个reques.js。http.js文件用来封装我们的axios,在http.js里面添加请求拦截器和响应拦截器api.js用来统一管理我们的接口url,

reques.js用来调用封装我们需要使用到的方法在request.js中添加请求拦截和响应拦截。

在请求拦截中,会给请求头添加token字段,还有loading动画的开启。

在响应拦截中,可以做一些loading动画的关闭,还有可以根据后端返回的状态码,做一些检验token是否有效或者过期的操作。

接着就是做一些axios进行的api接口的封装,这里用到了async,await封装请求接口函数,这样可以将异步操作同步化操作,代码更加友好,避免回调地域的出现。

十四、 Slot插槽

插槽就是父组件往子组件中插入一些内容。
有三种方式,默认插槽,具名插槽,作用域插槽

1.默认插槽就是把父组件中的数据,显示在子组件中,子组件通过一个 slot插槽标签 显示父组件中的数据
2.具名插槽是在父组件中通过,改用新写法 v-slot:center # 需要写template标签,给插槽命名,在子组件中通过slot标签,根据定义好的名字填充到对应的位置。
3.作用域插槽是带数据的插槽,子组件提供数据,父组件根据子组件传来的插槽数据来进行不同的展现和填充内容。在标签中通过slot-scope来接受数据。

十六、 为什么data是一个函数

如果不是一个函数,每个组件实例的data都是同一个引用数据,当该组件作为公共组件共享使用,一个地方的data更改,所有的data一起改变,如果data是一个函数,每个实例的data都在闭包中,就不会各自影响了。
data可以是对象也可以是函数,不会产生数据污染情况,函数有一个独立的作用域,函数内部的变量只能内部的函数去访问从而形成一个闭包
在mounted中加上this.$refs,或ref绑定一个对象

十七、 Element-ui和vant-ui按需引入 或CDN引入

首先安装按需引入的插件,在main.js中添加按需引入的配置,之后在建好的js文件中首先导入vue,再导入需要的element-ui /vant-ui插件,通过vue.use()全局注入。
修改样式可以用样式穿透 /deep/ :deep

十八、Less/Sass/Scss的区别

安装 npm install node-sass sass-loader --save 注意版本 使用lang=”scss”

Scss是Sass的缩排语法

1.变量符不一样,Less是@,而Sass是$,而且变量的作用域也不一样。
2.Sass没有局部变量,满足就近原则。Less中{}内定义的变量为局部变量。

3.**Sass支持条件语句,可以使用if{}else{},for{}循环等等。而Less不支持。**less里面有一些内置函数

十九、 Rem、vw/vh设置
rem 是根 root em的缩写,1rem等于html根元素设定的font-size的px值 flexible中

js动态设置html的 font-size= 移动设备 / 设计稿宽度 * 100 VantUI中设计稿默认37.5px

如果css里面没有设定html的font-size,则默认浏览器以1rem=16px来换算。
vw视窗的宽度 1vw=视窗宽度的1%
vh视窗高度,1vh=视窗高度的1%

二十一、 watch监听

一个对象,键是需要观察的表达式,值是对应回调函数。主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作;可以看作是 computed 和 methods 的结合体;
值是包括选项的对象:选项包括有三个。
第一个handler:其值是一个回调函数。即监听到变化时应该执行的函数。
第二个是deep:其值是true或false;确认是否深入监听。
第三个是immediate:其值是true或false;确认是否以当前的初始值执行handler的函数

二十二、 methods,watch,computed的区别

1 . computed 属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。主要当作属性来使用;调用多次,只会执行一次
2 . methods 方法表示一个具体的操作,主要书写业务逻辑;
3 . watch 一个对象,键是需要观察的表达式,值是对应回调函数。主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作;可以看作是 computed 和 methods 的结合体;

二十三、

二十五、使用Vue-cli配置代理

module.exports = {
	devServer: {
      proxy: {
      '/api1': {// 匹配所有以 '/api1'开头的请求路径
        target: 'http://localhost:5000',// 代理目标的基础路径
        changeOrigin: true,
        pathRewrite: {'^/api1': ''}
      },
      '/api2': {// 匹配所有以 '/api2'开头的请求路径
        target: 'http://localhost:5001',// 代理目标的基础路径
        changeOrigin: true,
        pathRewrite: {'^/api2': ''}
      }
    }
  }
}
/*
   changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
   changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080
   changeOrigin默认值为true
*/

二十四、vue路由首屏加载优化 路由懒加载 CDN引入 关闭sourcemap Gzip压缩

一、Vue首屏加载路由懒加载使用ES6的import ( ) const 组件名 = ( ) => import(‘组件路径’)

  1. sourcemap是为了方便线上调试用的,因为线上代码都是压缩过的,导致调试极为不便,而有了sourcemap,就等于加了个索引字典,出了问题可以定位到源代码的位置。
    但是,这个玩意是每个js都带一个sourcemap,有时sourcemap会很大,拖累了整个项目加载速度,为了节省加载时间,我们将其关闭掉。

Vue项目优化首屏加载

Webpack优化

1.webpack是可以帮助我们做到资源的去重和分离,去重就是将重复的引用减少,分离将不同的资源包分离在不同的包内

Webpack 构建结果输出分析 loader对css 图片资源压缩 js文件进行压缩 去除console 生产环境关闭source-map

externals防止将某些包打包到最终的bundle中,使用CDN加载 ,开启 gzip 压缩

浏览器缓存

代码层面
  • 第三方插件的按需引入 路由懒加载 图片懒加载 组件数据懒加载 进入可视区再加载数据 useIntersectionObserver
  • v-if 和 v-show 区分使用场景 computed 和 watch 区分使用场景 v-for 遍历必须为 item 添加 key
  • 防抖节流
  • 长列表性能优化 分页 滚动节流 只渲染可视区
    • 设置每一个列的高度值(itemHeight)
    • 获取显示区域高度 (offsetHeight)
    • 计算显示区域的数量 (visibaleCount)
    • 记录可视区域的第一(startIndex)和最后一个元素(endIndex)
    • 根据startIndex跟endIndex的值 计算可视区域起始到结束的数据赋值 (visibaleData)
  • 事件变量和定时器再beforeDestory销毁

计算机网络

A* 当浏览器输入URL到页面出现发生了什么

  1. 浏览器域名解析为IP地址(DNS域名解析)。

    本地解析:

    浏览器缓存 → 系统缓存 → 查找本地host文件 → 本地DNS服务器缓存

    互联网域名服务器解析:

    → 根域名服务器 → 顶级域名服务器 → 权威域名服务器

  2. 浏览器获得域名对应的ip地址后 ,与WEB服务器建立TCP连接(TCP三次握手)

  3. tcp连接建立后,浏览器给WEB服务器发送一个HTTP请求

  4. 服务器端响应HTTP请求,返回HTTP报文

  5. 浏览器解析和渲染页面

  6. 关闭 TCP 连接(四次挥手)

浏览器渲染的步骤

  1. HTML 解析出 DOM Tree
  2. CSS 解析出 Style Rules
  3. 两者关联生成 Render Tree
  4. Layout(布局)根据 Render Tree 计算每个节点的信息
  5. Painting 根据计算好的信息进行渲染整个页面

(1)回流(重排):当render树中的一部分或者全部因为大小边距等问题发生改变而需要重建的过程叫做回流(改变大小)。

**(2)重绘:**当元素的一部分属性发生变化,如外观背景色不会引起布局变化而需要重新渲染的过程叫做重绘(改变样式)。

回流必将引起重绘

如何减少回流和重绘

1.让元素脱离文档流 有动画效果的元素

  • 浮动 float
  • 绝对定位absolute
  • 固定定位fixed

2.通过合并多次DOM样式的修改,来减少回流和重绘的发生次数。

3.添加css样式而不是利用js控制样式

浏览器解析文档的过程中,如果遇到 script 标签,会立即解析脚本,停止解析文档(因为 JS 可能会改变 DOM 和 CSS,如果继续解析会造成浪费)。

如果是外部 script, 会等待脚本下载完成之后在继续解析文档。

现在 script 标签增加了 defer 和async 属性,脚本解析会将脚本中改变 DOM 和 css 的地方> 解析出来,追加到 DOM Tree 和Style Rules 上

状态码

一、http状态码分类:

100-199 提示信息 – 表示请求正在处理
200-299 成功 – 表示请求正常处理完毕
300-399 重定向 – 要完成请求必须进行更进一步的处理
400-499 客户端错误 – 请求有语法错误或请求无法实现
500-599 服务器端错误 – 服务器处理请求出错

二、* 常见的状态码有哪些?

200:请求成功,浏览器会把响应体内容(通常是html)显示在浏览器中;

301/302/303:(网站搬家了,跳转)重定向

400: 语义有误,当前请求无法被服务器理解。

401: 当前请求需要用户验证

403: 服务器已经理解请求,但是拒绝执行它。

404:(客户端问题)请求的资源没有找到

500:(服务端问题)请求资源找到了,但服务器内部发生了不可预期的错误;

强制缓存和协商缓存

  1. 强制缓存是我们在第一次请求资源时在 http 响应头设置一个过期时间,在时效内都将直接从浏览器进行获取,常见的 http 响应头字段如 Cache-Control 和 Expires
  2. 协商缓存是我们通过 http 响应头字段 etag 或者 Last-Modified 等判断服务器上资源是否修改,如果修改则从服务器重新获取,如果未修改则 304 指向浏览器缓存中进行获取
四、* 跨域

理解浏览器跨域的概念:协议、域名、端口都相同才同域,否则都是跨域
跨域就是指浏览器不允许当前页面的所在源,去请求另一个源的数据

CORS跨域 (前端不用动,后端设置Access-Control-Allow-Origin等)
服务端进行接口请求设置,前端直接调用
说明:后台设置前端某个站点进行访问
JSONP (动态创建script标签)
JSONP跨域-前端适配,后端配合
前后端同时改造

五、Git

git init 初始化git仓库 (mac中Command+Shift+. 可以显示隐藏文件)
git status 查看文件状态
git add 文件列表 追踪文件
git commit -m 提交信息 向仓库中提交代码
git log 查看提交记录
1.分支明细
(1)主分支(master):第一次向 git 仓库中提交更新记录时自动产生的一个分支。
(2)开发分支(develop):作为开发的分支,基于 master 分支创建。
(3)功能分支(feature):作为开发具体功能的分支,基于开发分支创建

2.分支命令
(1)git branch 查看分支
(2)git branch 分支名称 创建分支
(3)git checkout 分支名称 切换分支
(4)git merge 来源分支 合并分支 (备注:必须在master分支上才能合并develop分支)
(5)git branch -d 分支名称 删除分支(分支被合并后才允许删除)(-D 强制删除)

3.暂时保存更改
(1)存储临时改动:git stash
(2)恢复改动:git stash pop

多人冲突:
是当前修改是左箭头方向,传入的是右箭头的方向,中间用等于号分割,等号上边是当前修改,下边是传入的修改。
两人同时提交可能会出现冲突,解决办法是手动修改冲突

六、* http和https的区别

HTTP与HTTPS的区别
1、HTTP是超文本传输协议,信息是明文传输,HTTPS是具有安全性的SSL加密传输协议。
2、HTTPS协议需要ca申请证书,一般免费证书少,因而需要一定费用。
3、HTTP和HTTPS使用的是完全不同的连接方式,用的端口也不一样。前者是80,后者是443。
4、HTTP连接是无状态的,HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,安全性高于HTTP协议。

七、* 三次握手和四次挥手

三次握手:
第一次:建立连接时,客户端发送syn(syn=j)包到服务器,等待服务端确认
第二次:服务器收到syn包,必须确认客户的syn(ack=j+1),同时也发送一个syn(syn=k)包,即syn+ACK包
第三次:客户端收到服务器的syn和ack包,向服务器发送确认包ack(ack=k+1),发送完毕,客户端和服务端连接成功,完成三次握手

四次挥手:
第一次:浏览器发送完数据后,发送fin请求断开连接
第二次:服务器发送ack到客户端,确认客户端的断开请求
第三次:服务器请求断开fin的请求
第四次:客户端确认服务器的断开ack

八、使用基于token的登录流程

使用基于 Token 的身份验证方法,大概的流程是这样的:

客户端使用用户名跟密码请求登录
服务端收到请求,去验证用户名与密码
验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里或者 Local Storage 里
客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据

九、* Get和post

  • 提交数据存储位置不同

GET请求会将数据放到URL后面 POST请求会将数据放到请求体中 (http 协议规定,url 在请求头中,所以大小限制很小)

  • 对提交的数据大小限制不同

GET请求对所发信息量的限制是2000 个字符 POST请求对信息量没有限制

  • 对提交的数据编码不同

GET请求的参数只能是ASCII码,所以中文需要URL编码 POST请求传参没有这个限制

  • 应用场景不同

GET请求用于提交非敏感数据和小数据 POST请求用于提交敏感数据和大数据

Ge和post的选择:
1.私密性的信息请求使用post(如注册、登陆)
2.查询信息使用get。

十、web安全及防护

1.XSS攻击原理:

攻击者往Web页面里插入恶意 html标签或者javascript代码。
用来窃取cookie中的用户信息
解决:对一些输入的字符进行过滤,尽量采用post表单提交的方式。

2.CSRF攻击(跨站请求伪造):

登录受信任的网站A,并在本地生成Cookie,在不登出A的情况下,携带cookie去访问危险网站B
解决:通过验证码的方式解决

3.SQL注入攻击

就是通过吧SQL命令插入到Web表单递交或输入域名,最终达到欺骗服务器执行恶意的SQL命令。
解决:表单输入时通过正则表达式将一些特殊字符进行转换

你可能感兴趣的:(VUE,vue,javascript,前端)