日常知识点总结(vue篇):
1、vue的生命周期:
Vue实例从开始创建,初始化数据,编译模板,挂载Dom->渲染,更新->渲染,卸载等一系列过程,我们称这是Vue的生命周期。
作用:生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑。
1)beforeCreate( ) ;
实例创建前,这个阶段实例的data,method是读不到的
2)created( );
实例创建后,这个阶段已经完成了数据观测(data observer),属性和方法的运算,watch/event事件回调.mount挂载阶段还没开始,$el属性目前不可见,数据并没有在Dom元素上进行渲染.
3)beforeMount( );
在挂载开始之前被调用,相关的render函数首次被调用.
4)mounted( );
el选项的Dom节点被新创建的vm.$el替换,并挂载到实例上去之后调用此生命周期函数.此时实例的数据在Dom节点上进行渲染.
5)beforeUpdate( );
数据更新时调用,但不进行Dom重新渲染,在数据更新时Dom没渲染前可以在这个生命函数里进行状态处理
6)updated( );
这个状态下数据更新并且Dom重新渲染,当这个生命周期函数被调用时,组件Dom已经更新,所以你现在可以执行依赖于Dom的操作.当实例每次进行数据更新时updated都会执行.
7)beforeDestory( );
销毁前执行(实例仍然完全可用)。可以做一个确认停止事件的确认框。
8)destoryed( );
Vue实例销毁后调用.调用后,vue实例指示的所有东西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁.
Vue每个生命周期阶段可以做的事:
created:实例已经创建完成,因为它是最早触发的原因可以进行一些数据,资源的请求。
mounted:实例已经挂载完成,可以进行一些Dom操作。
beforeUpdate:可以在这个钩子中进一步的更改状态,这不会触发附加的重渲染过程。
updated:可以执行依赖于Dom的操作。然而在大多数情况下,你应该避免在此期间更改状态,因为这可能会导致更新无线循环。该钩子在服务端渲染期间不被调用。
beforeDestory:可以执行一些优化操作,清空定时器,解除绑定事件。
nextTick:针对单一事件更新数据后立即操作dom
watch: 监听具体数据变化,并做相应的处理
2、vue响应式原理:
当一个vue实例创建时,vue会遍历data选项的属性,用Object.defineProperty将它们转为getter/setter并且在内部追踪相关依赖,在属性被访问和修改时通知变化。每个组件实例内部都有相应的watcher程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的setter被调用时,会通知watcher重新计算,从而致使它关联的组件得以更新。
3、vue双向数据绑定原理:
vue.js是采用数据劫持结合“发布者---订阅者”模式的方式,通过Object.defineProperty( )来劫持各个属性的setter、getter,在数据变动时发布消息给订阅者,触发相应的监听回调。
具体步骤:
1)需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上setter和getter这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到数据变化。
2)compile解析模板指令,将模板中的变量替换成数据,然后初始化 渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图。
3)Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:在自身实例化时往属性订阅器(dep)里面添加自己,自身必须有一个update( )方法,待属性变动dep.notice( )通知时,能调用自身的update( )方法,并触发Compile中绑定的回调,则功成身退。
4)MVVM作为数据绑定的入口,整合Observe,Compile和Watcher三者,通过Observe来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observe和Compile之间的通信桥梁,达到数据变化-->视图更新;视图交互变化(input)-->数据model变更的双向绑定效果。
4、vue的组件通信:
1)父子间通信,父 -> 子通过props,子 -> 父$on,$emit(发布-订阅)
2)获取父子组件实例的方式$parent,$children
3)在父组件中提供数据子组件进行消费 Provide,inject(写插件用较多)
provide( ) { someval:'来自低级组件的数据'}
inject:['somaval']
4)Ref获取实例的方式调用组件的属性或者方法
5)Event Bus 实现跨组件通信
非父子组件/兄弟组件之间的数据传递:
/*新建一个Vue实例作为中央事件*/
let event = new Vue();
/*监听事件 */
event.$on('eventName',(val) => {
//.......do something
})
/*触发事件 */
event.$emit('eventName','这是一条消息。')
6)vuex:状态管理实现通信。服务器设置session服务器返回给客户端的信息在响应头中带着set-cookie='connect.sid'客户端会把信息种植到本地的cookie中httponly客户端再次向服务器发送请求的时候,会默认在请求头中cookie把connect.sid传递发给服务器
5、Vuex是什么:
定义:Vuex是专门为vue.js应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态。
状态自管理应用包含以下几个部分:
State,是 Vuex 这一状态管理工具的唯一的数据源,所有的数据都储存在里面。
Getter,对数据获取之前的再次编译,可以理解为state的计算属性,
在组件中使用$store.getters.fun( )。
Mutation ,是同步更新数据(内部会进行是否为异步方式更新数据的检测)。$watch严格模式下会报错
在组件中使用$store.commit(" ",params)。
Action,异步操作,可以获取数据后调用mutation提交最终数据
在组件中使用$store.dispath(" ")。
Module,当应用非常复杂时,可以把整个store拆分成几个模块(module),每个module中都可以含有各自的state,getter,mutation,action
vuex的使用:
1)在src目录下创建vuex文件夹,并在文件夹下创建一个store.js文件。
2)下载,并引入vuex。
3)在store.js文件中,引入vuex并且使用vuex。
4)在main.js中引入store并Vue.use(Vuex)。
使用场景:单页应用中,组件之间的状态。音乐播放,登录管理,加入购物车。
6、vue-loader是什么,什么用途:
vue-loader是基于webpack的一个loader(加载器),解析和转换.vue文件,提取出其中的逻辑代码script,样式代码style,以及HTML模板template,再分别把它们交给对应的loader去处理,核心的作用,就是提取,划重点。
webpack的loader,其实就是用来打包,转译js或者css文件,简单的说就是把写的代码转换成浏览器能识别的,还有一些打包,压缩的功能等。
vue-loader的作用:
1)允许为Vue组件的每个部分使用其它的webpack loader,例如在<style>的部分使用Sass和在<template>的部分使用Pug
2)允许在一个.vue文件中使用自定义块,并对其运用系定义的loader链
3)使用webpack loader将<style><template>中引入的资源当作模块依赖来处理
4)为每个组件模拟出scoped CSS
5)在开发过程中使用热重载来保持状态
7、vue-router的路由模式:
vue-router中默认使用的时hash模式,也就是URL中带有#号,使用mode:"history"修改为history模式。
实际上存在三种模式:
Hash: 使用URL的hash值来作为路由。支持所有浏览器。
History: 以来HTML5 History API 和服务器配置。参考官网中HTML5 History模式
Abstract: 支持所有javascript运行模式。如果发现没有浏览器的API,路由会自动强制进入这个模式。
hash模式:
背后的原理时onhashchange事件。因为hash发生变化的url都会被浏览器记录下来,因此浏览器的前进后退都可以用的。尽管浏览器没有请求服务器,但是页面状态和url----关联起来,被称为前端路由。
history路由:
historyAPI分为两大部分:切换(history.go() /history.back() /history.forward() ),
修改历史状态(pushState( stateObj,title,url) / replaceState(stateObj,title,url))
8、$router与$route的区别
$router,是路由实例对象。为VueRouter实例,想要跳转导航到不同URL,则使用$router.push( )方法,传入参数为字符串/对象。
$route,是路由信息对象。为当前router跳转对象里面可以获取name, path, query, params等。
params 和query 的传参及使用:
1) 使用query传参的时候,name,path都可以引入,但使用params传参的时候只能使用name进行引入.
2) 接收参数的时候使用this.$route.params.name或者this.$route.query.name
3) 进行路由跳转的时候,我们使用this.$router.push('路径')
4) 如果index.js配置路由时,我们能看到,params的参数是URL不可或缺的一部分,但是query的参数是拼起来的,没有也不影响.
9、用vue-cli初始化一个vue项目里的各个文件都是什么作用(从上到下依次说明):
node_modules:项目依赖的第三方node包
public:
src:放的是整个项目的源代码
1)main.js:是整个项目的入口文件
2)APP.vue:项目最开始的根组件
3)router:项目所有路由都放在router下的index.js文件里
4)store:
5)views:
6)components:放的是项目中用到的小组件
7)assets:项目里要用到的图片资源
8)config:项目里的配置文件,基础配置在index.js里,开发环境的配置在dev.env.js
9)build.js:项目打包的webpack配置内容
editorconfig:配置编辑器里的语法,里面可以自定义内容,可统一编辑器自动格式化代码。
eslintrc.js:代码的规范,看代码是否标准
gitignore:使用git希望把代码放到线上,但是一些特殊的文件并不想或者不需要传到线上,就可以把它配置到gitgnore文件里,当提交到git仓库文件时,这里的文件就不会被提交到git线上仓库;
babel.config.js:语法解析器
package-lock.json:package的锁文件,确定安装的第三方包版本,为了统一团队的编码;
package.json:这是一个依赖包,也就是第三方模块依赖存放处;
README.md:项目说明文件
10、v-show和v-if指令的共同点和不同点:
v-show指令是通过修改元素的display的CSS属性让其显示或者隐藏
v-if 指令是直接销毁和重建DOM达到让元素显示和隐藏的效果
使用v-show会更加节省性能上的开销;当只需要一次显示或隐藏时,使用v-if更加合理。
v-for与v-if不同在同一层级,在使用时,v-for的优先级比v-if高,会先循环,然后给每一个循环后的节点,添加v-if。
11、NextTick是做什么的
$nextTick是在下次DOM更新循环结束之后执行延迟回调,在修改数据之后使用$nextTick,则可以在回调中获取更新后的DOM。
12、对比jQuery, Vue有什么不同
jQuery专注视图层,通过操作DOM去实现页面的一些逻辑渲染;
Vue专注于数据层,通过数据的双向绑定,最终表现在DOM层面,减少DOM操作;
Vue使用了组件化思想,使得项目子集职责清晰,提高了开发效率,方便重复利用,便于协同开发。
12、Vue中computed和watch的区别:
computed(计算属性):
1)不支持异步,当computed内有异步操作时无效,无法监听数据的变化。
2)简化template里面{{ }}计算和处理props或$emit的传值。
3)具有缓存性,页面重新渲染值不变化,计算属性会立即返回之前的计算结果,而不必再次执行函数。
watch(侦听属性):
1)watch支持异步,监听props, $emit或本组件的值执行异步操作。
2)监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作。监听的函数接收两个参数,第一个参数是最新的值,第二个参数是输入之前的值。
3)不支持缓存,数据变,直接会触发相应的操作。
13、 计算属性 computed 和事件 methods 有什么区别
将同一函数定义为一个 method 或者一个计算属性。对于最终的结果,两种方式是相同的。
不同点:
computed:计算属性是基于它们的依赖进行缓存的,只有在它的相关依赖发生改变时才会重新求值。
method:只要发生重新渲染, method 调用总会执行该函数。
14、多页面应用与单页面应用的区别:
1)页面的组成
多页面,由多个完整页面,例如:page1.html, page2.html
单页面,由一个初始页面和多个页面模块组成,例如:index.html和page1.html.js, page2.html.js
2)公共文件加载
多页面,跳转页面前后,js/css/img等公用文件重新加载
单页面,js/css/img等公用文件只在加载初始页面时加载,更换页面内容前后无需重新加载
3)页面跳转/内容更新
多页面,页面通过window.location.href = './index.html'跳转
单页面,通过使用js方法,append/remove或者show/hide等方式来进行页面内容的更换
4)页面跳转/内容更新所需要数据的传递
多页面,可以使用路径携带数据传递的方式,或者localstorage,cookie等存储方式
单页面,直接通过参数传递,或者全局变量的方式进行,因为都是在一个页面的脚本环境下
5)用户体验
多页面,如果单个页面加载的文件相对较大(多),页面切换加载会很慢
单页面,页面片段切换较快,用户体验较好,因为初次已经加载好相关文件。但是初次加载页面时需要调整优化,因为加载文件较多。
6)使用场景
多页面,适用于高度追求支持搜索引擎的应用
单页面,高要求的体验度,追求界面流畅的应用
7)专场动画
多页面,不容易实现
单页面,容易实现
总结:单页面模式相较有优势,无论在用户体验还是页面切换的数据传递,页面切换动画,都可以有比较答的操作空间。
15、Vue父子组件生命周期调用顺序:
1)加载渲染过程:
父beforeCreate -> 父created -> 父beforeMount -> 子beforeCreate -> 子created -> 子beforeMount -> 子mounted -> 父mounted
2)子组件更新过程:
父fubeforeUpdate -> 子beforeUpdate -> 子updated -> 父updated
3)父组件更新过程:
父beforeUpdated -> 父updated
4)销毁过程:
父beforeDestory -> 子beforeDestory -> 子destoryed -> 父destoryed
理解:
组件的调用顺序都是先父后子,渲染完成的顺序肯定是先子后父
组件的销毁操作是先父后子,销毁完成的顺序是先子后父
16、 Vue 组件 data 为什么必须是函数
因为 JS 本身的特性带来的,如果 data 是一个对象,那么由于对象本身属于引用类型,当我们修改其中的一个属性时,会影响到所有 Vue 实例的数据。如果将 data 作为一个函数返回一个对象,那么每一个实例的 data 属性都是独立的,不会相互影响了。
17、Vue自定义过滤器
可以用全局方法Vue.filter( )注册一个自定义过滤器,它接收两个参数:过滤器ID和过滤器函数。过滤器函数以值为参数,返回转换后的值。
js:Vue.filter('reverse',function(value){
return value.split('').reverse().join('');
})
html:<span v-text='message | reverse'></span>
18、Vue中自定义指令
全局定义指令:在vue对象的directive方法里面有两个参数,一个是指令名称,另一个是函数。
组件内定义指令:directives
钩子函数:bind(绑定事件出发)/ inserted(节点插入时候触发)/ update(组件内相关更新)
钩子函数参数:el, binding
//注册全局自定义指令,v-focus
Vue.directive('focus',{
//当被绑定的元素插入到DOM中时
inserted: function(el){
//聚焦元素
el.focus()
}
})
//局部注册
directive:{
focus:{
//指令的定义
inserted:function(el){
el.focus();
}
}
}
vuejs里的指令/组件/插件:
组件与指令的区别:
组件,通常都有对应的html代码,表示一块具有特定样式,逻辑和功能的实体。
指令,通常用于给已存在DOM添加相应的行为,例如v-if, v-for等,定义指令的时候一般不需要特定的视图。
组件与插件的区别:
组件,是用来构成你的APP的业务模块,它的目标是App.vue。
插件,是用来增强你的技术栈的功能模块,它的目标是Vue本身。
19、Vue中常见性能优化
1)编码优化:
不要将所有的数据都放在data中,data中的数据都会增加getter和setter,会收集对应的watcher
vue在v-for时给每项元素绑定事件需要用事件代理
SPA页面采用keep-alive缓存组件
拆分组件(提高复用性,增加代码的可维护性,减少不必要的渲染)
v-if当值为false时内部指令不会执行,具有阻断功能,很多情况下使用v-if替代v-show
key保证唯一性(默认vue会采用就地复用策略)
Object.freeze冻结数据
合理使用路由懒加载,异步组件
尽量采用runtime运行时版本
数据持久化的问题(防抖,节流)
2)vue加载性能优化
第三方模块按需导入(babel-plugin-component)
滚动到可视区域动态加载(https://tangbc.github.io/vue-virtual-scroll-list)
图片懒加载(https://github.com/hilongjw/vue-lazyload)
3)用户体验
app-skeleton骨架屏,loading,在加载过程中,可以提供loading图标
app-shell app壳 ,先加载头和底部,给用户正在加载,不过加载较慢的错觉
pwa,serviceWorker
better-click防止iPhone点击延迟,在开发移动端vuejs项目时,手指触摸时会出现300ms的延迟效果,可以采用better-click对ipone系列的兼容体验优化。
4)SEO优化
预渲染插件prerender-spa-plugin
服务端渲染ssr
5)打包优化
使用cdn的方式加载第三方模块
多线程打包happypack
splitChunks抽离公共文件
sourceMap 生成,屏蔽sourceMap,在index.js的通用配置文件分别对开发环境和上线环境做了打包配置分类,在build对象中的配置信息中,productionSourceMap修改成false。
6)缓存,压缩
客户端缓存,服务端缓存
服务端gzip压缩,对于项目代码中的JS/CSS/等文件进行gzip压缩,index.js的通用配置,productionGzip设置为true
20、为什么使用key:
当有相同标签名的元素切换时,需要通过key特性设置唯一的值来标记,让Vue区分它们,否则Vue为了效率只会替换相同标签内部的内容。
21、自定义组件的双向绑定(v-model):绑定value值,监听input事件。
22、Vue组件化的理解:
定义:组件是可复用的Vue实例,准确讲它们是VueComponent的实例,继承自Vue。
优点:组件化可以增加代码的复用性,可维护性和可测试性。
使用场景:
通用组件,实现最基本的功能,具有通用性,复用性,例如按钮组件,输入框,布局组件
业务组件,完成具体业务,具有一定的复用性,例如登录组件,轮播图组件
页面组件,组织应用各部分独立内容,需要时在不同页面组件间切换,例如列表页,详情页组件
如何使用组件:
定义,Vue.component(),components选项,sfc(单文件组件)
分类,有状态组件,fucntional(无状态,函数组件),abstract(抽象组件,没有具体视图)
通信,props,$emit()/$on(),provide/inject,$children/$parent/$root/$attrs/$listeners
内容分发,<slot>,<template>,v-slot (v-slot :后边是插槽名称,=后边是组件内部绑定作用域值的映射。)
使用及优化,is,keep-alive,异步组件
组件的本质:
vue中的组件经历如下过程:组件配置=》VueComponent实例=》render()=》virtual DOM=》DOM
所以组件的本质是产生虚拟DOM
23、动态路由
24、导航守卫:
全局守卫,每次路由跳转都会被触发
router.beforeEach((to,from,next)=>{ //全局前置守卫 });
router.beforeResolve((to,from,next)=>{ //全局解析守卫});
router.afterEach((to,from)=>{ //全局后置钩子});
路由独享的守卫,写在配置里,
beforeEnter(to,from,next)=>{ }
组件内的守卫,可以在路由组件内直接定义路由导航守卫
beforeRouteEnter((to,from,next)=>{ })
beforeRouteUpdate((to,from,next)=>{ })
beforeRouteLeave((to,from,next)=>{ })
完整的导航解析流程(runQueue):
1)导航被触发
2)在失活的组件里调用离开守卫
3)调用全局的beforeEach守卫
4)在重用的组件里调用beforeRouterUpdate守卫
5)在路由配置里调用beforeEnter
6)解析异步路由组件
7)在被激活的组件里调用beforeRouterEnter
8)调用全局的beforeResolve守卫
9)导航被确认
10)调用全局的afterEach钩子
11)触发DOM更新
12)用创建好的实例调用beforeRouteEnter守卫中传给next的回调函数
25、vue.js实现点击按钮,全页面切换中英文?
1)所有组件配置当前页面所有json数据,使用$bus.on和$bus.emit通知所有组件
2)配置在一个大的json中,放到app.Vue中,读取不同字段,通过props层层传递
3)使用Vue-i18n组件
26、vue数组/对象来渲染一个列表,修改数组的某个值,视图是否会更新?为什么?
Vue.set(vm.items, indexOfItem, newValue)
Vue.items.splice(indexOfItem, 1, newvalue)
只有在data里初始化的数据才是响应式的,Vue不能检测到对象属性的添加或删除,没有在data里声明的属性不是响应式的。
27、router-link点击事件失效,怎么解决的?
在vue中绑定事件的方法:v-on:click=‘函数名称’;@click = ‘函数名称’;
在使用了 vue-router 路由时会使用 标签来代替 a 标签跳转。
解决办法:加 .native 修饰符
解释:
1: 因为它是自定义标签,根本就没有事件和方法,所以不触发,加个native 就是告诉vue 这个标签现在有主了 它是H5标签 可以加事件了。
2:父组件要想在子组件监听自己的click事件就得加native,router-link 其实就是一个封装好的 .vue 组件,所以需要 加.native修饰符才能绑定事件
28、Vue常用的修饰符
表单修饰符:
v-model.lazy,失去焦点,同步。
v-model.number,读输入的值判断是否可以转换为number
v-model.trim,输入内容,首位空格去除
事件修饰符:
v-on:click.prevent--阻止默认事件
v-on:click.stop--阻止冒泡
v-on:click.self要求click事件只有在e.target == e.currentTaget的时候才会执行
v-on:click.once只绑定一次click事件
v-on:click.capture遵循事件捕获顺序,不是冒泡顺序
v-on:scroll.passive = "onScroll" 在移动端,触发onscroll事件会让网页变卡,使用这个修饰符,相对于给onscroll事件整一个.lazy修饰符。
v-on:click.native 该修饰符把一个vue组件转化为一个普通的HTML标签。
按键修饰符:
v-on:keyDown.enter,按键修饰符,只有enter键才执行相对应事件;tab,esc等按键
v-on:keyDown.ctrl,alt,shift,meta系统修饰符,要按住相对应的按键才能执行事件
v-on:click.right,middle,left鼠标按键修饰符
29、axios的相关问题:
axios是一个基于promise的HTTP库,可以用在浏览器和node.js中。前端最流行的ajax请求库。
axios特点:
1)基于promise的异步ajax请求库,支持promise所有的API
2)浏览器端/node端都可以使用,浏览器中创建XMLHttpRequests
3)支持请求/响应拦截器
4)支持请求取消
5)可以转换请求数据和响应数据,并对响应回来的内容自动转换成JSON类型的数据
6)批量发送多个请求
7)安全性更高,客户端支持防御XSRF,就是让你的每个请求都带一个从cookie中拿到的key,根据浏览器同源策略,假冒的网站是拿不到你cookie中的key,这样,后台就可以轻松辨别出这个请求是否是用户在假冒网站上的误导输入,从而采取正确的策略。
axios常用语法
axios.get(url[, config]) //get请求用于列表和信息查询
axios.delete(url[, config]) //删除
axios.post(url[, data[, config]]) //post请求用于信息的添加
axios.put(url[, data[, config]]) //更新操作
axios.defaults.xxx //请求的默认全局配置
axios.interceptors.request.use() //添加请求拦截器
axios.interceptors.response.use() //添加响应拦截器
axios.Cancel() //用于创建取消请求的错误对象
axios.CancelToken() //用于创建取消请求的token对象
axios.isCancel() //是否是一个取消请求的错误
axios.all(promise) //用于批量执行多个异步请求
axios.spread() //用来指定接收所有成功数据的回调函数的方法
axios为什么既能在浏览器环境运行又能在服务器(node)环境运行?
axios在浏览器端使用XMLHttpRequest对象发送ajax请求;在node环境使用http对象发送ajax请求。
var defaults.adapter = getDefaultAdapter();
function getDefaultAdapter () {
var adapter;
if (typeof XMLHttpRequest !== 'undefined') {
// 浏览器环境
adapter = require('./adapter/xhr');
} else if (typeof process !== 'undefined') {
// node环境
adapter = require('./adapter/http');
}
return adapter;
}
上述代码,可以看出XMLHttpRequest是一个API,它为客户端提供了在客户端和服务器之间传输数据的功能;process对象是一个global(全局变量),提供有关信息,控制当前Node.js进程。
axios相关配置属性:
‘url’是用于请求的服务器URL
‘method’是创建请求时使用的方法,默认时get
‘baseURL’将自动加在‘url’前面,除非‘url’是一个绝对URL。它可以通过设置一个‘baseURL’便于为axios实例的方法传递相对URL
‘transformRequset’允许在向服务器发送前,修改请求数据,只能用在‘PUT’,‘POST’和‘PATCH’这几个请求方法
‘headers’是即将被发送的自定义请求头
‘params’是即将与请求一起发送的URL参数,必须是一个无格式对象(plainobject)或URLSearchParams对象
‘auth’表示应该使用HTTP基础验证,并提供凭据,username, password
‘proxy’定义代理服务器的主机名称和端口
axios相比原生ajax的优点(ajax的缺点)
ajax是针对MVC的编程,不符合现在前端MVVM的浪潮
基于原生的XHR开发,XHR本身的架构不清晰
30、懒加载(按需加载路由):
webpack中提供了require.ensure( )来实现按需加载。以前引入路由是通过import这样的方式引入,改为const定义的方式进行引入。
不进行页面按需加载引入方式:import home from '../../common/home.vue'
进行页面按需加载的引入方式:const home=r=>require.ensure([ ],( )=>r(require('../../comon/home.vue')))
31、Vue-cli3.0和2.0的区别:
1)默认进行懒观察(lazy observation)
在2.x版本里,不管数据多大,都会在一开始就为其创建观察者。当数据很大时,会在页面载入时造成明显的性能压力。3.x版本,只会对‘被用于渲染初始可见部分的数据’创建观察者。因此,3.x的观察者更高效。
2)更精准的变更通知
2.x版本中,使用Vue.set来给对象新增一个属性时,这个对象的所有watcher都会重新运行;3.x版本中,只有依赖那个属性的watcher才会重新运行。
3)3.0新加了TypeScript以及PWA的支持。
4)部分命令发生了变化
下载安装npm install -g vue@cli
删除了vue list
创建项目vue create
启动项目 npm run serve
5)默认项目目录结构也发生了变化
移除了配置文件目录,config和build文件夹
移除了static文件夹,新增public文件夹,并且index.html移动到public中
在src文件夹中新增了views文件夹,用于分类视图组件和公共组件
32、Vue3.0新特性:
1)setup 是新的组件选项。充当在组件内部使用入口点。
调用时间,创建组件实例时,在初始组件解析后立即调用。在生命周期方面,它在beforeCreate之后,created之前被调用。
2)Proxy
3.0表示已经放弃使用了Object.defineProperty,而选择了使用更快的原生Proxy。消除了之前Vue2.0中基于Object.defineProperty的实现所存在的很多限制:无法监听属性的添加和删除,数组索引和长度的变更,并可以支持Map,Set,Weak Map,Weak Set。
Proxy对象用于定义基本操作的自定义行为(如,属性查找,赋值,枚举,函数调用等)。通俗讲,就是在对目标对象的操作之前提供了拦截,可以对外界的操作进行过滤和改写,修改某些操作的默认行为,这样可以不直接操作对象本身,而是通过操作对象的代理对象来间接来操作对象,达到预期的目的。
语法:let proxy = new Proxy(target,handler);
参数target是用Proxy包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
参数handler也是一个对象,其属性是当执行一个操作时定义代理的行为的函数,也就是子当以的行为。
handler可以是空对象{ },则并表示对proxy操作就是对目标对象target操作;但不能设置为null,会抛出一个错误---Cannot create proxy with a non-object as target or handler!
语法层:
new Proxy(target,handler);
target,表示被代理的对象
handler,对代理的对象做了什么操作
handler {
set( ){ }, // 设置的时候干的事情
get( ){ }, // 获取干的事情
deleteProperty( ){ }, // 删除
has( ){ }, // 有没有这个东西 ‘xxx’in obj
apply( ){ }, // 调用函数处理
........
}
33、vuex刷新数据消失:
监听页面是否刷新,如果页面刷新了,将state对象存入到sessionStorage/localStorage中。页面打开之后,判断sessionStorage/localStorage中是否存在state对象,如果存在,则说明页面是被刷新过的,将sessionStorage/localStorage中存的数据取出来给vuex中的state赋值。如果不存在,说明是第一次打开,则取vuex中定义的state初始值。
//在页面加载时读取sessionStorage里的状态信息
if (sessionStorage.getItem("store") ) {
this.$store.replaceState(Object.assign({}, this.$store.state,JSON.parse(sessionStorage.getItem("store"))))
}
//在页面刷新时将vuex里的信息保存到sessionStorage里
window.addEventListener("beforeunload",()=>{
sessionStorage.setItem("store",JSON.stringify(this.$store.state))
})
34、vue怎样监听数组
vue通过重写数组的某些方法来监听数组变化,重写后的方法中会手动触发通知该数组的所有依赖进行更新(ob.dep.notify( ))。
35、vue手机端白屏:
手机白屏主要是因为页面渲染阻塞导致的,导致的原因有:
1)css文件加载需要一定的时间,在加载的过程中页面是空白的
解决:将css代码前置或者内联html即使用<style>
2)可能是等待异步加载数据在渲染页面导致白屏,数据量大加载慢,导致数据没请求到,阻塞页面渲染
解决:在手机显示的首屏时同步渲染页面,后续的数据在也页面滚动(滑屏)时,再采取异步请求渲染页面
3)手机页面的首屏JS的执行会阻塞页面的渲染
解决:尽量不要在首屏html代码中放置内联脚本。即:不要使用<script></script>
首页白屏优化实践:
1)SSR,服务端渲染。在服务端将渲染逻辑处理好,然后将处理好的HTML直接返回给前端显示。也可以解决SEO的问题,因为不需要动态获取数据了。
2)预渲染,用prerender-spa-plugin做预渲染。下面是常用prerender-spa-plugin的配置,staticDir预渲染输出的文件地址,routes要做预渲染的路由,minify压缩相关的配置,render渲染引擎相关的配置,可以传入自自定义的渲染引擎或者直接使用默认的PuppeteerRenderer, renderAfterDocumentEvent是渲染引擎配置中的一个属性,指当某个事件触发时才执行预渲染。
const path = require('path')
const PrerenderSPAPlugin = require('prerender-spa-plugin')
const Renderer = PrerenderSPAPlugin.PuppeteerRenderer
module.exports = {
configureWebpack: config => {
let plugins = []
plugins.push(new PrerenderSPAPlugin({
staticDir: path.resolve(__dirname, 'dist'),
routes: ['/', '/about'],
minify: {
collapseBooleanAttributes: true,
collapseWhitespace: true,
decodeEntities: true,
keepClosingSlash: true,
sortAttributes: true
},
renderer: new Renderer({
renderAfterDocumentEvent: 'custom-render-trigger'
})
}))
config.plugins = [
...config.plugins,
...plugins
]
}
}
3)骨架屏,loading
36、Vue监听路由的变化:
1)通过watch
// 监听,当路由发生变化的时候执行
watch:{
$route(to,from){
console.log(to.path);
}
},
或者
// 监听,当路由发生变化的时候执行
watch: {
$route: {
handler: function(val, oldVal){
console.log(val);
},
// 深度观察监听
deep: true
}
},
或者
// 监听,当路由发生变化的时候执行
watch: {
'$route':'getPath'
},
methods: {
getPath(){
console.log(this.$route.path);
}
}
2)通过vue-router的钩子函数beforeRouterEnter / beforeRouteUpdate / beforeRouteLeave
// 监听,当路由发生变化的时候执行
beforeRouteEnter(to, from, next){
// 在渲染该组件的对应路由被confirm前调用
// 不能获取组件实例 'this'
// 因为当钩子执行前,组件实例还没被创建
},
beforeRouterUpdate( to, from, next){
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在/foo/1 和 /foo/2 之间调转的时候
// 由于会渲染同样的Foo组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 'this'
},
deforeRouteLeave( to, from, next){
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 'this'
}
37、vue的路由跳转:
1)router-link
不带参数:<router-link :to="{name:'home'}">
带参数:
<router-link :to="{name:'home', params: {id:1}}">
// 路由配置 path: "/home/:id" 或者 path: "/home:id"
// 不配置path ,第一次可请求,刷新页面id会消失
// 配置path,刷新页面id会保留
// html 取参 $route.params.id
// script 取参 this.$route.params.id
<router-link :to="{name:'home', query: {id:1}}">
// query传参数 (类似get,url后面会显示参数)
// 路由可不配置
// html 取参 $route.query.id
// script 取参 this.$route.query.id
2)this.$router.push( )---函数里面调用
不带参数
this.$router.push('/home')
this.$router.push({name:'home'})
this.$router.push({path:'/home'})
query传参
this.$router.push({name:'home',query: {id:'1'}})
this.$router.push({path:'/home',query: {id:'1'}})
// html 取参 $route.query.id
// script 取参 this.$route.query.id
params传参
this.$router.push({name:'home',params: {id:'1'}}) // 只能用 name
// 路由配置 path: "/home/:id" 或者 path: "/home:id" ,
// 不配置path ,第一次可请求,刷新页面id会消失
// 配置path,刷新页面id会保留
// html 取参 $route.params.id
// script 取参 this.$route.params.id
query和params区别:query类似 get, 跳转之后页面 url后面会拼接参数,类似?id=1, 非重要性的可以这样传( 密码之类还是用params),刷新页面id还在。params类似 post, 跳转之后页面 url后面不会拼接参数 , 但是刷新页面id 会消失
3)this.$router.replace() (用法同上,push)
4)this.$router.go(n) ( )---向前或者向后跳转n个页面,n可为正整数或负整数
区别:
this.$router.push----跳转到指定url路径,并向history栈中添加一个记录,点击后退会返回到上一个页面
this.$router.replace----跳转到指定的url路径,但是history栈中不会有记录,点击返回跳转到上上个页面
this.$router.go(n)-----向前或者向后跳转n个页面,n可为正整数或负整数
网友评论