22年9月26日
焦虑不安,没有可以说上话的朋友。找不到工作,虽然是计算机专业相关却错过了最好的时间,人们常说任何时候都不晚,但是投递的简历石沉大海自己也不是一个自信的人,妈妈生病住院且非常的固执,现在还说让我三战考研,真的是头疼,好难过呜呜呜。我感觉我废了,我真的一点都静不下心来学习。
恋爱也是失败,呜呜呜。。
我真的是一个大废物呀,好想好想勇敢一点爱这个世界!
常用API说明
1.Vue.set
向响应式对象中添加一个属性,并确保这个新属性同样是响应式的,且会触发视图更新。
使用方法: Vue.set(target,propertyName,value)
2.Vue.delete
删除对象的属性,如果对象是响应式的,确保删除能触发更新视图。
使用方式: Vue.delete(target,propertyName)
如果使用 delete obj[‘property’] 是不能更新页面的。
3.vm.$on 与vm.$emit
4. 自定义组件实现双向绑定
v-model 就是 v-bind 与 v-on 的语法糖。
在这里我们将 userInfo 的值给了 value 属性,而 value 属性传递到了 user-add 组件中,所以在 user-add 组件中要通过 props 来接收 value 属性的值。
5.使用插槽完成内容分发
6.vm.$on 与 vm.$emit 应用
vm.$on 与 vm.$emit
的典型应用就是事件总线。 也就是通过在 Vue 原型上添加一个 Vue 实例作为事件总线,实现组件间相互通信,而且不受组件间关系 的影响。
7.vm.$once 与vm.$off
关于这两个方法,大家只需要了解一下就可以了。
vm.$once 监听一个自定义事件,但是只触发一次。一旦触发之后,监听器就会被移除。
vm.$off 移除自定义事件监听器。
如果没有提供参数,则移除所有的事件监听器;
vm.$off() // 移除所有的事件监听器
vm.$off('test') // 移除该事件所有的监听器
vm.$off('test', callback) // 只移除这个回调的监听器
ref 和vm.$refs
ref 被用来给元素或子组件注册引用信息。
引用信息将会注册在父组件的 $refs 对象上,如果在普通的DOM 元素上使用,引用指向的就是 DOM 元素;
如果用在子组件上,引用就指向组件的实例。
下面在对 ref 与 vm.$refs 的使用做一个总结:
ref 是作为渲染结果被创建的,在初始渲染时不能访问它们。也就是必须在 mounted 构造函数
中。
$refs 不是响应式的,不要试图用它在模板中做数据绑定。
过滤器
过滤器基本使用
自定义指令
自定义指令基本用法
渲染函数
render:function(createElement){
//createElement函数返回的结果为VNode. VNode就是虚拟dom,用js对象来模拟真实的DOM.
retrun createElement(
tag, //标签名称
data,// 传递数据
children //子节点数组
)
}
函数式组件
混入
混入( mixin )提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能,一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项被“混合”进入该组件本身的选项。
“混入”可以提高组件的复用功能,例如:上面所写的 hello 这个方法,不仅在一个组件中使用,还会
在其它组件中使用.那么,我们的处理方式就是,可以将 hello 这个方法单独定义在一个地方,如果某
个组件想要使用,可以直接将该方法注入到组件中。
插件
Vue Router
一、Vue Router 回顾
1、路由简介
路由是一个比较广义和抽象的概念,
路由的本质就是对应关系。
在开发中,路由分为: 后端路由、前端路由
后端路由
概念:根据不同的用户 URL 请求,返回不同的内容
本质:URL 请求地址与服务器资源之间的对应关系
前端路由
概念:根据不同的用户事件,显示不同的页面内容
本质:用户事件与事件处理函数之间的对应关系
vue-router的基本使用
Vue Router (官网: https://router.vuejs.org/zh/ )是 Vue.js 官方的路由管理器。 它和Vue.js 的核心深度集成,可以非常方便的用于 SPA 应用程序的开发。
基本使用的步骤:
- 引入相关的库文件
- 添加路由链接
- 添加路由填充位
- 定义路由组件
- 配置路由规则并创建路由实例
- 把路由挂载到 Vue 根实例中
4、路由重定向
路由重定向指的是:用户在访问地址 A 的时候,强制用户跳转到地址 C ,从而展示特定的组件页面;
通过路由规则的 redirect 属性,指定一个新的路由地址,可以很方便地设置路由的重定向:
5、嵌套路由
父级路由通过 children 属性配置子级路由
6.动态匹配路由
6.1 动态匹配路由的基本用法
可以发现整个路由规则中只有后续的数字是在变化的。所以这里可以通过动态路由参数的模
式进行路由匹配。
6.2 路由组件传递参数
$route 与对应路由形成高度耦合,不够灵活,所以可以使用 props 将组件和路由解耦
第一种情况:
props的值为布尔类型
在定义路由规则的时候,为其添加了 props 属性,并将其值设置为 true .那么在组件中就可以通过 props:[‘id’] 的形式来获取对应的参数值。
第二种情况: props 的值为对象类型
在上面的代码中,在路由规则中,通过 props 向用户组件中传递了一个对象,那么在 User 用户组件中可以接收到传递过来的对象。但是参数 id 无法接收到。
如果要解决这个问题,可以使用 props 的值为函数类型。也就是给 props 传递一个函数。
第三种情况: props 的值为函数类型
8、编程式导航
页面导航的两种方式
声明式导航:通过点击链接实现导航的方式,叫做声明式导航
例如:普通网页中的 <a></a> 链接 或 vue 中的 <router-link></router-link>
编程式导航:通过调用 JavaScript 形式的 API 实现导航的方式,叫做编程式导航
例如:普通网页中的 location.href
编程式导航基本用法
常用的编程式导航 API 如下:
this.$router.push ('hash地址')
this.$router.go(n)
9、路由案例
10、路由守卫
Vue-router 中的路由守卫,主要是对其内容进行保护,如果没有对应的权限,则不允许访问。
我们首先来看一下全局守卫,也就是所有的路由都会经过全局守卫来进行检测。
11、addRoutes动态路由添加
12、路由组件缓存
生命周期:
activated 和 deactivated 会在 keep-alive 内所有嵌套的组件中触发
如:B页面是缓存页面
当A页面跳到B页面时,B页面的生命周期:activated(可在此时更新数据)
B页面跳出时,触发deactivated
B页面自身刷新时,会触发created-mouted-activated
13、Hash模式与History模式
13.1 Hash模式与History模式区别
前端路由中,不管是什么实现模式,都是客户端的一种实现方式,也就是当路径发生变化的时候,是不会向服务器发送请求的。
如果需要向服务器发送请求,需要用到 ajax 方式。
两种模式的区别
首先是表现形式的区别
Hash 模式
hash 模式中路径带有 # , # 后面的内容作为路由地址。可以通过问号携带参数。
当然这种模式相对来说比较丑,路径中带有与数据无关的符号,例如 # 与 ?
History 模式
History 模式是一个正常的路径的模式,如果要想实现这种模式,还需要服务端的相应支持。
https://www.baidu.com/showlist/22256
下面再来看一下两者原理上的区别。
Hash 模式是基于锚点,以及 onhashchange 事件。
通过锚点的值作为路由地址,当地址发生变化后触发 onhashchange 事件。
History 模式是基于 HTML5 中的 History API
也就是如下两个方法
history.pushState( ) IE10 以后才支持
history.replaceState( )
13.2 History 模式的使用
History 模式需要服务器的支持为什么呢?
因为在单页面的应用中,只有一个页面,也就是 index.html 这个页面,服务端不存在
http://www.test.com/login 这样的地址,也就说如果刷新浏览器,请求服务器,是找不到 /login 这个页面的,所以会出现 404 的错误。(在传统的开发模式下,输入以上的地址,会返回 login 这个页面,而在单页面应用中,只有一个页面为 index.html )
所以说,在服务端应该除了静态资源外都返回单页应用的 index.html
在Nginx服务器中配置History 模式
二、Vue Router原理
9.27昨晚做梦了,梦见自己歇斯底里和男友吵架,砸东西。他给别的女孩子买东西,打电话甚至当着我的面了,无奈。他还是把那个手镯送给那个女生了,他很讨厌地看向我,像一只冷漠的怪兽。他说,你发什么疯啊,我凭什么要给你看,夺走了他的手机,他说和我在一起没有隐私。是啊,谁又愿意看这些呢?可是梦境也告诉我,没有用即使砸了东西即使发疯也没用,耗光了自己的力量。不要想念了,就永远忘记这个人吧。
妈妈生病住院,工作不好找,真的是寒冬啊。
每一天都是没有希望的一天。
========================
3、实现构造函数
vue响应式原理
3.2 Vue3
响应式原理
Vue3
的响应式原理是通过Proxy
来完成的。
Proxy
直接监听对象,而非属性,所以将多个属性转换成getter/setter
的时候,不需要使用循环。
Proxy
是ES6
课程中新增的,IE
不支持
Proxy
实现响应式的基本代码如下(该代码的功能与上面所讲解的是一样的):
6、模拟Vue响应式原理–Vue
当我们在使用Vue
的时候,首先会根据Vue
类来创建Vue
的实例。
那么Vue
类主要的功能如下:
- 负责接收初始化的参数(选项)
- 负责把
data
中的属性注入到Vue
实例,转换成getter/setter
(可以通过this
来访问data
中的属性) - 负责调用
observer
监听data
中所有属性的变化(当属性值发生变化后更新视图) - 负责调用
compiler
解析指令/差值表达式
结构
Vue
中包含了_proxyData
这个私有方法,该方法的作用就是将data
中的属性转换成getter/setter
并且注入到Vue
的实例中。
模拟Vue/js/vue.js
7、Observer
Observer
的功能
- 负责把
data
选项中的属性转换成响应式数据 data
中的某个属性也是对象,把该属性转换成响应式数据(例如data
中的某个属性为Student
对象,也要将Student
对象中的属性转换成响应式)- 数据变化发送通知
2、为什么使用Virtual DOM
-
手动操作
Dom
比较麻烦,还需要考虑浏览器兼容性问题,虽然有Jquery
等库简化DOM
操作,但是随着项目的复杂度越来越高,DOM
操作复杂提升,既要考虑Dom
操作,还要考虑数据的操作。 -
为了简化
DOM
的复杂操作于是出现了各种的MVVM
框架,MVVM
框架解决了视图和状态的同步问题,也就是当数据发生变化,更新视图,当视图发生变化更新数据。 -
为了简化视图的操作我们可以使用模板引擎,但是模板引擎没有解决跟踪状态变化的问题(当数据发生了变化后,无法获取上一次的状态,只有将页面上的元素删除,然后在重新创建,这时页面有刷新的问题,同时频繁操作
Dom
,性能也会非常低),于是Virtual Dom
出现了。 -
Virtual Dom
的好处就是当状态改变时不需要立即更新DOM
,只需要创建一个虚拟树来描述DOM
,Virtual Dom
内部将弄清楚如何有效(diff
)的更新DOM
.(例如:向用户添加列表中添加一个用户,只添加新的内容,原有的结构会被重用)下面,我们看一段代码,该代码是使用
jquery
来实现的数据展示与排序,是纯DOM
操作的方式
总结:
虚拟DOM
可以维护程序的状态,跟踪上一次的状态
通过比较前后两次状态的差异来更新真实DOM
3、虚拟DOM的作用
维护视图和状态的关系(虚拟DOM
会记录状态的变化,只需要更新状态变化的内容就可以了)
复杂视图情况下提升渲染性能。
下面我们看一个案例,该案例的功能比较简单,单击按钮后,更新div
中的内容。
let div=document.querySelector('#app')
let btn=document.querySelectory('#btn')
btn.onclick=function(){
div.textContent='Hello World'
}
以上代码非常简单,而且是使用DOM
操作的方式来实现的。
虚拟DOM
除了渲染DOM
以外,还可以实现渲染到其它的平台,例如可以实现服务端渲染(ssr
),原生应用(React Native
),小程序(uni-app
等)。以上列举的案例中,内部都使用了虚拟DOM
.
Vue
中虚拟DOM
生成真实DOM
的过程
4、Snabbdom基本使用
4.1 创建项目
在讲解Snabbdom
的基本使用之前,我们先来创建一个项目。
打包工具为了方便使用,使用了parcel
,你也可以使用webpack
.
下面创建项目,并安装parcel
Vuex状态管理
1、课程目标
Vuex
核心概念和基本使用回顾- 购物车案例
- 模拟实现
Vuex
2、组件内状态管理流程
下面我们通过组件内状态管理的流程来回顾一下什么是组件内状态管理。VUE
中最核心的两个功能就是数据驱动与组件化,使用组件化的开发,可以提高开发效率,提高可维护性。
3、简易的状态管理方案
在前面的课程中,我们讲解过多种的状态管理方案,例如,父组件向子组件传递数据,子组件向父组件传递数据,以及兄弟组件之间的数据传递等。但是当多个视图依赖同一状态,或者来自不同视图的行为需要变更同一状态的时候,以上的方案就变得非常的麻烦,而且让代码变得不可维护。
为了解决这些问题,我们可以将不同组件共享的状态抽取出来,存储到一个全局的对象中,并且保证在将来使用该对象的时候,它是响应式的。
4、什么是Vuex
Vuex
是专门为Vue.js
设计的状态管理库。
Vuex
采用集中式的方式存储需要共享的状态。
Vuex
的作用是进行状态管理,解决复杂组件通信,数据共享的问题。
什么情况下使用Vuex
?
非必要的情况下不要使用Vuex
如果是小项目,并且不会涉及到大量组件的通信,不需要使用Vuex
,使用反而增加了项目的复杂度。
如果是开发大型的单页应用程序,这时会涉及到多个视图依赖于同一状态,并且来自不同视图的行为需要变更同一状态,这时就需要用到Vuex
.
例如:我们后面所要实现的购物车案例。
Vue服务端渲染
一、服务端渲染基础
1、概述
我们现在可以使用Vue
,React
等开发SPA
单页面应用,单页面应用的优点,用户体验好,开发效率高,可维护性好等。
缺点:首屏渲染时间长(在客户端通过JS
来生成html
来呈现内容,用户需要等待客户端解析完js
才能够看到页面,这样导致首屏渲染时间变长)
不利于SEO
.(单页面的html
是没有内容的,需要客户端js
解析完才能够生成对应的内容,这样的情况不利于搜索引擎抓取对应的页面内容)
为了解决以上问题,需要借助于服务端的渲染来完成。
4、客户端渲染
在讲解服务端渲染的时候,我们知道了服务端渲染的一些问题,但是随着客户端AJAX
技术的普及,得到了有效的解决。
Ajax
使得客户端动态获取数据成为可能,也就是在服务端的渲染的工作,现在可以在客户端完成。这样带来的好处就是前后端代码完全分离,服务端提供接口,客户端访问接口获取数据,而且有利于前后端开发人员协同开发,提高开发效率。同时由于可以在客户端渲染,从而减轻了服务端的压力。而且也提高了用户体验,进行页面的切换的时候,不会刷新浏览器。
5、为什么客户端渲染首屏渲染慢?
所谓的首屏,是我们在浏览器中输入一个地址后,打开的第一个页面,就是首屏。
我们在浏览器的地址栏中输入了地址,向服务器发送请求,服务器返回的是一个空白HTML
,没有具体的数据内容,只有js
脚本,这时浏览器还会向服务器发送请求获取数据。
而服务端渲染,是在服务端获取数据,然后构建好对应的模板,生成HTML
返回到客户端,这样客户端无需再向服务器发送请求。这样通过对比可以看到,客户端渲染需要多次向服务器发送请求,所以导致渲染慢。
二、NuxtJS基础
1、什么是NuxtJS
一个基于Vue.js
生态的第三方开源服务端渲染应用框架。它可以帮我们轻松的使用Vue.js
技术栈构建同构应用。
一、Vue面试基础知识
1、computed和watch
computed
有缓存,如果数据data
没有发生变化的话,则不会重新计算。watch
如何实现深度的监听?watch
监听引用类型,获取不到oldValue
2、v-if与v-show
3、循环列表
key
的重要性,注意key
不能乱写,例如不能使用random
或者是index
v-for
和v-if
不能一起使用!v-for
的优先级要高于v-if
,这样的话就会先去执行循环,这样数组中的内容都循环完毕了,才会使用v-if
进行判断。这样判断会被执行多次,而且是重复的判断。
4、父子组件如何通信
父子组件的通信通过props
与$emit
完成,关于这块内容在前面的课程中已经重点讲解过了,这里不在进行讲解了。
beforeDestroy(){
event.$off('onAddSub',this.addSub)
}
6、生命周期
生命周期分为哪几个阶段?
- 挂载阶段
- 更新阶段
- 销毁阶段
重点理解官网中的图
7、自定义v-model
v-model
是vue
实现数据双向绑定最好的一个指令, v-model
本质上不过是语法糖,它负责监听用户的输入事件以更新数据,当你修改页面的时候 v-model
自动去更新数据层 (model)
,当你修改数据的时候v-model自动去更新视图层 (view
)
8、$nextTick
Vue
是异步渲染data
改变之后,DOM
不会立刻渲染$nextTick
会在DOM
渲染之后被触发,以获取最新的DOM
节点。
8、$nextTick
Vue
是异步渲染data
改变之后,DOM
不会立刻渲染$nextTick
会在DOM
渲染之后被触发,以获取最新的DOM
节点。
原因是:当data
中list
数组中的内容发生了变化后,DOM
元素并不会立即改变。这时获取到的DOM
元素的内容还是以前的内容。
但是,这里我们希望当单击完按钮后,立即获取到最新的DOM
元素内容,应该怎样处理呢?
把获取DOM
元素的内容放到$nextTick
方法对应的回调函数内部就可以了。
总结:第一:Vue
是异步渲染,$nextTick
是在DOM
渲染完以后才执行的。
第二:页面渲染时会将data
的修改做整合,也就是说多次data
修改只会渲染一次,例如上面的案例中,我们对list
数组做了三次的修改,但是最终只做了一次渲染。这样$nextTick
也就只调用了一次。
9、slot
基本使用
作用域插槽
具名插槽
10、动态组件
:is="component-name"
什么时候用:需要根据数据,动态渲染的场景,即组件类型不确定。
11、异步加载组件
在开发的时候,我们经常会加载一些体积比较大的组件,例如:编辑器,echarts
等,
而这些组件的加载非常消耗性能,为了提高性能,可以采用异步的方式来进行加载。
·import( )
函数实现按需加载,异步加载大组件
通过上面的代码,我们可以看到最开始的时候是不会加载FormDemo
这个组件的,当单击了show
按钮的时候才会加载该组件,但是在加载该组件的时候是通过import
方法来完成的,这就是异步加载组件,或者是按需加载,以前的加载方式是不管组件是否会用到都要进行加载,这其实就是同步的一种加载方式,这种方式会影响性能。
12、keep-alive
keep-alive
实现缓存组件
什么时候会用到缓存组件呢?
需要进行频繁切换,不需要重复渲染的情况下,可以考虑使用keep-alive
,例如 Tab
页签组件
这也是常见的一种优化的手段。
13、mixin
mixin
(混入)可以把多个组件中有相同的逻辑的内容,抽离出来。
通过这个案例,我们可以看到,如果有很多组件,而且这些组件都有相同的逻辑,那么可以将这些相同的逻辑通过混入的方式引入到组件中,而在组件中定义的都是自己独有的内容。
当然,mixin
也有自己的一些问题,
第一:变量来源不明确,不利于阅读,例如如下代码
<p>{{name}} {{major}} {{city}}</p>
假如当前组件混入了多项内容,那么在当前组件中我们使用了ciity
变量,而该变量到底来自哪,不容易被查找。
第二:多mixin
可能会造成命名冲突
第三点:mixin
和组件可能出现多对多的关系,复杂度较高。
例如:一个组件可以引用多个mixin
,而一个mixin
可以被多个组件所引用,这样复杂度较高以后,很容易出现错误。
当然为了解决mixin
的这些问题,在Vue3
中提出了Composition API
来进行解决。
二、Vue原理
1、MVVM
传统组件,只是静态渲染,更新还需要依赖于DOM
操作。
数据驱动–Vue.js
所谓的数据驱动的理念:当数据发生变化的时候,用户界面也会发生相应的变化,开发者并不需要手动的去修改dom
.
这样我们在开发的时候,更加关注的是数据(业务逻辑),而不是dom
操作。
三、常见面试题
1、为何在v-for中使用key
在v-for
中必须使用key
,key
的取值不能是index
和random
.
使用key
的原因:
在diff
算法中通过tag
和key
来判断,是否为sameNode
,减少渲染次数,提升渲染的性能
2、Vue组件如何通讯
父子组件:props
与this.$emit
自定义事件event.$on event.$emit
vuex
3、双向数据绑定v-model的实现原理
input
元素的value=this.msg
绑定input
事件this.msg=$event.target.value
data
更新触发render
4、computed的特点
缓存,data
不变不会重新计算
提高性能
5、为什么组件data必须是一个函数
组件就是一个类,我们去使用组件,实际上就是对组件的一个实例化,如果data
不是一个函数的话,每个组件实例的data
都是一样的,那这样就共享了。
6、多个组件有相同的逻辑,如何抽离
使用mixin
mixin
有一些缺点