vue相关

1,Object.defineProperty Proxy 区别 定义、优缺点、区别

Object.defineProperty :vue2中实现数据监听/响应式的核心API。

Object.defineProperty遍历监听(observer)vue对象中的所有属性:data,props,computed。给每个属性增加getter和setter操作,当属性发生变化时更新视图。

缺点:

1,只对对象进行劫持,递归到底,一次性计算量大。

2,无法监听数组。vue重写覆盖数组原生方法。

3,无法监听新增/删除属性,要调用vue.set() 、 vue.delete()方法。

proxy: vue3中实现数据监听/响应式的核心API。

1,对目标对象操作之前设置了拦截,通过操作对象的代理来间接操作对象。

2,可监听数组变化

3,可监听新增/删除属性。

优点:

proxy深度监听性能更好:只在get时才进行下一级监听(意思是获取到哪一层,那层才会触发响应式。例如访问到a,不会再去访问a里面更深层内容)

区别: 两者是否需要key属性。

Object.defineProperty:

必须要知道拦截的key(如,{count:1}的count)是什么,所以对新增属性无能为力。

代码 Object.defineProperty(data,'count',{get(){},set(){}})

proxy:

不需要关心具体的key,它去拦截的是 修改 data 上的任意 key 和 读取 data 上的任意 key。

兼容性,proxy无法兼容IE(包括IE11),vue检测到就降级为object.defineProperty的数据监听系统。

代码 new Proxy(data,{get(key){},set(key,value){}})

2, 组件渲染更新过程 网红题---render-vnode-diff-patch

模板编译

1,转js:转换为js代码,即编译模板。

2,不是html标签语言:模板不是html标签语言,模板有插值,指令,js表达式(判断,循环。只有js才能实现判断,循环(图灵完备的)。所以模板一定会转为js代码)

3,编译为render函数:模板编译过程:模板编译为render函数,返回vnode。再执行diff和patch。

使用webpack,vue-loader,会在开发环境下编译模板。

虚拟dom和diff算法

1,将dom抽象为虚拟dom,diff算法对比新旧虚拟dom,只把变化的部分重新渲染。

2,diff算法是通过js层面的计算,返回一个patch补丁对象,之后解析这个patch对象,渲染到页面上。

因为传统的dom渲染慢,消耗性能。js在浏览器上运行快。

表示虚拟dom的js对象上有三个属性:tag(元素标签名),props(元素属性),children(元素下级-数组)

{ "tag":"div",props:{"color:":"red","id","id11"},children:[{}] }

diff算法规则

diff即比较。同层树节点进行比较。

1,只比较同意层级,不深度比较。

2,如tag不相同,则删掉重建。

3,如tag和key相同,则认为是相同节点,不在深度比较。

组件渲染/更新过程

  1. 初次渲染组件

1,解析模板为render函数。

2,触发响应式,监听data属性(第一次只触发getter)

3,执行render函数,生成vnode,并执行patch。

  1. 更新组件

1,修改data触发setter。

2,重新执行render函数,生成newVnode,

3,执行patch(vnode,newVnode),diff算法更新视图。

  1. 异步渲染组件

$nextTick()是异步渲染组件,汇总data的修改,一次性更新视图。好处:减少dom操作次数,提高性能。

3, w ebpack 配置详解

含义:是js应用程序的静态模块打包器; 是目前主流的前端工程化解决方案。

功能:代码压缩混淆;处理不同浏览器兼容性(如写es6代码)

常用配置:

1,webpack.config.js是配置文件。

webpack在打包构建之前,会先读取这个配置文件。生成dist文件。

用 vue-cli-service serve 启动就会用 vue.config.js;
用 webpack-dev-server 启动就会用 wepback.config.js(默认)。

  1. entry指定打包入口,output指定打包出口

3,如何修改http服务器地址?

devServer选项中配置proxy代理里的target指向新的http服务器地址。

4,热更新 webpack-dev-server

5,loader加载器

css,less,jpg怎么被打包输出?

webpack只会解析js文件,其他的文件需要对应的loader加载包来解析和打包。

less-loader处理less文件、css-loader处理css、babel-loader处理高级js语法。

使用webpack,vue-loader,会在开发环境下编译模板。

6,build打包 打包好处:代码压缩,性能优化。

4, webpack对性能的优化

在webpack.config.js里module选项里配置npParse(不解析哪些模块,例如jquery,elementui等)

实例:webpack.config.js 文件里 modules.export{

module:{ noParse:{ /jquery,elementui/} }

}

