- HTML篇
- CSS篇
- JS篇### vue面试题汇总
1. 谈谈你对MVVM开发模式的理解?
MVVM是一种简化用户界面的实践驱动编程方式。在当前主流的前后端分离的开发模式中,MVVM模式的优越性日益体现,相较于经典的MVC模式,其对于程序模块的封装很好地解决了前后端信息交互的冗余和繁琐
MVVM分为Model、View、ViewModel三者。
Model 代表数据模型,数据和业务逻辑都在Model层中定义;
View 代表UI视图,负责数据的展示;
ViewModel 负责监听 Model 中数据的改变并且控制视图的更新,处理用户交互操作;
Model 和 View 并无直接关联,而是通过 ViewModel 来进行联系的,Model 和 ViewModel 之间有着双向数据绑定的联系。因此当 Model 中的数据改变时会触发 View 层的刷新,View 中由于用户交互操作而改变的数据也会在 Model 中同步。
这种模式实现了 Model 和 View 的数据自动同步,因此开发者只需要专注对数据的维护操作即可,而不需要自己操作 dom。为什么使用MVVM:
低耦合,
可复用,
独立开发,
可测试
2. v-if 和 v-show 有什么区别?
- 手段 - v-if是动态的向DOM树内添加或者删除DOM元素;- v-show是通过设置DOM元素的display样式属性控制显隐;
- 编译 - v-if是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译;- v-show是在任何条件下,无论首次条件是否为真,都被编译,然后被缓存,而且DOM元素保留;
- 性能消耗: - v-if有更高的切换消耗;- v-show有更高的初始渲染消耗
3.
r
o
u
t
e
和
route和
route和router区别
- $route 是“路由信息对象”,包括 path,params,hash,query,fullPath,matched,name 等路由信息参数
- $router 是“路由实例”想要导航到不同URL 对象包括了路由的跳转方法,钩子函数等。通过push、replace、go、back等方法,来实现页面间的跳转
4.vue自定义指令
vue指令
vue2局部注册:directive选项
directives: { 'focus': { bind(el, binding, vnode) { el.focus() } } }全局注册:main.js
Vue.directives('focus',{ bind(el, binding, vnode) { el.focus() } })生命周期:
- bind:只调用一次,指令第一次绑到元素调用,用于初始化
- inserted:被绑定元素插入父节点时调用
- update:所在组件vnode更新调用
- componentUpdate:指令在组件的vnode及子组件的vnode全部更新完调用
- ubind:只调用一侧,指令解绑
vue3局部注册:引入 import { Directive , DirectiveBinding } from ‘vue’ 分别校验
vFocus,
binding<template> <input type="text" v-focus="{ color: 'red' }" /> </template> <script setup> const vFocus = { created(el, binding) { el.style.backgroundColor = binding.value.color; console.log(el, binding.value.color); //<input type="text" style="background-color: red;"> 'red' }, }; </script>全局注册:main.js,app.vue如上引入
import{ createApp }from'vue'import App from'./App.vue'const app =createApp(App) app.directive('focus',{created(el, binding){ el.style.backgroundColor = binding.value.color; console.log(el, binding.value.color);//<input type="text" style="background-color: red;"> 'red'}}) app.mount('#app')生命周期:
- created 元素初始化的时候
- beforeMount 指令绑定到元素后调用 只调用一次
- mounted 元素插入父级dom调用
- beforeUpdate 元素被更新之前调用
- update 这个周期方法被移除 改用updated
- beforeUnmount 在元素被移除前调用
- unmounted 指令被移除后调用 只调用一次
5.vue项目优化
- 代码层面 - 长列表性能优化- 事件销毁, beforeDestroy生命周期函数内执行销毁逻辑。- 图片懒加载- 路由懒加载- 按需加载插件- v-if,v-for避免同时使用- v-if,v-show选择- keep-alive组件缓存- input防抖节流
- 基础的web技术优化 - 开启gzip压缩- 浏览器缓存- CDN加速
- webpack优化
6.vue模板如何编译
Vue的模板编译就是将“HTML”模板编译成render函数的过程。这个过程大致可以分成三个阶段:
- 解析阶段:将“HTML”模板解析成AST语法树;
- 核心 parseHTML( template ,{}) Vue定义了很多匹配HTML的正则表达式 ,parseHTML根据正则匹配
- parseHTML是解析模板字符串的“主线程”,它的第一个参数是要解析的模板字符串, 也就是单文件组件中最外层 所包裹的部分;第二个参数是一个选项对象,它会包含一些回调,以及一些配置项。
- 选项对象: - start( tag, attrs, unary ) 匹配到开始标签时的回调,tag为当前标签的标签名,attrs为该标签上的属性列表,unary为当前标签是否为自闭合标签- end() 匹配到结束标签时的回调- chars(text) 匹配到文本节点的回调- comment(text) 匹配到注释节点的回调,其处理逻辑跟文本的处理逻辑类似
- 优化阶段:从AST语法树中找出静态子树并进行标记(被标记的静态子树在虚拟dom比对时会被忽略,从而提高虚拟dom比对的性能); - 上面简单介绍过,优化阶段的工作就是标记静态子树,标记静态子树后主要有以下两个优点: - 生成虚拟dom的过程中,如果发现一个节点是静态子树,除了首次渲染外不会生成新的子节点树,而是拷贝已存在的静态子树;- 比对虚拟dom的过程中,如果发现当前节点是静态子树,则直接跳过,不需要进行比对。- 标记静态子树的过程分为两个步骤: - 遍历AST语法树,找出所有的静态节点并打上标记(注:当前节点及其所有子节点都是静态节点,当前节点才会被打上静态节点的标记)- 遍历经过上面步骤后的树,找出静态根节点,并打上标记(注:静态根节点是指本身及所有子节点都是静态节点,但是父节点为动态节点的节点,找到了静态根节点也就找到了“静态子树”)
- 代码生成阶段:通过AST生成代码字符串,并最终生成render函数。
7.vue2响应式原理
vue 采用了几个核心部件 :
Observer,
Dep,
Watcher,
Scheduler
- observer把一个普通的对象转换成响应式的对象
- observer 把对象的每个属性通过 object.defineProperty 转换为带有 getter 和 setter 的属性
- Dep 表示依赖, vue 会为响应式对象中的每一个属性,对象本身,数组本身创建一个 dep 实例,每个 dep 实例都可以做两件事情 :
- 记录依赖:是谁在用我
- 派发更新:我变了,我要通知那些用我的人
- watcher 在函数执行的过程中,如果发生了依赖记录,那么 dep 就会把这个全局变量记录下来,表示有一个 wathcer 用到了我这个属性。
- Scheduler 不会立即执行更新,通过nexttick异步更新
8.vue3响应式原理
通过Proxy(代理): 拦截对象中任意属性的变化,包括:属性值的读写,属性的增加,属性的删除等。
通过Reffect(反射): 对源对象的属性进行操作, Reflect不是一个函数对象,因此它是不可构造的。
9.刷新浏览器后,Vuex的数据是否存在?如何解决?
不存在原因: 因为
store里的数据是保存在运行内存中的,当页面刷新时,页面会重新加载vue实例,store里面的数据就会被重新赋值初始化。
我们有两种方法解决该问题:
- 使用
vuex-along- 使用
localStorage或者sessionStroage
10.vue和react共同点?区别
共同点:
- 数据驱动视图
- 组件化
- 都使用
Virtual DOM不同点:
- 核心思想不同 - vue定位就是尽可能的降低前端开发的门槛,让更多的人能够更快地上手开发。这就有了vue的主要特点:
灵活易用的渐进式框架,进行数据拦截/代理,它对侦测数据的变化更敏感、更精确。- react 定位就是提出 UI 开发的新思路React推崇函数式编程(纯组件),数据不可变以及单向数据流,当然需要双向的地方也可以手动实现, 比如借助onChange和setState来实现。- 组件写法 - React推荐的做法是
JSX + inline style, 也就是把 HTML 和 CSS 全都写进 JavaScript 中- Vue 推荐的做法是 template 的单文件组件格式(简单易懂,从传统前端转过来易于理解),即 html,css,JS 写在同一个文件(vue也支持JSX写法)- diff算法
- 响应式原理 - vue2采用object.defineProperty ,vue3采用proxy,reflect- React基于状态机,手动优化,数据不可变,需要
setState驱动新的state替换老的state。
11.vue双向数据绑定原理
简易实现:v-model分为两部分,通过v-bind绑定值,再通过v-on:input来通步修改值
原理:
- 需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上setter和getter这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化
- 通过dep来理清依赖关系,watcher在依赖中添加自身
- compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
- 待属性变动dep.notice()通知时,能调动watcher自身的update方法,并处罚compile回调渲染视图
12.computed和watch区别
computed计算属性,watch监听属性
- 计算属性不在 data 中,它是基于data 或 props 中的数据通过计算得到的一个新值。watch 可以监听的数据来源:data,props,computed内的数据
- component中有get和set方法,会默认缓存计算结果。watch不支持缓存,支持异步, immediate监听属性立即执行一次,deep开启深度监听
13.Vuex
Vuex是一种状态管理模式,存在的目的是共享可复用的组件状态。
主要包括以下几个模块:
- State => 基本数据,定义了应用状态的数据结构,可以在这里设置默认的初始状态。
- Getter => 从基本数据派生的数据,允许组件从 Store 中获取数据,mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性。
- Mutation => 是唯一更改 store 中状态的方法,且必须是同步函数。
- Action => 像一个装饰器,包裹mutations,使之可以异步。用于提交 mutation,而不是直接变更状态,可以包含任意异步操作。
- Module => 模块化Vuex,允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中。
14.vuex辅助函数
mapState,
mapMutations,
mapActions,
mapGettersmapState和mapGetters:
- 两者都放在 computed中,以mapState举例
import { mapState } from 'vuex' computed中 computed:{ ...mapState(['data']) //data是vuex存放的state中的属性,此时{{data}}可使用 }mapMutations, mapActions:
- 放在组件的
methods属性中 。使用与上类似
15.vuex模块化使用
当我们开发的项目比较大时,store中的数据就可能比较多,这时我们store中的数据就可能变得臃肿,为了解决这一问题,我们就需要将store模块化(module)
前提:创建两份js文件,含有属性与vuex写法相同,需要通过
namespaced:true开启命名空间store/index.js:在modules中引入文件
使用:
- 访问state数据: - 第一种方式:
this.$store.state.moduleA.sum- 第二种方式:...mapState('moduleA',['sum','number'])- action提交mutation
- 第一种方式:需要传参
this.$store.dispatch('moduleB/addZhang',{name:'小明',age:18}),无需传参this.$store.dispatch('moduleB/addServer')- 第二种方式:
...mapActions('moduleB',['addZhang'])- getters计算属性
- 第一种方式:
this.$store.getters['moduleB/firstName']- 第二种方式:
...mapGetters('moduleB',['firstName'])
16.vue中mixin
mixin(混入): 提供了一种非常灵活的方式,来分发
Vue组件中的可复用功能。
本质其实就是一个
js对象,它可以包含我们组件中任意功能选项,如
data、
components、
methods、
created、
computed等等
我们只要将共用的功能以对象的方式传入
mixins选项中,当组件使用
mixins对象时所有
mixins对象的选项都将被混入该组件本身的选项中来
具体使用:
- 创建mixins.js文件
let mixin ={created(){ console.log('我是mixin中的');},methods:{hellow(){ console.log('你好');},},}exportdefault mixin
- 局部使用
import mixin from"./mixins";exportdefault{mixins:[mixin],mounted(){this.hellow();//你好},};
- 全局使用main.js
import{ createApp }from'vue'import App from'./App.vue'import mixins from"./mixins";const app =createApp(App) app.mixin(mixins) app.mount('#app')
17.Vue中给对象添加新属性时,界面不刷新怎么办?
原因:vue2响应式采用object.defineProperty进行劫持,那个添加新属性时,新的属性不会具有get和set方法,不是一个响应式所以界面不刷新
解决:Vue.set() 向响应式对象中添加一个
property,并确保这个新
property同样是响应式的
vue3通过proxy劫持和reflect映射实现响应式,不会有这个问题
18.vue组件通讯方式
- 通过 props 传递 - props校验:name:{type:String,required:true,default:默认值} required是否必要
- 通过 $emit 触发自定义事件
- 使用 ref
- EventBus
- Provide 与 Inject
- Vuex
19.vue3setup的父传子怎么去写?
介绍三种方法:
第一种:使用vue2写法通过props和$emit
第二种:setup函数写法
- setup(props,context),通过props接收数据,通过context.emit(‘调用父组件方法’,传递参数)
第三种:script中setup
- vue3自带defineProps,defineEmits
const emits = defineEmits(["changeNumber"]); // 也可以不赋值,取值通过{{num}}获取 const props = defineProps({ num: { type: Number, default: () => [], }, list: { type: Array, }, }); const changeNum = function () { emits("changeNumber", 888); // console.log(11111111111); };
20.setup可不可以直接写async和await?
可以
setup 语法糖中可直接使用 await,不需要写 async , setup 会自动变成 async setup
<script setup>import Api from'../api/Api'const data =await Api.getData() console.log(data)</script>
21.vue生命周期
vue2
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qlfjtF6I-1685109549653)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1685089235304.png)]](https://img-blog.csdnimg.cn/f9c692f63fb84948b79a5de9bd173ee0.png)
beforeCreate – 首次访问data
created – 首次访问this生命周期
mounted – 页面展示
vue3
![[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7tHeS6mz-1685109549654)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\1685089301710.png)]](https://img-blog.csdnimg.cn/863ebacfed9644d49a0ea1182b5b165b.png)
区别
:
- beforeCreate -> setup() 开始创建组件之前,创建的是data和method
- created -> setup()
- beforeMount -> onBeforeMount 组件挂载到节点上之前执行的函数。
- mounted -> onMounted 组件挂载完成后执行的函数
- beforeUpdate -> onBeforeUpdate 组件更新之前执行的函数。
- updated -> onUpdated 组件更新完成之后执行的函数。
- beforeDestroy -> onBeforeUnmount 组件挂载到节点上之前执行的函数。
- destroyed -> onUnmounted 组件卸载之前执行的函数。dszhuoyi
- activated -> onActivated 组件卸载完成后执行的函数
- deactivated -> onDeactivated
22.说说 Vue 中 CSS scoped 的原理
添加scoped标签后会给组件中所有标签元素,添加一个唯一标识,这个唯一标识就是自定义属性,data-v-xxxxxxxx这样的字眼,同时对应的样式选择器也会添加这个唯一的属性选择器
23.$nextTick原理
在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM
nextTick原理
24.data是函数不是对象
vue是一个单页面应用最终所有的实例都会挂载到app.vue文件,如果data是一个对象那么会导致数据污染。通过函数返回对象的方式,利用函数作用域的限制避免数据污染
25.路由守卫
vue路由守卫分为三种:全局路由守卫,独享路由守卫,组件路由守卫
to: 进入到哪个路由去
from: 来自哪个路由
next:是否跳转
- 全局守卫: router.beforeEach((to,from,next)=>{})
- 独享路由守卫: beforeEnter:(to,from,next)=>{}
- 组件路由守卫: beforeRouteEnter:(to,from,next)=>{}, beforeRouteUpdate , beforeRouteLeave
26.vue设置全局变量
方法一:
vue2.x挂载全局是使用Vue.prototype.$xxxx=xxx的形式来挂载,然后通过this.$xxx来获取挂载到全局的变量或者方法。Vue 3中,使用config.globalProperties、app.config.globalProperties.$data = ‘111’const{proxy}=getCurrentInstance() console.log(proxy.$data)方法二:
- provide/inject
27.vue中keep-alive
属性:
include和
exclude语法:
// 指定home组件和about组件被缓存<keep-alive include="home,about"><router-view></router-view></keep-alive>// 除了home组件和about组件别的都缓存<keep-alive exclude="home,about"><router-view></router-view></keep-alive>钩子函数:
activated当组件被激活(使用)的时候触发 可以简单理解为进入这个页面的时候触发deactivated当组件不被使用(inactive状态)的时候触发 可以简单理解为离开这个页面的时候触发进入开启缓存的组件
初始进入和离开 created ---> mounted ---> activated --> deactivated 后续进入和离开 activated --> deactivated
28.vue插槽
slot又名插槽,是Vue的内容分发机制,组件内部的模板引擎使用slot元素作为承载分发内容的出口。插槽slot是子组件的一个模板标签元素,而这一个标签元素是否显示,以及怎么显示是由父组件决定的。slot又分三类,默认插槽,具名插槽和作用域插槽。
默认插槽:又名匿名插槽,当slot没有指定name属性值的时候一个默认显示插槽,一个组件内只有有一个匿名插槽。
具名插槽:带有具体名字的插槽,也就是带有name属性的slot,一个组件可以出现多个具名插槽。
作用域插槽:默认插槽、具名插槽的一个变体,可以是匿名插槽,也可以是具名插槽,该插槽的不同点是在子组件渲染作用域插槽时,可以将子组件内部的数据传递给父组件,让父组件根据子组件的传递过来的数据决定如何渲染该插槽。
实现原理:当子组件vm实例化时,获取到父组件传入的slot标签的内容,存放在vm.
s l o t 中,默认插槽为 v m . slot中,默认插槽为vm. slot中,默认插槽为vm.slot.default,具名插槽为vm. s l o t . x x x , x x x 为插槽名,当组件执行渲染函数时候,遇到 s l o t 标签,使用 slot.xxx,xxx 为插槽名,当组件执行渲染函数时候,遇到slot标签,使用 slot.xxx,xxx为插槽名,当组件执行渲染函数时候,遇到slot标签,使用slot中的内容进行替换,此时可以为插槽传递数据,若存在数据,则可称该插槽为作用域插槽。
29.vue2和vue3区别
双向绑定更新
vue2 的双向数据绑定是利⽤ES5 的⼀个 API ,Object.defineProperty()对数据进⾏劫持 结合 发布订阅模式的⽅式来实现的。
vue3 中使⽤了 ES6 的 ProxyAPI 对数据代理,通过 reactive() 函数给每⼀个对象都包⼀层 Proxy,通过 Proxy 监听属性的变化,从⽽ 实现对数据的监控。
这⾥是相⽐于vue2版本,使⽤proxy的优势如下
1.defineProperty只能监听某个属性,不能对全对象监听 可以省去for in、闭包等内容来提升效率(直接绑定整个对象即可)
2.可以监听数组,不⽤再去单独的对数组做特异性操作,通过Proxy可以直接拦截所有对象类型数据的操作,完美⽀持对数组的监听。
获取props
vue2在script代码块可以直接获取props,vue3通过setup指令传递
API不同
Vue2使⽤的是选项类型API(Options API),Vue3使⽤的是合成型API(Composition API)
建立数据data
vue2是把数据放入data中,vue3就需要使用一个新的setup()方法,此方法在组件初始化构造得时候触发。
生命周期不同
vue2 -------- vue3
beforeCreate -> setup() 开始创建组件之前,创建的是data和method
created -> setup()
beforeMount -> onBeforeMount 组件挂载到节点上之前执行的函数。
mounted -> onMounted 组件挂载完成后执行的函数
beforeUpdate -> onBeforeUpdate 组件更新之前执行的函数。
updated -> onUpdated 组件更新完成之后执行的函数。
beforeDestroy -> onBeforeUnmount 组件挂载到节点上之前执行的函数。
destroyed -> onUnmounted 组件卸载之前执行的函数。dszhuoyi
activated -> onActivated 组件卸载完成后执行的函数
deactivated -> onDeactivated
是否支持碎片:vue2.0 只允许有一个根标签,vue3.0支持碎片化,可以拥有多个根节点
main.js文件不同:vue2中我们可以使用pototype(原型)的形式去进行操作,引入的是构造函数 vue3中需要使用结构的形式进行操作,引入的是工厂函数
diff算法不同
更好的支持ts
30.Vue3.0 所采用的 Composition Api (组合式)与 Vue2.x 使用的 Options Api(选项式) 有什么不同?
- options Api 当组件变得复杂,导致对应属性的列表也会增长,这可能会导致组件难以阅读和理解 。composition Api它将功能定义在一起,利于查找和理解
Composition API对tree-shaking友好,代码也更容易压缩Composition API中见不到this的使用,减少了this指向不明的情况- 如果是小型组件,可以继续使用
Options API,也是十分友好的
31.vue3中hook
本质是一个函数,把setup函数中使用的Composition API(组合式api)进行了封装,类似于vue2中的mixin
自定义hook优势:复用代码,让setup中的逻辑更清楚易懂
32.vue组件和插件的区别
组件: Vue 组件是一个可复用的 Vue 实例,可以带有自己的状态和方法。组件可以包含其他组件,从而形成一个复杂的 UI 列表。
优点
- 可以将代码封装成一个可复用的组件,提高开发效率。
- 组件具有良好的可维护性,易于修改和更新。
缺点
- 组件的功能和作用比较独立,不太适用于全局功能的扩展。
- 组件的管理和组织需要一定的规范,否则可能会导致混乱和不易维护。
插件: Vue 插件可以扩展 Vue 的全局功能,在应用程序中可以重复使用。常见的插件如
vue-router、
vuex、
axios等。
优点
- 插件可以方便地扩展 Vue 的全局功能。
- 插件可以使代码重复利用,提高开发效率。
- 开源社区中已经有大量的插件可以用于解决常见的问题。
缺点
- 插件具有一定的复杂性,需要更多的学习成本。
- 插件功能可能比较复杂,可能会导致性能下降。
33.vue修饰符
在
Vue中,修饰符处理了许多
DOM事件的细节,让我们不再需要花大量的时间去处理这些烦恼的事情,而能有更多的精力专注于程序的逻辑处理
- 表单修饰符 - .lazy 懒加载,光标离开标签时,才赋值给value- .trim 过滤首位空格- .number 限制输入类型为数字或转为数字
- 事件修饰符 - .stop 阻止事件冒泡- .prevent 组织事件默认行为- .once 事件只触发一次- .capture 开启事件捕获- .self 事件只在自身触发
- 鼠标按键修饰符 - left 左键点击- right 右键点击- middle 中键点击
- 键值修饰符 - 普通键(enter、tab、delete、space、esc、up…)- 系统修饰键(ctrl、alt、meta、shift…)
- v-bind修饰符 - .async 对props进行双向绑定- .prop 设置自定义标签属性,避免暴露数据,防止污染html结构- .camel 将命名为驼峰命名法
34.Vue路由中,history和hash两种模式有什么区别?
hash: hash 模式是一种把前端路由的路径用井号
#拼接在真实 URL 后面的模式。当井号
#后面的路径发生变化时,浏览器并不会重新发起请求,而是会触发
hashchange事件。
- 优点:浏览器兼容性较好,连 IE8 都支持
- 缺点:路径在井号
#的后面,比较丑history: history API 是 H5 提供的新特性,允许开发者直接更改前端路由,即更新浏览器 URL 地址而不重新发起请求
- 优点:路径比较正规,没有井号
#- 缺点:兼容性不如 hash,且需要服务端支持,否则一刷新页面就404了
35.params和query区别
params和
query都是用于传递参数的,但它们的传参方式和使用场景是不同的。
params通过路由路径传递参数,在路由配置中使用
:paramName的形式进行声明
const router =newVueRouter({routes:[{path:'/user/:id',component: User,},],})query通过 URL 查询字符串(即问号后面的部分)传递参数,在路由地址后面使用
?连接多个参数键值对
不需要在router中配置
/search?q=vue会自动匹配到search组件
区别:
params适合用于必须存在的参数传递,例如用户详情页或文章详情页的访问。query适合用于可选的参数传递,例如搜索功能中关键词的传递。
36.vue2中assets和vue3中public区别 ?
在 Vue 2 中,
assets目录是默认存在的,可以直接在项目的根目录下创建,它通常用来存放组件需要的图片、样式等静态资源文件。这些文件会被打包到 JavaScript 文件中,在代码中使用相对路径引用。
在 Vue 3 中,可以通过配置
vue.config.js文件来设置
public目录,它的作用与
assets目录类似,用来存放静态资源文件。但是,与 Vue 2 不同的是,
public目录下的文件不会被打包,而是会直接复制到输出目录下
37.单页应用如何提高加载速度?
- 使用代码分割:将代码拆分成小块并按需加载(懒加载),以避免不必要的网络请求和减少加载时间。
- 缓存资源:利用浏览器缓存来存储重复使用的文件,例如 CSS 和 JS 文件、图片等。
- 预加载关键资源:在首次渲染之前,先提前加载关键资源,例如首页所需的 JS、CSS 或数据,以保证关键内容的快速呈现。
- 使用合适的图片格式:选择合适的图片格式(例如 JPEG、PNG、WebP 等),并根据需要进行压缩以减少文件大小。对于一些小图标,可以使用
iconfont等字体文件来代替。- 启用 Gzip 压缩:使用服务器端的 Gzip 压缩算法对文件进行压缩,以减少传输时间和带宽消耗。
- 使用 CDN:使用内容分发网络(CDN)来缓存和传递文件,以提高文件的下载速度和可靠性。
- 优化 API 请求:尽可能地减少 API 调用的数量,并使用缓存和延迟加载等技术来优化 API 请求的效率。
- 使用服务器端渲染:使用服务器端渲染(SSR)来生成 HTML,以减少客户端渲染所需的时间和资源。但需要注意,SSR 也可能增加了服务器的负担并使网站更复杂。
38.Vue父组件调用子组件的方法
vue中如果父组件想调用子组件的方法,可以在子组件中加上ref,然后通过this.$refs.ref.method调用
<child ref="child"></child> 调用:this.$refs.child.子组件方法
39.vue3中dom获取,ref在组件上使用
<template><div class="ref"><h3>ref使用:</h3><input type="text" ref="input"/>// ref="input" 需要和 const input = ref(null); 相对应</div></template><script setup>import{ reactive, ref, createApp, onMounted }from"vue";let state =reactive({text:"信息按钮"});// 同名的 input来进行获取节点const input =ref(null);onMounted(()=>{if(input.value){ input.value.focus();}});</script><style scoped></style>
40.渐进式框架理解
渐进式: 可以理解为没有多做职责之外的事
个人理解:主张最少的,一开始仅基于基础框架构建,随着需求不断扩充
41.页面初始化闪烁
产生原因:当网速较慢,
vue.js文件还没有加载完时,在页面上会显示{{message}}的字样,知道vue创建实例,编译模板时,dom才会被替换,所以这个过程屏幕是闪动的。
所以解决这个问题,需要在style样式中设置【v-cloak】{display:none}。在一般情况下,v-clock是一个解决初始化慢导致页面闪动的最佳实践,对于简单的项目很实用。
但是在具有工程化的项目里,比如使用了webpack和vue-router的项目中,html结构只是一个空的div元素,剩余的内容都是由路由去挂载不同的组件完成的,所以不需要v-cloak。
42.vue属性名和method名称一致出现什么问题
vue2中, 这个
属性会覆
盖掉 methods中的方法。也就是说,这个方法将无法被正确调用。
vue3中,报错
43.class和style如何动态绑定
class 与 style 动态绑定一般通过对象或者数组来实现
对象写法:适用于要绑定的样式名字样式确定,但动态决定用不用。
数组写法:适用于要绑定的样式名字样式不确定。
<div v-bind:class="{ active: isActive }"></div>//对象写法<div v-bind:class="[activeClass, errorClass]"></div>//数组写法
44.vue遇到的坑
- data必须是一个函数,而不是一个对象
- vue管理的函数不要写成箭头函数
- 添加属性页面不刷新
- 子路由path不需要添加**/**,path=‘new’
45.v-if和v-for 优先级
实践中不管是vue2或者vue3都不应该把v-if和v-for放在一起使用。
在 vue 2.x 中,在一个元素上同时使用 v-if 和 v-for 时, v-for 会优先作用。
在 vue 3.x 中, v-if 总是优先于 v-for 生效。
vue2中v-for的优先级是高于v-if的,放在一起,会先执行循环在判断条件,并且如果值渲染列表中一小部分元素,也得再每次重渲染的时候遍历整个列表,比较浪费资源。
vue3中v-if的优先级是高于v-for的,所以v-if执行时,它调用相应的变量如果不存在,就会导致异常
46.vue核心原理
数据驱动,组建系统
47.vue自带动画组件, transition
组件是 Vue 提供的用于包裹需要动画效果的元素组件。使用组件可以方便地实现元素的进入和离开动画效果。
<template><div><button @click="visible = !visible">Toggle</button><transition name="fade"><p v-if="visible">Hello, World!</p></transition></div></template><script>exportdefault{data(){return{visible:false}},}</script><style>.fade-enter-active,.fade-leave-active {transition: opacity .5s;}.fade-enter,.fade-leave-to {opacity:0;}</style>
48.vue-loader工作原理
- 将一个 .vue 文件 切割成 template、script、styles 三个部分。
- template 部分 通过 compile 生成 render、 staticRenderFns。
- 获取 script 部分 返回的配置项对象 scriptExports。
- styles 部分,会通过 css-loader、vue-style-loader, 添加到 head 中, 或者通过 css-loader、MiniCssExtractPlugin 提取到一个 公共的css文件 中。
- 使用 vue-loader 提供的 normalizeComponent 方法, 合并 scriptExports、render、staticRenderFns, 返回 构建vue组件需要的配置项对象 - options, 即 **{data, props, methods, render, staticRenderFns…}**。
49.vue的diff算法
diff整体策略为:深度优先,同层比较
- 当数据发生改变时,订阅者
watcher就会调用patch给真实的DOM打补丁- 通过
isSameVnode进行判断,相同则调用patchVnode方法- patchVnode做了以下操作:- 找到对应的真实
dom,称为el- 如果都有都有文本节点且不相等,将el文本节点设置为Vnode的文本节点- 如果oldVnode有子节点而VNode没有,则删除el子节点- 如果oldVnode没有子节点而VNode有,则将VNode的子节点真实化后添加到el- 如果两者都有子节点,则执行updateChildren函数比较子节点- updateChildren主要做了以下操作:- 设置新旧
VNode的头尾指针- 新旧头尾指针进行比较,循环向中间靠拢,根据情况调用patchVnode进行patch重复流程、调用createElem创建一个新节点,从哈希表寻找key一致的VNode节点再分情况操作
版权归原作者 夜斗(dou) 所有, 如有侵权,请联系我们删除。