目录
2、VUE 中什么是组件,为什么要封装组件?组件中 data 为什么是一个函数?
19、为什么 Vuex 的 mutation 不能做异步操作
1、MVVM
MVVM是Model-View-ViewModel的简写,即模型-视图-视图模型。【模型】指的是后端传递的数据。【视图】指的是所看到的页面。【视图模型】mvvm模式的核心,它是连接view和model的桥梁。它有两个方向:一是将【模型】转化成【视图】,即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。二是将【视图】转化成【模型】,即将所看到的页面转化成后端的数据。实现的方式是:DOM 事件监听。这两个方向都实现的,我们称之为数据的双向绑定。
总结:在MVVM的框架下视图和模型是不能直接通信的。它们通过ViewModel来通信,ViewModel通常要实现一个observer观察者,当数据发生变化,ViewModel能够监听到数据的这种变化,然后通知到对应的视图做自动更新,而当用户操作视图,ViewModel也能监听到视图的变化,然后通知数据做改动,这实际上就实现了数据的双向绑定。并且MVVM中的View 和 ViewModel可以互相通信。
m->model,v->view,vm->viewModel。dom通过监听事件操作vue里的data,反之vue中的data通过指令操作dom,这就是所说数据驱动视图,这就是mvvm的理解。
2、VUE 中什么是组件,为什么要封装组件?组件中 data 为什么是一个函数?
1)为什么要封装组件?
主要就是为了解耦,提高代码复用率。
2)什么是组件?
页面上可以复用的都称之为组件 它是 HTML、CSS、JS 的聚合体。 组件就相当于库,把一些能在项目里或者不同项目里可以复用的代码进行需求性的封装。
3)组件中的 data 为什么是一个函数?
让每个返回的实例都可以维护一份被返回对象的独立的拷贝。
3、vue.js的两个核心
数据驱动,组件系统
4、vue生命周期
beforeCreate-created-beforeMount-mounted-beforeUpdate-update-beforeDestroy-destroyed
Vue 实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。
1)beforeCreate(){}
创建前,访问不到data当中的属性以及methods当中的属性和方法,可以在当前生命周期创建一个loading,在页面加载完成之后将loading移除
2)created(){}
创建后,当前生命周期执行的时候会遍历data中所有的属性,给每一个属性都添加一个getter、setter方法,将data中的属性变成一个响应式属性
当前生命周期执行的时候会遍历data&&methods身上所有的属性和方法,将这些属性和方法代理到vue的实例身上
在当前生命周期中我们可以进行前后端数据的交互(ajax请求)
拓展 axios与jquery的ajax有什么不同
axios的优点:
a、从nodejs中创建http请求
b、支持promiseAPI
c、提供了一些并发请求的接口
d、自动转换json数据
e、客户端支持防止CSRF/XSRF
ajax的缺点:
a、jQuery项目庞大,单纯的使用ajax却要引入整个Jquery非常不合理
b、基于原生的XHR开发,但是XHR架构并不清晰
3)beforeMount(){}
模板与数据进行结合,但是还没有挂载到页面上。因此我们可以在当前生命周期中进行数据最后的修改
4)mounted(){}
当前生命周期数据和模板进行相结合,并且已经挂载到页面上了,因此我们可以在当前生命周期中获取到真实的DOM元素
如何获取DOM元素
a、给元素添加一个ref属性值必须是唯一的
b、使用:this.$refs.属性
还可以在当前生命周期中做方法的实例化
5)beforeUpdate(){}
当数据发生改变的时候当前生命周期就会执行,因此我们可以通过当前生命周期来检测数据的变化 当前生命周期执行的时候会将更新的数据与模板进行相结合,但是并没有挂载到页面上,因此我们可以在当前生命周期中做更新数据的最后修改
6)updated(){}
数据与模板进行相结合,并且将更新后的数据挂载到了页面上。因此我们可以在当前生命周期中获取到最新的DOM结构
在当前生命周期中如果做实例化操作的时候切记要做条件判断
7)beforeDestroy(){}
当前生命周期中我们需要做事件的解绑 监听的移除 定时器的清除等操作
8)destroyed(){}
5、描述vue组件声明周期
1)单组件声明周期图
挂载: beforeCreate => created => beforeMount => mounted
更新: beforeUpdate => updated
销毁: beforeDestroy => destroyed
2)父子组件生命周期图
挂载: parent beforeCreate => parent created => parent beforeMount => child beforeCreate => child created => child beforeMount => child mounted => parent mounted
更新: parent beforeUpdate => child beforeUpdate => child updated => parent updated
销毁: parent beforeDestroy => child beforeDestroy => child destroyed => parent destroyed
从以上能够看出:
挂载时,子组件是在父组件before mount后开始挂载,并且子组件先mounted,父组件随后
更新时,子组件是在父组件before update后开始更新,子组件先于父组件更新 销毁时,子组件是在父组件before destroy后开始销毁,并且是子组件先销毁,父组件随后
6、双向数据绑定v-model的实现原理
双向数据绑定最核心的方法便是通过Object.defineProperty()来实现对属性的劫持,达到监听数据变动的目的
先是从data里面的数据msg通过绑定到input控件和p标签上。然后input上通过v-on:input监听控件,触发change()。
调用方法都可以默认获取e事件,e.target.value是获取调用该方法的DOM对象的value值。把value值在赋给data里的msg,就是实现了双向数据绑定的原理了。
7、vue中事件绑定的原理
1)原生dom事件的绑定,采用的是addEventListener实现
a)vue在创建真是dom时会调用createElm,默认会调用invokeCreateHooks
b)会遍历当前平台下相对的属性处理代码,其中就有updateDOMListeners方法,内部会传入add方法
2)组件绑定事件采用的是$on方法
8、vue组件如何通信
父子通信:
父向子传递数据是通过 props,子向父是通过 events($emit);
通过父链 / 子链也可以通信($parent / $children);
ref 也可以访问组件实例;
provide / inject API;
$attrs/$listeners
vuex
兄弟通信:
事件总线Bus;
Vuex
跨级通信:
事件总线Bus;
Vuex;
provide / inject API
$attrs/$listeners
9、Vue组件中的Data为什么是函数,根组件却是对象呢?
当前生命周期执行完毕后会将vue与页面之间的关联进行断开 如果data是一个函数的话,这样每复用一次组件,就会返回一份新的data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有组件实例共用了一份data,就会造成一个变了全都会变的结果。 所以说vue组件的data必须是函数。这都是因为js的特性带来的,跟vue本身设计无关。
10、computed和 watch
watch:一个数据影响多个数据,当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
computed:一个数据受多个数据影响,是基于它的响应式依赖进行缓存的,只在相关响应式依赖发生改变时它们才会重新求值。
11、v-if和v-show区别
v-show通过css display控制显示和隐藏,v-if组件真正的渲染和销毁,而不是显示和隐藏,频繁切换状态使用v-show 否则v-if
v-if 常用于一次性改变,如根据权限决定是否显示
v-show 用于 tabs 切换
v-if 可与 templete块连用 ,v-show 不支持 <template> 元素,也不支持 v-else
v-if 有更高的切换消耗而 v-show 有更高的初始渲染消耗
v-if 是控制元素的添加与删除,而 v-show 只是控制元素的 display 属性。
12、为何v-for要用key
快速查找到节点,减少渲染次数,提升渲染性能
13、Vue3.0的新特性
1)代码结构更清晰
2)压缩包体积更小
3)Object.defineProperty 替换为es6的proxy。将原本对对象属性的操作变为整个对象的操作,可优化性增强
4)启用 TypeScript 语法,大大的简化了代码
14、性能比vue2.x快1.2~2倍如何实现的
1)diff算法更快
vue2.0是需要全局去比较每个节点的,若发现有节点发生变化后,就去更新该节点
vue3.0是在创建虚拟dom中,会根据DOM的内容会不会发生内容变化,添加静态标 记, 谁有flag!比较谁。
2)静态提升
vue2中无论元素是否参与更新,每次都会重新创建,然后再渲染
vue3中对于不参与更 新的元素,会做静态提升,只被创建一次,在渲染时直接复用即可
3)事件侦听缓存
默认情况下,onclick为动态绑定,所以每次都会追踪它的变化,但是因为是同一函数,没有必要追踪变化,直接缓存复用即可 在之前会添加静态标记会把点击事件当做动态属性会进行diff算法比较, 但是在事件监听缓存之后就没有静态标记了,就会进行缓存复用
15、为什么vue3.0体积比vue2.x小
在vue3.0中创建vue项目 除了vue-cli,webpack外还有一种创建方法是Vite Vite是作者开发的一款有意取代webpack的工具,其实现原理是利用ES6的import会发送请求去加载文件的特性,拦截这些请求,做一些预编译,省去webpack冗长的打包时间
16、Vue中 keep-alive 的作用
keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。一旦使用keepalive包裹组件,此时mouted,created等钩子函数只会在第一次进入组件时调用,当再次切换回来时将不会调用。此时如果我们还想在每次切换时做一些事情,就需要用到另外的周期函数,actived和deactived,这两个钩子函数只有被keepalive包裹后才会调用。
17、前端路由的hash模式和history模式有什么区别
1)hash模式
在浏览器中符号“#”,#以及#后面的字符称之为hash,用window.location.hash读取; 注意:hash虽然在URL中,但不会提交给服务器端, 只在浏览器端使用
2)history模式
路由路径中没有#, 利用HTML5的新特性: pushState()/replaceState()及popState事件监听
注意: 路径会提交给后台, 在生产环境下会出现404的问题
解决404问题: 后台服务器端配置404页面或通过自定义中间件指定404页面为index.html页面
18、vuex中怎么异步请求的?
vuex中的异步方法,例如请求都要在actions中声明,通过解构出commit参数,再将请求返回的数据通过commit提交到mutations中声明的方法进行修改state中的数据
19、为什么 Vuex 的 mutation 不能做异步操作
vuex 中所有的状态更新的唯一途径都是 mutation,异步操作通过 Action 来提交 mutation 实现,这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够使用一些工具帮助我们更好地了解我们的应用。每一个 mutation 执行完成后都会对应到一个新的状态变更,这样 devtools 就可以打个快照存下来。如果 mutation 支持异步操作,无法被 devtools 所监测,就没有办法知道状态是何时更新的,无法很好的进行状态的追踪,给调试带来困难
20、Webpack
https://webpack.docschina.org/concepts/ https://baijiahao.baidu.com/s?id=1706629892058057497&wfr=spider&for=pc&searchword=webpack%E9%9D%A2%E8%AF%95%E9%A2%98
21、Vue的性能优化
尽量减少data中的数据,data中的数据都会增加getter和setter,会收集对应的watcher
v-if和v-for不能连用
如果需要使用v-for给每项元素绑定事件时使用事件代理
SPA页面采用keep-alive(K普懒死)缓存组件
在更多的情况下,使用v-if替代v-show
key保证唯一
使用路由懒加载、异步组件
防抖、节流
第三方模块按需导入
长列表滚动到可视区域动态加载
图片懒加载
SEO优化
预渲染
服务端渲染SSR
打包优化
压缩代码
Tree Shaking/Scope Hoisting
使用cdn加载第三方模块
多线程打包happypack
splitChunks抽离公共文件
sourceMap优化
用户体验
骨架屏
PWA