路由:两种模式、路由守卫、路由懒加载

5, vue-router两种模式

hash:

  1. hash模式下是指#之后的所有字符串,虽然它包含在url中,但不包含在http请求中,所以改变hash值不会重新加载页面。

2,hash改变触发浏览器的前进后退。

history: history模式下就是当页面刷新时,它会发送请求,把url传过去,因此,如果后端没有做处理的 话,就会因找不到资源报404。因此history模式时需要跟后端配合。

面试问题:history模式下刷新出现404如何解决?

原因:vue-router设置的路径不是真实存在的,所以刷新就返回404错误。

解决方式:需要后台配置支持。后端:修改服务器404页面配置路径情况下指向index.html页面。

前端:在vue里覆盖所有的路由情况,给出一个404页面。

补充知识:网页url的组成部分:http://127.0.0.1:8080/01-hash.html?a=100\&b=20#/aaa/bbb

location.protocol(协议 ) : http

location.hostname(主机 ) :127.0.0.1

location.post(端口 ) : 8080

location.pathname : /01-hash.html

location.search : ?a=100&b=20

location.hash : #/aaa/bbb

6, vue - router路由守卫,动态路由、(组件和路由)懒加载

路由守卫(RBAC权限设计思想): 就是路由钩子函数。作用:根据用户权限动态生成左侧菜单。

我们在vue项目里,src文件里创建permission.js权限控制。import到main.js里。

思路:router.beforeEach()结合router.addRoutes()使用。

当用户点击登录后,首先进入路由守卫,从后台获取用户的权限,在vuex中保存菜单信息,然后运用addRoutes方法动态添加路由配置,最后完成登录。

RBAC权限设计思想指:用户,角色,功能来让不同的账号登录后进入不同的页面。

router.beforeEach((to, from, next) => {

NProgress.start()

if (getToken()) {//getToken从cookie里获取token

to.meta.title && store.dispatch('settings/setTitle', to.meta.title)

/* has token*/

if (to.path === '/login') {

next({ path: '/' })

NProgress.done()

} else {

if (store.getters.roles.length === 0) {

// 判断当前用户是否已拉取完user_info信息

store.dispatch('GetInfo').then(() => {

store.dispatch('GenerateRoutes').then(accessRoutes => {

// 根据roles权限生成可访问的路由表

router.addRoutes(accessRoutes) // 动态添加可访问路由表

next({ ...to, replace: true }) // hack方法 确保addRoutes已完成

})

}).catch(err => {

store.dispatch('LogOut').then(() => {

Message.error(err)

next({ path: '/' })

})

})

} else {

next()

}

}

} else {

// 没有token

if (whiteList.indexOf(to.path) !== -1) {

// 在免登录白名单,直接进入

next()

} else {

next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页

NProgress.done()

}

}

})

组件和路由懒加载:import,require

组件懒加载,即在需要的时候,加载该异步组件。路由懒加载,即在路由激活时,加载该路由配置下相应的异步组件。

CommonJs 规范的 require 可以实现组件和路由的懒加载,ES6 语法标准的 import 也可以实现。

组件和路由的懒加载,一般用于首屏优化,不立刻请求资源,待首屏加载完毕或者按需响应时再加载资源。可以减少首屏加载用时。

1,require实现懒加载:

{

path:"index",

component : resolve => require( [ "@/views/index"] ),

hidden:true

}

2, import 实现懒加载

{

path:"index",

component : ( ) => import( "@/views/index"), //返回一个'promise'对象

hidden:true

}

vue官方文档中使用的也是import实现路由懒加载

动态路由:两种

  1. params参数添加:

如index.js里添加id:{path:"/user/:id", component:User}

然后在绑定id:<router-link :to="/user/"+dataid tag='button'> 用户</router-link>

获取这id:this.$route.params.id

2, query参数路由:

<router-link :to={path:"/user",query:{id:'dataid'}}>用户</router-link>

7,MVVM

数据驱动视图 ------ vue:MVVM, react:setState

MVVM

1,view视图层,model数据层,viewModel通过数据绑定 把视图层和数据层链接起来。

2,view层和model层完全解耦:

view层展示的是viewModel的数据,viewModel与model层进行交互。(开发者只需要关注业务逻辑,不需要手动操作dom)

8, vue组件生命周期 注释:el是挂载元素,data是数据

beforeCreate:el和data都是undefined

created:data有,el没有

说明:可以做初始化数据操作,但dom无法交互。如需要,使用$nextTick()访问dom

