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 会提供很多警告来帮你对付常见的错误与陷阱。
而在生产环境下,这些警告语句却没有用,反而会增加应用的体积。

相关推荐
Stanford_11064 分钟前
关于IDE的相关知识之一【使用技巧】
前端·ide·windows·微信小程序·微信公众平台·twitter·微信开放平台
爱健身的小刘同学10 分钟前
安装 electron 依赖报错
前端·javascript·electron
耶啵奶膘10 分钟前
uniapp+vue2+uview2.0导航栏组件二次封装
前端·javascript·uni-app
布兰妮甜11 分钟前
如何使用 Tailwind CSS 构建响应式网站:详细指南
前端·css·tailwind css
MavenTalk12 分钟前
前端技术选型之uniapp
android·前端·flutter·ios·uni-app·前端开发
雨中奔跑的小孩15 分钟前
electron打包部署vue项目
javascript·vue.js·electron
ZZZCY200327 分钟前
路由策略与路由控制实验
前端·网络
shawya_void36 分钟前
javaweb-day01-html和css初识
前端·css·html
khatung37 分钟前
React——useReducer
前端·javascript·vscode·react.js·前端框架·1024程序员节
思考的橙子39 分钟前
CSS之3D转换
前端·css·3d