在style标签上不加上scoped的属性,默认为全局css样式
新增的 v-slot 属性怎么用?router-link 通过一个作用域插槽暴露底层的定制能力。这是一个更高阶的 API,主要面向库作者,但也可以为开发者提供便利,多数情况用在一个类似 NavLink 这样的自定义组件里。
在使用 v-slot API 时,需要向 router-link 传入一个单独的子元素。否则 router-link 将会把子元素包裹在一个 span 元素内。
可以通过命名视图(router-view),它容许同一界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果 router-view 没有设置名字,那么默认为 default。通过设置components即可同时渲染多个组件。
只需将多个路径的component字段的值设置为同一个组件即可。
可以通过watch方法来对$route进行监听,或者通过导航守卫的钩子函数beforeRouteUpdate来监听它的变化。
mvc 和 mvvm 其实区别并不大。都是一种设计思想。主要就是 mvc 中 Controller 演变成 mvvm 中的 viewModel。mvvm 主要解决了 mvc 中大量的 DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。和当 Model 频繁发生变化,开发者需要主动更新到 View 。
MVVM 是 Model-View-ViewModel 的缩写。mvvm 是一种设计思想。
1:Model 层代表数据模型,也可以在 Model 中定义数据修改和操作的业务逻辑;View 代表 UI 组件,它负责将数据模型转化成 UI 展现出来,ViewModel 是一个同步 View 和 Model 的对象。
2:在 MVVM 架构下,View 和 Model 之间并没有直接的联系,而是通过 ViewModel 进行交互,Model 和 ViewModel 之间的交互是双向的, 因此 View 数据的变化会同步到 Model 中,而 Model 数据的变化也会立即反应到 View 上。
3:ViewModel 通过双向数据绑定把 View 层和 Model 层连接了起来,而 View 和 Model 之间的同步工作完全是自动的,无需人为干涉,因此开发者只需关注业务逻辑,不需要手动操作 DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。
$root,和$parent都能访问父组件的属性和方法,区别在于如果存在多级子组件,通过parent 访问得到的是它最近一级的父组件,通过root 访问得到的是根父组件。通过在子组件标签定义 ref 属性,在父组件中可以使用$refs 访问子组件实例。
// 响应式原理
vue的响应式实现主要是利用了Object.defineProperty的方法里面的setter 与getter方法的观察者模式来实现。在组件初始化时会给每一个data属性注册getter和setter,然后再new 一个自己的Watcher对象,此时watcher会立即调用组件的render函数去生成虚拟DOM。在调用render的时候,就会需要用到data的属性值,此时会触发getter函数,将当前的Watcher函数注册进sub里。当data属性发生改变之后,就会遍历sub里所有的watcher对象,通知它们去重新渲染组件。
// proxy的优势如下:
Proxy 可以直接监听对象而非属性,可以直接监听数组的变化;
Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具备的;
Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而 Object.defineProperty 只能遍历对象属性直接修改;
// Object.defineProperty 的优势如下:
兼容性好,支持 IE9,而 Proxy 的存在浏览器兼容性问题,而且无法用 polyfill(垫片)来弥补
1:在Compostion API 中时根据逻辑相关组织代码的,提高可读性和可维护性,类似于react的hook写法。
2:更好的重用逻辑代码,在Options API中通过MIxins重用逻辑代码,容易发生命名冲突且关系不清。
3:解决在生命周期函数经常包含不相关的逻辑,但又不得不把相关逻辑分离到了几个不同方法中的问题,如在mounted中设置定时器,但需要在destroyed中来清除定时器,将同一功能的代码拆分到不同的位置,造成后期代码维护的困难。
如果应用够简单,最好不要使用 Vuex,一个简单的 store 模式即可,需要构建一个中大型单页应用时,使用Vuex能更好地在组件外部管理状态
可以直接修改,但是极其不推荐,state的修改必须在mutation来修改,否则无法被devtool所监测,无法监测数据的来源,无法保存状态快照,也就无法实现时间漫游/回滚之类的操作。
Vuex中所有的状态更新的唯一途径都是mutation,异步操作通过 Action 来提交 mutation实现,这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。每个mutation执行完成后都会对应到一个新的状态变更,这样devtools就可以打个快照存下来,否则无法被devtools所监测。如果mutation支持异步操作,就没有办法知道状态是何时更新的,无法很好的进行状态的追踪,给调试带来困难。
// 答案:
对于 Vue 来说,组件之间的数据传递具有单向数据流这样的特性称为单向数据流,单向数据流(Unidirectional data flow)方式使用一个上传数据流和一个下传数据流进行双向数据通信,两个数据流之间相互独立,单向数据流指只能从一个方向来修改状态。
而双向数据绑定即为当数据发生变化的时候,视图也就发生变化,当视图发生变化的时候,数据也会跟着同步变化,两个数据流之间互为影响。
#
将路由模式改为history
$route用来获取路由的信息的,它是路由信息的一个对象,里面包含路由的一些基本信息,包括name、meta、path、hash、query、params、fullPath、matched、redirectedFrom等。而$router主要是用来操作路由的,它是VueRouter的实例,包含了一些路由的跳转方法,钩子函数等
jQuery 专注视图层,通过直接操作 DOM 去实现页面的一些逻辑渲染;Vue 专注于数据层,通过数据的双向绑定,最终表现在 DOM 层面,减少了 DOM 操作。Vue 使用了组件化思想,使得项目子集职责清晰,提高了开发效率,方便重复利用,便于协同开发
通过directive来自定义指令,自定义指令分为全局指令和局部指令,自定义指令也有几个的钩子函数,常用的有bind和update,当 bind 和 update 时触发相同行为,而不关心其它的钩子时可以简写。一个表达式可以使用多个过滤器。过滤器之间需要用管道符“|”隔开。其执行顺序从左往右。
通过filter来定义过滤器,过滤器分为全局和局部过滤器,过滤器的主体为一个普通的函数,来对数据进行处理,可以传递参数。当有局部和全局两个名称相同的过滤器时候,会以就近原则进行调用,即:局部过滤器优先于全局过滤器被调用。
// 优点
1单页应用的内容的改变不需要重新加载整个页面,web应用更具响应性和更令人着迷。
2、单页应用没有页面之间的切换,就不会出现“白屏现象”,也不会出现假死并有“闪烁”现象
3、单页应用相对服务器压力小,服务器只用出数据就可以,不用管展示逻辑和页面合成,吞吐能力会提高几倍。
4、良好的前后端分离。后端不再负责模板渲染、输出页面工作,后端API通用化,即同一套后端程序代码,不用修改就可以用于Web界面、手机、平板等多种客户端。
// 缺点
1、首次加载耗时比较多。
2、SEO问题,不利于百度,360等搜索引擎收录。
3、容易造成Css命名冲突。
4、前进、后退、地址栏、书签等,都需要程序进行管理,页面的复杂度很高,需要一定的技能水平和开发成本高。
// 用法上
1:query要用path来引入,params要用name来引入,接收参数都是类似的,分别是this.$route.query.name和this.$route.params.name。
// 展示上
2:query更加类似于我们ajax中get传参,params则类似于post,说的再简单一点,前者在浏览器地址栏中显示参数,后者则不显示
3:params是路由的一部分,必须要有。query是拼接在url后面的参数,没有也没关系。
4:params、query不设置也可以传参,params不设置的时候,刷新页面或者返回参数会丢失
keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。一旦使用keepalive包裹组件,此时mouted,created等钩子函数只会在第一次进入组件时调用,当再次切换回来时将不会调用。此时如果我们还想在每次切换时做一些事情,就需要用到另外的周期函数,actived和deactived,这两个钩子函数只有被keepalive包裹后才会调用。
通常的url 地址由以下内容构成:协议名 域名 端口号 路径 参数 哈希值,当哈希值改变,页面不会发生跳转,单页面应用就是利用了这一点,给window注册onhashchange事件,当哈希值改变时通过location.hash就能获得相应的哈希值,然后就能跳到相应的页面。
// 答案:
v-if(判断是否隐藏,用来判断元素是否创建)
v-show(元素的显示隐藏,类似css中的display的block和hidden)
v-for(把数据遍历出来)
v-bind(绑定属性)
v-model(实现双向绑定)
解析和转换 .vue 文件,提取出其中的逻辑代码 script、样式代码 style、以及 HTML 模版 template,再分别把它们交给对应的 Loader 去处理。
// 答案:
用过,都使用过。插槽相当于预留了一个位置,可以将我们书写在组件内的内容放入,写一个插槽就会将组件内的内容替换一次,两次则替换两次。为了自定义插槽的位置我们可以给插槽取名,它会根据插槽名来插入内容,一一对应。
// 答案:
vue-router 提供的导航守卫主要用来对路由的跳转进行监控,控制它的跳转或取消,路由守卫有全局的, 单个路由独享的, 或者组件级的。导航钩子有3个参数:
1、to:即将要进入的目标路由对象;
2、from:当前导航即将要离开的路由对象;
3、next :调用该方法后,才能进入下一个钩子函数(afterEach)。
在style标签上加上scoped属性
Proxy相当于在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写,我们可以这样认为,Proxy是Object.defineProperty的全方位加强版,它解决了之前defineProperty无法监听到数组变化等缺点。
vue和react的diff算法,都是忽略跨级比较,只做同级比较。vue diff时调动patch函数,参数是vnode和oldVnode,分别代表新旧节点。
1.vue对比节点。当节点元素相同,但是classname不同,认为是不同类型的元素,删除重建,而react认为是同类型节点,只是修改节点属性。
2.vue的列表对比,采用的是两端到中间比对的方式,而react采用的是从左到右依次对比的方式。当一个集合只是把最后一个节点移到了第一个,react会把前面的节点依次移动,而vue只会把最后一个节点移到第一个。总体上,vue的方式比较高效。
create为组件初始化阶段,在此阶段主要完成数据观测(data observer),属性和方法的运算, watch/event 事件回调。然而,挂载阶段还没开始,此时还未生成真实的DOM,也就无法获取和操作DOM元素。而mount主要完成从虚拟DOM到真实DOM的转换挂载,此时html已经渲染出来了,所以可以直接操作dom节点。
1:无法监控到数组下标的变化,导致通过数组下标添加元素,不能实时响应;
2:只能劫持对象的属性,从而需要对每个对象,每个属性进行遍历,如果,属性值是对象,还需要深度遍历。
axios 是请求后台资源的模块。 通过npm install axios -S来安装,在大多数情况下我们需要封装拦截器,在实现登录的过程中我们一般在请求拦截器中来加入token,在响应请求器中通过判断后端返回的状态码来对返回的数据进行不同的处理。如果发送的是跨域请求,需在配置文件中 config/index.js 进行代理配置。
v-model是一个语法糖,这一个指令可以分为几个指令,它内部已经帮我们处理整合了。对于普通的文本框来说,v-model = v-bind:value + @input。对单选框和复选框来说,v-model = v-bind:checked + @change,并且它还有一个非常重要的功能,就是解决父子组件之间的通讯问题,可以提升我们的开发效率。在vue中通过使用的方式来绑定事件。
把不同路由对应的组件分割成不同的代码块,然后当路由被访问时才加载对应的组件即为路由的懒加载,可以加快项目的加载速度,提高效率。通过这种格式来导入组件const foo = () => import('./foo.vue');
计算属性computed :
1. 支持缓存,只有依赖数据发生改变,才会重新进行计算
2. 不支持异步,当computed内有异步操作时无效,无法监听数据的变化
3.computed 属性值会默认走缓存,计算属性是基于它们的响应式依赖进行缓存的,也就是基于data中声明过或者父组件传递的props中的数据通过计算得到的值
4. 如果一个属性是由其他属性计算而来的,这个属性依赖其他属性,是一个多对一或者一对一,一般用computed
5.如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的,属性都有一个get和一个set方法,当数据变化时,调用set方法。
侦听属性watch:
1. 不支持缓存,数据变,直接会触发相应的操作;
2.watch支持异步;
3.监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;
4. 当一个属性发生变化时,需要执行对应的操作;一对多;
5. 监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,函数有两个参数,
immediate:组件加载立即触发回调函数执行,
deep: 深度监听,为了发现对象内部值的变化,复杂类型的数据时使用,例如数组中的对象内容的改变,注意监听数组的变动不需要这么做。
注意:deep无法监听到数组的变动和对象的新增,参考vue数组变异,只有以响应式的方式触发才会被监听到。
watch工作原理:
watch在一开始初始化的时候,会读取一遍监听的数据的值,此时那个数据就收集到watch的watcher了然后你给watch设置的handler,watch 会放入watcher的更新函数中,当数据改变时,通知watch的watcher进行更新,于是你设置的handler就被调用了。
// 答案:
评估项目成员的水平,如果成员js基础较好、编码能力较强则选择React,否则Vue。
评估系统的大小,如果想构建生态系统,则选择React,如果要求而快,简单和“能用就行",则选择Vue。
评估系统运行环境,如果你想要一个同时适用于Web端和原生APP的框架,请选择React(RN)。
如果您不打算开发大型单页应用,使用 Vuex 可能是繁琐冗余的,并且state中的值会伴随着浏览器的刷新而初始化,无缓存。
1:Vue 使用的是 web 开发者更熟悉的模板与特性,Vue的API跟传统web开发者熟悉的模板契合度更高,比如Vue的单文件组件是以模板+JavaScript+CSS的组合模式呈现,它跟web现有的HTML、JavaScript、CSS能够更好地配合。React 的特色在于函数式编程的理念和丰富的技术选型,Vue更加注重web开发者的习惯。
2:Vue跟React的最大区别在于数据的reactivity,就是反应式系统上。Vue提供反应式的数据,当数据改动时,界面就会自动更新,而React里面需要调用方法SetState。我把两者分别称为Push-based和Pull-based
通过params传参会出现参数丢失的情况,可以通过query的传参方式或者在路由匹配规则加入占位符即可以解决参数丢失的情况。
利用$attrs 和 $listeners
1. 定义组件并抛出
2. import引入,并在component里面定义
3. 使用组件(注意首字母大写)
在Vue中利用数据劫持defineProperty在原型prototype上初始化了一些getter,分别是router代表当前Router的实例 、 router代表当前Router的实例、router代表当前Router的实例、route 代表当前Router的信息。在install中也全局注册了router-view,router-link,其中的Vue.util.defineReactive, 这是Vue里面观察者劫持数据的方法,劫持_route,当_route触发setter方法的时候,则会通知到依赖的组件。
接下来在init中,会挂载判断是路由的模式,是history或者是hash,点击行为按钮,调用hashchange或者popstate的同时更_route,_route的更新会触发route-view的重新渲染。
通用组件的封装就是对可复用组件的解耦和样式复用,为了解耦一般数据都是通过父组件传递过来,在子组件中进行数据处理,对于一些较为复杂的数据可能还需要做数据验证,为了避免高耦合,逻辑最好放在父组件中,通过自定义事件将数据回传,子组件只是一个承载体,这样既降低耦合,保证子组件中数据和逻辑不会混乱。如果同一组件需要适应不同需求时,我们需要配合slot来使用,可以通过具名插槽灵活地解决了不同场景同一组件不同配置的问题。
常用的生命周期有,beforeCreate,created,beforeMount,mounted,beforeUpdate,updated,beforeDestroy,destroyed
1、使用 a t t r s 和 attrs和 attrs和listeners
Vue.component("C", {
template: `
我是C组件
`,
});
Vue.component("B", {
/**
给C组件绑定$attrs属性和$listeners事件,C组件可以直接获取到A组件中传递下来的props(除了B组件中props声明的)
*/
template: `
我是B组件
`,
props: ["msg1"],
data() {
return {
mymsg1: this.msg1,
};
},
});
Vue.component("A", {
template: `
我是A组件
`,
data() {
return {
msg1: "A",
msgc: "hello c!",
};
},
methods: {
getChild(val) {
console.log(val);
},
getC(val) {
console.log(val);
},
},
});
const app = new Vue({
el: "#app",
template: `
`,
});
1.观察者 observer:首先通过观察者对 data 中的属性使用 object.defineproperty 劫持数据的 getter 和 setter,通知订阅者,触发他的 update 方法,对视图进行更新
2.Compile:用来解析模板指令,并替换模板数据,初始化视图,初始化相应的订阅器
3.订阅者 Watcher:订阅者接到通知后,调用 update 方法更新对应的视图
4.订阅器 Dep:订阅者可能有多个,因此需要订阅器 Dep 来专门接收这些订阅者,并统一管理
但在 vue3 中抛弃了 object.defineproperty 方法,因为
1.Object.defineproperty 无法监测对象属性的添加和删除、数组索引和长度的变更,因此 vue 重写了数组的 push/pop/shift/unshift/splice/sort/reverse 方法
2.Object.defineProperty 只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历,这样很消耗性能
vue3 中实现数据双向绑定的原理是数据代理,使用 proxy 实现。Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。
主要通过 Proxy 对对象进行绑定监听处理,通过 new Map 对对象的属性操作进行处理,将要执行的函数匹配到存到对应的 prop 上面,通过每次的访问触发 get 方法,进行存方法的操作,通过修改触发 set 的方法,此时执行回调监听的函数,这样达到修改数据和视图的
参考
1、作用:
迫使 Vue
实例重新渲染。注意它仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件。
2、内部原理:
Vue.prototype.$forceUpdate = function () {
const vm: Component = this;
if (vm._watcher) {
vm._watcher.update();
}
};
实例需要重新渲染是在依赖发生变化的时候会通知 watcher,然后通知 watcher 来调用 update 方法,就是这么简单。
diff 程可以概括为:oldCh 和 newCh 各有两个头尾的变量 StartIdx 和 EndIdx,它们的 2 个变量相互比较,一共有 4 种比较方式。如果 4 种比较都没匹配,如果设置了 key,就会用 key 进行比较,在比较的过程中,变量会往中间靠,一旦 StartIdx>EndIdx 表明 oldCh 和 newCh 至少有一个已经遍历完了,就会结束比较,这四种比较方式就是首、尾、旧尾新头、旧头新尾.
准确: 如果不加 key,那么 vue 会选择复用节点(Vue 的就地更新策略),导致之前节点的状态被保留下来,会产生一系列的 bug. 快速: key 的唯一性可以被 Map 数据结构充分利用,相比于遍历查找的时间复杂度
O(n)
,Map
的时间复杂度仅仅为O(1)
建议使用 id,不建议使用索引
vue 的双向绑定是由数据劫持结合发布者-订阅者模式实现的,那么什么是数据劫持?vue 是如何进行数据劫持的?说白了就是通过 Object.defineProperty()来劫持对象属性的 setter 和 getter 操作,在数据变动时做你想要做的事情
我们已经知道实现数据的双向绑定,首先要对数据进行劫持监听,所以我们需要设置一个监听器 Observer,用来监听所有属性。如果属性发生变化了,就需要告诉订阅者 Watcher 看是否需要更新。因为订阅者是有很多个,所以我们需要有一个消息订阅器 Dep 来专门收集这些订阅者,然后在监听器 Observer 和订阅者 Watcher 之间进行统一管理的。接着,我们还需要有一个指令解析器 Compile,对每个节点元素进行扫描和解析,将相关指令(如 v-model,v-on)对应初始化成一个订阅者 Watcher,并替换模板数据或者绑定相应的函数,此时当订阅者 Watcher 接收到相应属性的变化,就会执行对应的更新函数,从而更新视图。因此接下去我们执行以下 3 个步骤,实现数据的双向绑定:
1.实现一个监听器 Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
2.实现一个订阅者 Watcher,每一个 Watcher 都绑定一个更新函数,watcher 可以收到属性的变化通知并执行相应的函数,从而更新视图。
3.实现一个解析器 Compile,可以扫描和解析每个节点的相关指令(v-model,v-on 等指令),如果节点存在 v-model,v-on 等指令,则解析器 Compile 初始化这类节点的模板数据,使之可以显示在视图上,然后初始化相应的订阅者(Watcher)。
实现虚拟 DOM 的过程
// 使用axios用于对数据的请求
import axios from "axios";
// 创建axios实例
const instance = axios.create({
baseURL: baseURL + version,
timeout: 5000,
});
// 创建请求的拦截器
instance.interceptors.request.use(
(config) => {
config.headers["Authorization"] = localStorage.getItem("token");
return config;
},
(error) => {
return Promise.reject(error);
}
);
// 创建响应的拦截器
instance.interceptors.response.use(
(response) => {
let res = null;
// 对相应的数据进行过滤
if (response.status === 200) {
if (response.data && response.data.err === 0) {
res = response.data.data;
} else if (response.data.err === -1) {
return alert("token无效");
}
} else {
return alert("请求失败");
}
return res;
},
(error) => {
return Promise.reject(error);
}
);
export default instance;
vue 中列表循环需加:key=“唯一标识” 唯一标识可以是 item 里面 id index 等,因为 vue 组件高度复用增加 Key 可以标识组件的唯一性,为了更好地区别各个组件 key 的作用主要是为了高效的更新虚拟 DOM
详情链接
参考
diff 算法是一种通过同层的树节点进行比较的高效算法,避免了对树进行逐层搜索遍历,所以时间复杂度只有 O(n)。
diff 算法有两个比较显著的特点:
1、比较只会在同层级进行, 不会跨层级比较。
2、在 diff 比较的过程中,循环从两边向中间收拢。
diff 流程: 首先定义 oldStartIdx、newStartIdx、oldEndIdx 以及 newEndIdx 分别是新老两个 VNode 的两边的索引。
接下来是一个 while 循环,在这过程中,oldStartIdx、newStartIdx、oldEndIdx 以及 newEndIdx 会逐渐向中间靠拢。while 循环的退出条件是直到老节点或者新节点的开始位置大于结束位置。
while 循环中会遇到四种情况:
情形一:当新老 VNode 节点的 start 是同一节点时,直接 patchVnode 即可,同时新老 VNode 节点的开始索引都加 1。
情形二:当新老 VNode 节点的 end 是同一节点时,直接 patchVnode 即可,同时新老 VNode 节点的结束索引都减 1。
情形三:当老 VNode 节点的 start 和新 VNode 节点的 end 是同一节点时,这说明这次数据更新后 oldStartVnode 已经跑到了 oldEndVnode 后面去了。这时候在 patchVnode 后,还需要将当前真实 dom 节点移动到 oldEndVnode 的后面,同时老 VNode 节点开始索引加 1,新 VNode 节点的结束索引减 1。
情形四:当老 VNode 节点的 end 和新 VNode 节点的 start 是同一节点时,这说明这次数据更新后 oldEndVnode 跑到了 oldStartVnode 的前面去了。这时候在 patchVnode 后,还需要将当前真实 dom 节点移动到 oldStartVnode 的前面,同时老 VNode 节点结束索引减 1,新 VNode 节点的开始索引加 1。
while 循环的退出条件是直到老节点或者新节点的开始位置大于结束位置。
情形一:如果在循环中,oldStartIdx 大于 oldEndIdx 了,那就表示 oldChildren 比 newChildren 先循环完毕,那么 newChildren 里面剩余的节点都是需要新增的节点,把[newStartIdx, newEndIdx]之间的所有节点都插入到 DOM 中
情形二:如果在循环中,newStartIdx 大于 newEndIdx 了,那就表示 newChildren 比 oldChildren 先循环完毕,那么 oldChildren 里面剩余的节点都是需要删除的节点,把[oldStartIdx, oldEndIdx]之间的所有节点都删除
1、路由传参
query
// 方法一
<template>
<router-link
:to="{
path: 'blogDetail',
query: { id: item.id, views: item.views }
}"
tag="h2"
>
</router-link>
</template>
// 方法二
this.$router.push({
path: 'blogDetail',
query: {
id: item.id,
views: item.views
}
})
params
<template>
<router-link
:to="{
name: 'blogDetail',
params: { id: item.id, views: item.views }
}"
tag="h2"
>
</router-link>
</template>
this.$router.push({
name: 'blogDetail',
params: {
id: item.id,
views: item.views
}
})
hash | history | |
---|---|---|
url 显示 | 有#,很 Low | 无#,好看 |
回车刷新 | 可以加载到 hash 值对应页面 | 一般就是 404 掉了 |
支持版本 | 支持低版本浏览器和 IE 浏览器 | HTML5 新推出的 API |
每次通过 vue-router 进行页面跳转,都会触发 beforeEach 这个钩子函数,这个回调函数共有三个参数,to,from,next 这三个参数,to 表示我要跳转的目标路由对应的参数,from 表示来自那个路由,就是操作路由跳转之前的,即将离开的路由对应的参数,next 是一个回调函数,一定要调用 next 方法来 resolve 这个钩子函数;
单向数据流指只能从一个方向来修改状态。
数据从父级组件传递给子组件,只能单向绑定。
子组件内部不能直接修改从父级传递过来的数据。
综上可知,如果 data 是一个函数的话,这样每复用一次组件,就会返回一份新的 data,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。而单纯的写成对象形式,就使得所有组件实例共用了一份 data,就会造成一个变了全都会变的结果。
所以说 vue 组件的 data 必须是函数。这都是因为 js 的特性带来的,跟 vue 本身设计无关。
1、首屏加载优化
2、路由懒加载
{
path: '/',
name: 'home',
component: () => import('./views/home/index.vue'),
meta: { isShowHead: true }
}
3、开启服务器 Gzip
开启 Gzip 就是一种压缩技术,需要前端提供压缩包,然后在服务器开启压缩,文件在服务器压缩后传给浏览器,浏览器解压后进行再进行解析。首先安装 webpack 提供的compression-webpack-plugin
进行压缩,然后在 vue.config.js:
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const productionGzipExtensions = ['js', 'css']......plugins: [
new CompressionWebpackPlugin(
{
algorithm: 'gzip',
test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
threshold: 10240,
minRatio: 0.8
}
)]....
4、启动 CDN 加速
我们继续采用 cdn 的方式来引入一些第三方资源,就可以缓解我们服务器的压力,原理是将我们的压力分给其他服务器点。
5、代码层面优化
computed 和 watch 区分使用场景
computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值。当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算;
watch:类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
v-if 和 v-show 区分使用场景 v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景;v-show 则适用于需要非常频繁切换条件的场景。这里要说的优化点在于减少页面中 dom 总数,我比较倾向于使用 v-if,因为减少了 dom 数量。
v-for 遍历必须为 item 添加 key,且避免同时使用 v-if v-for 遍历必须为 item 添加 key,循环调用子组件时添加 key,key 可以唯一标识一个循环个体,可以使用例如 item.id 作为 key 避免同时使用 v-if,v-for 比 v-if 优先级高,如果每一次都需要遍历整个数组,将会影响速度。
6、Webpack 对图片进行压缩
7、避免内存泄漏
8、减少 ES6 转为 ES5 的冗余代码
微任务
原理:
nextTick 方法主要是使用了宏任务和微任务,定义了一个异步方法,多次调用 nextTick 会将方法存入队列中,通过这个异步方法清空队列。
作用: nextTick 用于下次 Dom 更新循环结束之后执行延迟回调,在修改数据之后使用 nextTick 用于下次 Dom 更新循环结束之后执行延迟回调,在修改数据之后使用 nextTick 用于下次 Dom 更新循环结束之后执行延迟回调,在修改数据之后使用 nextTick,则可以在回调中获取更新后的 DOM。
单页应用 页面跳转---->js 渲染 优点:页面切换快 缺点:首屏加载稍慢,seo 差
多页应用 页面跳转---->返回 html 优点:首屏时间快,seo 效果好 缺点:页面切换慢
参考
虚拟 DOM 其实就是一个 JavaScript 对象。通过这个 JavaScript 对象来描述真实 DOM,真实 DOM 的操作,一般都会对某块元素的整体重新渲染,采用虚拟 DOM 的话,当数据变化的时候,只需要局部刷新变化的位置就好了 ,
虚拟dom
相当于在js
和真实dom
中间加了一个缓存,利用dom diff
算法避免了没有必要的dom
操作,从而提高性能
具体实现步骤如下
JavaScript
对象结构表示 DOM
树的结构;然后用这个树构建一个真正的 DOM
树,插到文档当中DOM
树上,视图就更新参考
vue 中列表循环需加:key=“唯一标识” 唯一标识可以是 item 里面 id index 等,因为 vue 组件高度复用增加 Key 可以标识组件的唯一性,为了更好地区别各个组件 key 的作用主要是为了高效的更新虚拟 DOM
一、v-model 修饰符
1、.lazy:
输入框改变,这个数据就会改变,lazy 这个修饰符会在光标离开 input 框才会更新数据:
2、.trim:
输入框过滤首尾的空格:
3、.number:
先输入数字就会限制输入只能是数字,先字符串就相当于没有加 number,注意,不是输入框不能输入字符串,是这个数据是数字:
二、事件修饰符
4、.stop:
阻止事件冒泡,相当于调用了 event.stopPropagation()方法:
5、.prevent:
阻止默认行为,相当于调用了 event.preventDefault()方法,比如表单的提交、a 标签的跳转就是默认事件:
6、.self:
只有元素本身触发时才触发方法,就是只有点击元素本身才会触发。比如一个 div 里面有个按钮,div 和按钮都有事件,我们点击按钮,div 绑定的方法也会触发,如果 div 的 click 加上 self,只有点击到 div 的时候才会触发,变相的算是阻止冒泡:
7、.once:
事件只能用一次,无论点击几次,执行一次之后都不会再执行
8、.capture:
事件的完整机制是捕获-目标-冒泡,事件触发是目标往外冒泡
9、.sync
对 prop 进行双向绑定
10、.keyCode:
监听按键的指令,具体可以查看 vue 的键码对应表
只要进行调用就会执行,不管依赖的值有没有改变。无缓存。
监听其所有依赖的变化,如果有变化会执行,没有变化不执行。有缓存,不用每次重新算。不支持异步。
详解:在 vue 的 模板内({{}}
)是可以写一些简单的 js 表达式的 ,很便利。但是如果在页面中使用大量或是复杂的表达式去处理数据,对页面的维护会有很大的影响。这个时候就需要用到 computed 计算属性来处理复杂的逻辑运算。
在数据未发生变化时,优先读取缓存。computed 计算属性只有在相关的数据发生变化时才会改变要计算的属性,当相关数据没有变化是,它会读取缓存。而不必想 motheds 方法 和 watch 方法是否每次都去执行函数。
setter 方法在设置值是触发。
getter 方法在获取值时触发。
观察某一个变量,发生变化会执行。支持异步。Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个属性。
一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象。
1.主动调用的方法写在 methods 里,依据某些变量的更新进行某种操作用 computed 或者 watch。
2.computed 和 watch:如果要异步,只能用 watch。如果是计算某个值推荐用 computed,比如购物车全选单选功能,购物车计算总价小计功能。
<p v-on="{click:dbClick,mousemove:MouseClick}"></p>
vue template 模板编译的过程经过 parse()生成 ast(抽象语法树),optimize 对静态节点优化,generate()生成 render 字符串 之后调用 new Watcher()函数,用来监听数据的变化,render 函数就是数据监听的回调所调用的,其结果便是重新生成 vnode。 当这个 render 函数字符串在第一次 mount、或者绑定的数据更新的时候,都会被调用,生成 Vnode。 如果是数据的更新,那么 Vnode 会与数据改变之前的 Vnode 做 diff,对内容做改动之后,就会更新到 我们真正的 DOM
参考
hash | history | |
---|---|---|
url 显示 | 有#,很 Low | 无#,好看 |
回车刷新 | 可以加载到 hash 值对应页面 | 一般就是 404 掉了 |
支持版本 | 支持低版本浏览器和 IE 浏览器 | HTML5 新推出的 API |
组件支持用户在具有路由功能的应用中 (点击) 导航。 通过 to 属性指定目标地址,默认渲染成带有正确链接的 标签,可以通过配置 tag 属性生成别的标签.。 通过 router-link 进行跳转不会跳转到新的页面,也不会重新渲染,它会选择路由所指的组件进行渲染,避免了重复渲染的“无用功”。 总结:对比,router-link 组件避免了不必要的重渲染,它只更新变化的部分从而减少 DOM 性能消耗
slot 用于封装组件中,写在子组件 接收父组件动态传递子组件内容片断
slot 插槽的使用方法其实就是类似于一个子组件或者标签的引用的过程,在父组件里面定义一个 slot,给她起个 name,然后组件引入到子组件,子组件里面有个元素的属性 slot 值等于 name,然后父组件里面没有值的时候就可以显示子组件里面的信息了(切记:插槽 slot 要写在父组件里面!!!)
vue slot 用法 1:
slot 主要是让组件的可扩展性更强
1.匿名 slot 使用
//定义组件
//定义组件
//使用方法
如果不在 slot 里加入任何标签,slot 什么都不会显示。
router.beforeEach
全局前置守卫 进入路由之前router.beforeResolve
全局解析守卫(2.5.0+) 在beforeRouteEnter
调用之后调用router.afterEach
全局后置钩子 进入路由之后1、 Vue 异步加载技术
1:vue-router配置路由,使用vue的异步组件技术,可以实现懒加载,此时一个组件会生成一个js文件。
2:component: resolve => require(['放入需要加载的路由地址'], resolve)
2、 ES6 推荐方式 imprort ()----推荐使用
import Vue from "vue";
import Router from "vue-router";
// 官网可知:下面没有指定webpackChunkName,每个组件打包成一个js文件。
const Foo = () => import("../components/Foo");
const Aoo = () => import("../components/Aoo");
// 下面2行代码,指定了相同的webpackChunkName,会合并打包成一个js文件。
// const Foo = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '../components/Foo')
// const Aoo = () => import(/* webpackChunkName: 'ImportFuncDemo' */ '../components/Aoo')
export default new Router({
routes: [
{
path: "/Foo",
name: "Foo",
component: Foo,
},
{
path: "/Aoo",
name: "Aoo",
component: Aoo,
},
],
});
3、 webpack 提供的 require.ensure()实现懒加载
1:vue-router配置路由,使用webpack的require.ensure技术,也可以实现按需加载。
2:这种情况下,多个路由指定相同的chunkName,会合并打包成一个js文件。
3:require.ensure可实现按需加载资源,包括js,css等。他会给里面require的文件单独打包,不会和主文件打包在一起。
4:第一个参数是数组,表明第二个参数里需要依赖的模块,这些会提前加载。
5:第二个是回调函数,在这个回调函数里面require的文件会被单独打包成一个chunk,不会和主文件打包在一起,这样就生成了两个chunk,第一次加载时只加载主文件。
6:第三个参数是错误回调。
7:第四个参数是单独打包的chunk的文件名
import Vue from 'vue';
import Router from 'vue-router';
const HelloWorld=resolve=>{
require.ensure(['@/components/HelloWorld'],()=>{
resolve(require('@/components/HelloWorld'))
})
}
Vue.use('Router')
export default new Router({
routes:[{
{path:'./',
name:'HelloWorld',
component:HelloWorld
}
}]
})
1、路由跳转
router-link 组件 默认会被渲染成一个 标签,进行跳转,在组件中可以通过绑定to
属性来指定要跳转的链接;tag
属性指本来的标签
<router-link :to="/foo" tag="h2">Foo</router-link>
$router.push()方法
2、路由传参
query
// 方法一
<template>
<router-link
:to="{
path: 'blogDetail',
query: { id: item.id, views: item.views }
}"
tag="h2"
>
</router-link>
</template>
// 方法二
this.$router.push({
path: 'blogDetail',
query: {
id: item.id,
views: item.views
}
})
params
<template>
<router-link
:to="{
name: 'blogDetail',
params: { id: item.id, views: item.views }
}"
tag="h2"
>
</router-link>
</template>
this.$router.push({
name: 'blogDetail',
params: {
id: item.id,
views: item.views
}
})
参考 100 题
1、问题描述:页面刷新的时候 vuex 里的数据会重新初始化,导致数据丢失。因为 vuex 里的数据是保存在运行内存中的,当页面刷新时,页面会重新加载 vue 实例,vuex 里面的数据就会被重新赋值。
2、解决思路:
办法一:将 vuex 中的数据直接保存到浏览器缓存中(sessionStorage、localStorage、cookie) 办法二:在页面刷新的时候再次请求远程数据,使之动态更新 vuex 数据 办法三:在父页面向后台请求远程数据,并且在页面刷新前将 vuex 的数据先保存至 sessionStorage(以防请求数据量过大页面加载时拿不到返回的数据)
3、 解决过程:
3.1、选择合适的浏览器存储
3.2、解决方案
1、$nextTick 是在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM,意思是 等你 dom 加载完毕以后再去调用 nextTick()里面的数据内容
1、手段:v-if 是动态的向 DOM 树添加或者删除 DOM 元素;v-show 是通过设置 DOM 元素的 display 样式属性控制显示和隐藏。
2、编译过程:v-if 切换有一个局部编译/卸载的过程, 切换过程中合适地销毁和重建内部的事件监听和子组件;v-show 只是简单的基于 css 切换。
3、编译条件:v-if 是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译(编译被缓存?编译被缓存后,然后再切换的时候进行局部卸载); v-show 是在任何条件下(首次条件是否为真)都被编译,然后被缓存,而且 DOM 元素保留
4、性能消耗:v-if 有更高的切换消耗;v-show 有更高的初始渲染消耗 使用场景:v-if 适合运营条件不大可能改变;v-show 适合频繁切换
6、相同点: v-show 都可以动态控制着 dom 元素的显示隐藏 不同点: v-if 的显示隐藏是将 DOM 元素整个添加或删除,v-show 的显示隐藏是为 DOM 元素添
7、加 css 的样式 display,设置 none 或者是 block,DOM 元素是还存在的
8、在渲染多个元素的时候,可以把一个 元素作为包装元素,并使用 v-if 进行条件判断,最终的渲染不会包含这个元素,v-show 是不支持 语法
生命周期 | 发生了什么 |
---|---|
beforeCreate | 初始化界面前 : 在当前阶段 data、methods、computed 以及 watch 上的数据和方法都不能被访问,都还没有完成初始化。 |
created | 初始化界面后 : 在实例创建完成后发生,当前阶段已经完成了数据观测,也就是可以使用数据,更改数据,在这里更改数据不会触发 updated 函数,也就是不会更新视图。实例的 data 数据和 methods 方法都已经被初始化完毕了,可以正常访问 |
beforeMount | 挂载前 :完成模板编译,虚拟 Dom 已经创建完成,即将开始渲染。在此时也可以对数据进行更改,不会触发 updated。数据还没有更新到页面上去。当编译完成之后,只是在内存中已经有了编译好的页面,但并未渲染。 |
mounted | 挂载完成 : 将编译好的模板挂载到页面 (虚拟 DOM 挂载) ,可以在这进行异步请求以及 DOM 节点的访问,在 vue 用$ref 操作 |
beforeUpdate | 更新数据前 : 组件数据更新之前调用,数据都是新的,页面上数据都是旧的。将要根据最新的 data 数据,重新解析所有指令,从而重新渲染浏览器页面。 |
updated | 组件更新后 : render 重新渲染 , 此时数据和界面都是新的 ,要注意的是避免在此期间更改数据,因为这可能会导致无限循环的更新 |
beforeDestroy | 组件卸载前 : 实例销毁之前,在当前阶段实例完全可以被使用,我们可以在这时进行善后收尾工作,比如清除计时器 |
destroyed | 组件卸载后 : 组件已被拆解,数据绑定被卸除,监听被移出,子实例也统统被销毁。 |
activited | keep-alive 专属 , 组件被激活时调用 |
deactivated | keep-alive 专属 , 组件被销毁时调用 |
1、v-model 本质上是一个语法糖,可以看成是 value + input 方法的语法糖。可以通过 model 的 prop 属性和 event 事件来进行自定义。
2、v-model 是 vue 的双向绑定的指令,能将页面上控件输入的值同步更新到相关绑定的 data 属性, 也会在更新data
绑定属性时候,更新页面上输入控件的值。
1、生命周期:
小程序
的钩子函数要简单得多 。 vue
的钩子函数在跳转新页面时,钩子函数都会触发,但是小程序
的钩子函数,页面不同的跳转方式,触发的钩子并不一样。
在页面加载请求数据时,两者钩子的使用有些类似,vue
一般会在created
或者mounted
中请求数据,而在小程序
,会在onLoad
或者onShow
中请求数据。
2、数据绑定:
vue 动态绑定一个变量的值为元素的某个属性的时候,会在变量前面加上冒号:
<img :src="imgSrc"/>
小程序 绑定某个变量的值为元素属性时,会用两个大括号括起来,如果不加括号,为被认为是字符串
<image src="{{imgSrc}}"></image>
3、列表循环
4、显示与隐藏元素
vue
中,使用v-if
和v-show
控制元素的显示和隐藏
小程序
中,使用wx-if
和hidden
控制元素的显示和隐藏
5、事件处理
vue
:使用v-on:event
绑定事件,或者使用@event
绑定事件
小程序
中,全用bindtap(bind+event)
,或者catchtap(catch+event)
绑定事件
6、数据的双向绑定
在vue
中,只需要再表单
元素上加上v-model
,然后再绑定data
中对应的一个值,当表单元素内容发生变化时,data
中对应的值也会相应改变 。
当表单内容发生变化时,会触发表单元素上绑定的方法,然后在该方法中,通过this.setData({key:value})
来将表单上的值赋值给data
中的对应值 。
7、绑定事件传参
在vue
中,绑定事件传参挺简单,只需要在触发事件的方法中,把需要传递的数据作为形参传入就可以了
在小程序
中,不能直接在绑定事件的方法中传入参数,需要将参数作为属性值,绑定到元素上的data-
属性上,然后在方法中,通过e.currentTarget.dataset.*
的方式获取
8、父子组件通信
父组件向子组件传递数据,只需要在子组件通过v-bind
传入一个值,在子组件中,通过props
接收,即可完成数据的传递
父组件向子组件通信和vue
类似,但是小程序
没有通过v-bind
,而是直接将值赋值给一个变量 在子组件properties
中,接收传递的值
1、props 和$emit
父组件向子组件传递数据是通过 prop 传递的,子组件传递数据给父组件是通过$emit 触发事件
2、 a t t r s 和 attrs和 attrs和listeners
3、中央事件总线 bus
上面两种方式处理的都是父子组件之间的数据传递,而如果两个组件不是父子关系呢?这种情况下可以使用中央事件总线的方式。新建一个 Vue 事件 bus 对象,然后通过 bus. e m i t 触发事件, b u s . emit触发事件,bus. emit触发事件,bus.on 监听触发的事件。
4、provide 和 inject
父组件中通过 provider 来提供变量,然后在子组件中通过 inject 来注入变量。不论子组件有多深,只要调用了 inject 那么就可以注入 provider 中的数据。而不是局限于只能从当前父组件的 prop 属性来获取数据,只要在父组件的生命周期内,子组件都可以调用。
5、v-model
父组件通过 v-model 传递值给子组件时,会自动传递一个 value 的 prop 属性,在子组件中通过 this.$emit(‘input’,val)自动修改 v-model 绑定的值
6、 p a r e n t 和 parent和 parent和children
7、boradcast 和 dispatch
8、vuex 处理组件之间的数据交互 如果业务逻辑复杂,很多组件之间需要同时处理一些公共的数据,这个时候才有上面这一些方法可能不利于项目的维护,vuex 的做法就是将这一些公共的数据抽离出来,然后其他组件就可以对这个公共数据进行读写操作,这样达到了解耦的目的。
vue 中八种通信方式
vue2.0 是需要全局去比较每个节点的,若发现有节点发生变化后,就去更新该节点
vue3.0 是在创建虚拟 dom 中,会根据 DOM 的的内容会不会发生内容变化,添加静态标记, 谁有 flag!比较谁。
vue2 中无论元素是否参与更新,每次都会重新创建,然后再渲染 vue3 中对于不参与更新的元素,会做静态提升,只被创建一次,在渲染时直接复用即可
默认情况下,onclick 为动态绑定,所以每次都会追踪它的变化,但是因为是同一函数,没有必要追踪变化,直接缓存复用即可
在之前会添加静态标记 8 会把点击事件当做动态属性 会进行 diff 算法比较, 但是在事件监听缓存之后就没有静态标记了,就会进行缓存复用
在 vue3.0 中创建 vue 项目 除了 vue-cli,webpack 外还有 一种创建方法是 Vite Vite 是作者开发的一款有意取代 webpack 的工具,其实现原理是利用 ES6 的 import 会发送请求去加载文件的特性,拦截这些请求,做一些预编译,省去 webpack 冗长的打包时间
在 vue2.0 中: 主要是往 data 和 method 里面添加内容,一个业务逻辑需要什么 data 和 method 就往里面添加,而组合 API 就是 有一个自己的方法,里面有自己专注的 data 和 method。
首先 composition API(组合 API) 和 Option API(vue2.0 中的 data 和 method)可以共用 composition API(组合 API)本质就是把内容添加到 Option API 中进行使用
1.ref 和 reactive 都是 vue3 的监听数据的方法,本质是 proxy 2.ref 基本类型复杂类型都可以监听(我们一般用 ref 监听基本类型),reactive 只能监听对象(arr,json) 3.ref 底层还是 reactive
vue3.0
现在 我们需要实现这样 一个功能,登录拦截,其实就是 路由拦截,首先在定义路由的时候就需要多添加一个自定义字段 requireAuth,用于判断该路由的访问是否需要登录。如果用户已经登录,则顺利进入路由, 否则就进入登录页面。在路由管理页面添加 meta 字段
{
path:'/manage',
name:'manage',
component:manage,
meta:{requireAuth:true}
}
在入口文件中,添加路由守卫
{
path: '/',
name: 'home',
component: () => import('./views/home/index.vue'),
meta: { isShowHead: true }
}
开启 Gzip 就是一种压缩技术,需要前端提供压缩包,然后在服务器开启压缩,文件在服务器压缩后传给浏览器,浏览器解压后进行再进行解析。首先安装 webpack 提供的compression-webpack-plugin
进行压缩,然后在 vue.config.js:
const CompressionWebpackPlugin = require('compression-webpack-plugin')
const productionGzipExtensions = ['js', 'css']......plugins: [
new CompressionWebpackPlugin(
{
algorithm: 'gzip',
test: new RegExp('\\.(' + productionGzipExtensions.join('|') + ')$'),
threshold: 10240,
minRatio: 0.8
}
)]....
我们继续采用 cdn 的方式来引入一些第三方资源,就可以缓解我们服务器的压力,原理是将我们的压力分给其他服务器点。
computed 和 watch 区分使用场景
computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值。当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算;
watch:类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
v-if 和 v-show 区分使用场景 v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景;v-show 则适用于需要非常频繁切换条件的场景。这里要说的优化点在于减少页面中 dom 总数,我比较倾向于使用 v-if,因为减少了 dom 数量。
v-for 遍历必须为 item 添加 key,且避免同时使用 v-if v-for 遍历必须为 item 添加 key,循环调用子组件时添加 key,key 可以唯一标识一个循环个体,可以使用例如 item.id 作为 key 避免同时使用 v-if,v-for 比 v-if 优先级高,如果每一次都需要遍历整个数组,将会影响速度。
单一的数据源
变化可以预测
本质上:
Redux 和 Vuex 都是对 MVVM 思想的服务,将数据从视图中抽离的一种方案
形式上:
Vuex 借鉴了 Redux,将 store 作为全局的数据中心,进行数据管理
threshold: 10240,
minRatio: 0.8
}
)]…
#### 4、启动 CDN 加速
我们继续采用 cdn 的方式来引入一些第三方资源,就可以缓解我们服务器的压力,原理是将我们的压力分给其他服务器点。
#### 5、代码层面优化
- computed 和 watch 区分使用场景
computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值。当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算;
watch:类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
- v-if 和 v-show 区分使用场景 v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景;v-show 则适用于需要非常频繁切换条件的场景。这里要说的优化点在于减少页面中 dom 总数,我比较倾向于使用 v-if,因为减少了 dom 数量。
- v-for 遍历必须为 item 添加 key,且避免同时使用 v-if v-for 遍历必须为 item 添加 key,循环调用子组件时添加 key,key 可以唯一标识一个循环个体,可以使用例如 item.id 作为 key 避免同时使用 v-if,v-for 比 v-if 优先级高,如果每一次都需要遍历整个数组,将会影响速度。
#### 6、Webpack 对图片进行压缩
#### 7、避免内存泄漏
#### 8、减少 ES6 转为 ES5 的冗余代码
##### 103. ★★★ Vuex 和 redux 有什么区别?他们的共同思想。
##### Redux 和 Vuex 区别
- Vuex 改进了 Redux 中的 Action 和 Reducer 函数,以 mutations 变化函数取代 Reducer,无需 switch,只需在对应的 mutation 函数里改变 state 值就可以
- Vuex 由于 Vue 自动重新渲染的特性,无需订阅重新渲染函数,只要生成新的 state 就可以
- Vuex 数据流的顺序是:View 调用 store.commit 提交对应的请求到 Store 中对应的 mutation 函数 -- store 改变(vue 检测到数据变化自动渲染)
##### 共同思想
- 单一的数据源
- 变化可以预测
- `本质上:`Redux 和 Vuex 都是对 MVVM 思想的服务,将数据从视图中抽离的一种方案
- `形式上:`Vuex 借鉴了 Redux,将 store 作为全局的数据中心,进行数据管理