beforeMount:data和el都有,但还是虚拟dom

说明:此时对数据更改,不会触发updated

mounted:实例已挂载,数据渲染好

说明:可访问dom节点

beforeUpdate:虚拟dom打补丁之前

说明:更改数据,不会重新渲染

updated:虚拟dom重新渲染和patch打补丁之后调用,组成新的dom已更新。

说明:不要更新数据,会死循环

beforeDestroy:实例销毁前调用

说明:清定时器,自定义事件

destroyed:实例销毁后调用

说明:实例监听器移除,子实例销毁

9, vue组件生命周期钩子

是回调函数。创建组件实例的过程中会调用对应的钩子方法。

是一个发布订阅模式,将钩子订阅好,在对应的阶段发布。

10, vue父组件和子组件生命周期钩子执行顺序

渲染 过程

父beforeCreate --- 父created --- 父beforeMount --- 子beforeCreate --- 子created --- 子 beforeMount --- 子mounted --- 父mounted

更新 过程

父beforeUpdate --- 子beforeUpdate --- 子updated --- 父updated

销毁 过程

父beforeDestroy --- 子beforeDestory --- 子destoryed --- 父destroyed

11, ajax请求应放在哪个生命周期

放在mounted里:实例已挂载,数据渲染好。2,created里,使用$nextTick() 完成数据绑定。

因为ajax是异步获取数据,如放在mounted之前,即使ajax拿到数据,也要等渲染完成。

12, computed

缓存,data不变不会重新计算;提高性能。

13, 何时使用keep - alive

  1. 缓存组件,不需要重复渲染。2,多个静态tab页切换。

14, 作用域插槽slot占位符

子组件中放已占位符<slot></slot>(子组件中具名占位符)

父组件中给占位符填充内容

15, v-show和v-if

v-show通过css的display控制显示和隐藏

v-if是组件真正的渲染和销毁。频繁切换显示状态用v-show,否则用v-if

16, v-for中使用key

必须使用key,不要用index和random。如果是静态数据不做更新和删除操作,则可以用index。

原因:diff算法通过tag和key确认是否为sameNode。所以key的唯一性,能让diff算法更快的找到需要更新的dom。

移除key不存在的元素。减少渲染次数,提升性能。

17, 何时使用before D estory

1,解除自定义事件 this.$off()

  1. 清除定时器

如果不解绑会造成内存泄漏

自定义事件:

1,子组件触发父组件的方法。

2,dom事件如window,scroll。

解除方法: this.$off()解除所有自定义事件。vue自己的事件会自己解除,但自定义事件则要手动解除。
项目实例:

康兮项目里,有个页面需展示心电图表数据。设置定时器,展示完一分钟的心电数据后再次请求。之前没有清除定时器,导致占内存占的越来越大,页面很卡。之后改为再次进行下次请求前清除定时器并在离开此页面时在beforeDestory里清除定时器。

18, 组件data必须是一个函数

1,组件是一个class类,每个地方用的时候相当于这个类的实例化。实例出的data在一个闭包里,那么实例出来的数据就不会相互影响。如果data不是一个函数,那么每个组件的数据都共享了,一个地方改,其他地方跟着改。

2,vue根实例只有一个,所以没有这种情况。

19, 如何将组件所有的props传递给子组件

props 如: \20, 父子组件传值

父传子:

1,props

2,$parent

3, provide和inject 父组件暴露给后代组件的属性和方法

官方不推荐使用,因为数据追溯困难,不知道哪层声明了provide,哪层申明了inject。

4,.sync 父子双向传值语法糖

①,父组件在传入子组件的数据后加.sync,不需要对子组件的$emit进行接收;

②,子组件$emit传回的不再是个函数,而是 update:父组件传给子组件的变量名

好处:父组件少处理了$emit传来的函数那步。

<template>

<div class="content">

<btn :btnName.sync='num' ></btn>

</div>

</template>

export default{

props:['btnName']

methods:{

changeName(){

this.$emit('update:btnName',888)

}

}

}

子传父:

1,emit

  1. ref

其他组件传值:

1, $bus

2, vuex

21, v-model表单元素实现数据双向绑定

v-model本质上是语法糖,监听用户输入事件 来更新数据

官方文档有说到:v-model的原理有两个操作:

1,v-bind绑定value 属性值

2,v-on绑定input 事件监听到函数中,函数中获取最新的值赋值到绑定属性值中

<input v-model="searchText" /> 相当于:

<input :value="searchText" @input="searchText = $event.target.value" />

22, mixin抽离多组件有相同逻辑

mixin:1,js可包含任意选项;2,会混入到组件本身选项;

// 定义一个js文件,混入对象

export default {

created: function () {

this.hello()

},

methods: {

hello: function () {

console.log('hello from mixin!')

}

}

}

<script>// 其他组件使用混入对象

import mixin from './mixin'

export default {

mixins:[mixin],

data () {

return {}

}

}

</script>

mixin缺点:1,容易发生命名冲突;2,不能向mixin传参改变逻辑;

为了解决这个问题应使用vue3中通过逻辑关注点组织代码的方式,组合式api。

23, 组合api和选项式api

options API:选项式api。会在data,props,methods,computed,watch等中定义属性和方法。逻辑关注点被分散在各个选项中。

例如:methods中有20多个方法,分不清哪个方法对应哪个功能。

composition API:组合式api。是一个setup函数,根据逻辑相关性组织代码。

24, vue是什么

做过很多项目,基本都了解,很熟练。

是渐进式的js框架,单页面应用框架。只关注MVC中的视图层。

1,vue的核心特征:数据驱动MVVM

2,组件、指令、vue全家桶(vue脚手架vue-cli,vueRouter,vuex,axios)

25, vuex

vuex是专门为vue应用程序开发的状态管理模式。由5部分组成:

state:数据

actions: 异步操作

mutations: 唯一改变state数据的地方

getters: 类似于计算属性,对state数据进行计算,缓存。

modules: 模块化管理store,例如user模块,shop模块...,每个模块有自己的state,getter,action,mutation。

vuex缺点:存储在xuex中的状态,刷新页面,会丢失。解决方法:安装插件 vuex-persistedState

26, vuex中action和mutation区别

  1. action可做异步操作,mutation不可以

2,mutation每次制作一个操作,action可以提交多个mutation

27, vue - router异步加载(懒加载)方法

  1. 正常方式:

import Login from "@/componts/pages/login"

export default new Router({

routes:[ {

path:"/login",

component:Login

}]

})

  1. 异步加载:

使用resolve异步机制,用require替代import,实现按需加载。

好处:如果项目巨大,那么首页加载将是灾难。所以需要把一些路由用异步加载的 方式进行加载。

export default new Router({

routes:[ {

path:'/login',

component: resolve=>require("[@/component/pages/login]",resolve)}]

})

27, vue路由this .route.push 跳转页面不刷新解决

1,跳转前

this.$router.push( { 'path':'' ,query:{ 'id':'' }})

2,接收页面 watch 监听

watch :{

'$route'(to,from){ //监听路由变化 }

}

28,diff 算法的时间复杂度

diff算法:同层树节点进行比较。

  1. 只比较同一层级,不跨级比较
  2. tag不相同,则删掉重建,不再深度比较。
  3. tag和key都相同,则认为是相同节点,不再深度比较。

29, vue常见性能优化方案

v-show v-if v-for computed vue-router keep-alive 定时器 图片懒加载 webpack

  1. 合理使用v-show,v-if

2,v-for加key,避免与v-if同时使用

3,合理使用computed

4,使用vue-router异步加载组件
5,使用keep-alive缓存组件

6,自定义事件,DOM事件,定时器及时销毁:例如使用防抖和节流时使用lodash库,移除组件时在beforeDestroy销毁定时器。

7,Data层级不要太深

8,图片懒加载

9,webpack层面优化:① productionSourceMap:false 提升构建速度

vue.config.js 中设置productionSourceMap:false 在构建生产环境时 不要生成sourcemap文件,提高构建速度。

30, v - for优先级高于v-if,避免同时使用

31, vue注册全局组件

//在mian.js里引入Count组件

import Count from "..."

Vue.component("MyCount",Count)

  1. 定义组件 Count.vue

2, main.js里引入组件

  1. Vue.component( "组件名",实例) 注册组件

4,任何页面都可以使用该组件

32, 组件封装

面试回答:

我在用vue开发项目时,一般都会用到组件封装。

我在搭建一个项目时,创建一个views目录放页面组件,common目录放公共组件(如,head,foot),feature目录放功能组件(如 swiper,tabbar,list)。

vue.extend()不常用,用vue.component更简单

33, dict字典

场景:固定下拉菜单内容,把这个下拉菜单全部封装到dict.js字典里。再把这个字典放到vue原型上,在页面中调用。

34, elementui组件的二次封装

重复性较多的组件,可以封装起来。例如样式功能相似的表格。给表格传入不同的参数

35, vue综合面试

1,vue为什么要求组件模板只有一个根元素

①vue的VDOM算法只允许VDOM的树状解构有一个根节点。如果逻辑抽象树有多个根,那么就会产生多个入口,这对于遍历、查找、比较都不方便。

②组件的template都会转换成Vnode对象,组件的根元素对应的就是vnode对象。

2,你了解diff算法吗?

在"vue2题1"------组件渲染和更新过程里

3,在vue文件中style是必须的吗?script是必须的吗?为社么?

template是必须的,style和scipt都不是必须的。如果没有template,vue会报错。

36, scoped原理以及scoped的穿透用法

scoped原理:

scoped:css样式只能用于当前vue组件。

scoped实现原理:通过postCss实现,给组件中所有的dom元素添加唯一的动态属性。给css选择器添加一个属性选择器。这样做是使样式只作用于该属性的dom元素。

scoped缺点 :如果你子组件的根元素上有一个类已经在这个父组件中定义过了,那么这个父组件的样式就会泄露到子组件中。

scoped穿透: sass和less 使用 外层 /deep/ 第三方组件样式

stylus使用 外层 >>> 第三方组件样式

scoped穿透缺点失去了组件的封装效果 。这个组件内的所有的 .title 类的样式都会被这些样式所浸染---即便是孙节点。

使用scope和module的区别?

scoped样式可能会收到全局样式影响,

module样式不会受到全局样式影响。

scoped的效果是对元素加上data属性,但是可能会受到全局样式的影响。

module经过css-loader会对类名进行编译,添加上hash值等,所以无需担心和其他页面的同样的类名冲突,也可以避免全局样式被污染。

其实两种方案都非常简单、易用,在某种程度上解决的是同样的问题。 那么你该选择哪种呢?

scoped 样式的使用不需要额外的知识,给人舒适的感觉。它所存在的局限,也正是它的使用简单的原因。它可以用于支持小型到中型的应用。

在更大的应用或更复杂的场景中,这个时候,对于 CSS 的运用,我们就会希望它更加显式,拥有更多的控制权。虽然在模板中大量使用 $style 看起来并不那么"性感",但却更加安全和灵活,为此我们只需付出微小的代价。

module好处

它的第一点好处就是,当我们在 HMTL 中查看这个元素时我们可以立刻知道它所属的是哪个组件;第二点好处是,一切都变成显式的了,我们拥有了彻底的控制权------不会再有什么奇怪的现象了。

scoped:

<style>//生成style样式

.button[data-v-f61kqi1] {color: red;}

</style><button class="button" data-v-f61kqi1></button>

module:

<template><button :class="$style.button" />

</template><style module>.button {color: red}

</style>

//生成html和style样式

<style>.ComponentName__button__2Kxy {color: red;}

</style><button class="ComponentName__button__2Kxy"></button>

37, ruoyi框架

当路由匹配到一个不存在的路由时,显示某一个组件:

{ path:"/:path(.*)",component:import('@/view/redirect.vue') }

38, vue实例方法

$mount() 外部设置el,vue的作用范围。

$destroy() 手动销毁。

$watch() 监听。

$forceUpdate() 强制更新

$delete()

$nextTick()

39, 自定义指令

//全局指令

Vue.directive("red",(ele)=>{

ele.style.color = "red"

})

//组件指令

directives:{

test:{

inserted: function (el,binding) {// 指令的定义

/ /el为绑定元素,可以对其进行dom操作

console.log(binding) //一个对象,包含很多属性属性

},

bind: function (el, binding, vnode) {

el.innerHTML =binding.value

}

}

}

40, to Fixed() 方法可把 Number 四舍五入为指定小数位数的数字。

在vue中,过滤器使用toFixed()对数值取两位小数操作,提示data.toFixed is not a function

解决办法:

Number(data).toFixed(n) //转成数值类型;

41,Vue.config.productionTip = false

阻止启动生产消息,常用作指令

没有Vue.config.productionTip = false这句代码,它会显示你生产模式的消息

开发环境下,Vue 会提供很多警告来帮你对付常见的错误与陷阱。
而在生产环境下,这些警告语句却没有用,反而会增加应用的体积。

相关推荐
崔庆才丨静觅33 分钟前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60611 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了1 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅1 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅2 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅2 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment2 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅3 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊3 小时前
jwt介绍
前端
爱敲代码的小鱼3 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax