Vue,Angular,React前端三大框架巨头,重要性不用多说,不过目前项目开发中主要用vue,现总结了一些Vue常用的知识点。
优点:
组件化、响应式、单页面路由(SPA)、轻量级、渐进式(随意component是否使用、vuex是否使用)
缺点:
不利于SEO、不支持IE8以下(因为defineproperty)、首屏加载时间长(SPA缺点)
理解:SPA只在页面初始化时加载相应的HTML、JS、和CSS。当页面加载完成之后,利用路由实现HTML内容的变换,UI与用户
的交互,而不会因为用户的操作进行页面的重新加载或跳转
优点:
用户体验感好,避免了不必要的跳转和重复渲染
SPA对服务器压力小
前后端职责分离
缺点:
初次加载耗时多,将JS、HTML、CSS统一加载
前进后退靠路由,不能使用浏览器的前进后退
SEO难度大
第一个M是Model,数据模型
第二个V是View,代表UI组件
VM为viewModel视图模型,是view和model的桥梁,同时监听模型数据以及控制视图行为。数据绑定到viewmodel层并自动渲染
到页面中,视图变化通知viewmodel层更新数据。
v-if:根据表达式的值的真假条件渲染元素。在切换时元素及它的数据绑定 / 组件被销毁并重建。
v-show:根据表达式之真假值,切换元素的 display CSS 属性。
v-for:循环指令,基于一个数组或者对象渲染一个列表,vue 2.0以上必须需配合 key值 使用。
v-bind:动态地绑定一个或多个特性,或一个组件 prop 到表达式。
v-on:用于监听指定元素的DOM事件,比如点击事件。绑定事件监听器。
v-model:实现表单输入和应用状态之间的双向绑定
v-pre:跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。
v-once:只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。用于优化更新性能。
参考 https://blog.csdn.net/weixin_58032613/article/details/122759818
.prevent 提交事件不再重载页面
.stop 阻止单击事件冒泡
.self 当事件发生在该元素本身而不是子元素时会触发
.capture 事件侦听,事件发生时会调用
.once 事件只触发一次
.passive 事件的默认行为立即执行无需等待事件回调执行完毕
因为组件是用来复用的,而js里对象是引用关系,如果组件中data是一个对象,那么作用域没有隔离,子组件中的data属性值
会相互影响。
而如果是函数的话,每个实例可以维护一份返回对象的独立拷贝,组件实例之间的data属性值不会相互影响。
v-if指令是直接销毁和重建DOM达到让元素显示和隐藏的效果。
v-show修改display的css属性控制元素的显示与隐藏。
v-show性能更好,如果只需要一次显示与隐藏,用v-if
Hash模式:
浏览器URL中'#'后的字符为hash,通过window.location.hash读取,通过hashchange事件来监听hash值的变化从而实现页面
跳转(渲染)。Hash不被包括在HTTP请求中,hash不会重加载页面。
History模式:
通过history.pushState来切换地址栏的路径,再通过监听popstate事件来操作浏览器的回退和前进按钮。而在这种模式下,
前端的URL必须要和后端发起请求的URL一致。(因为history模式改变URL方式会导致浏览器向服务器发送请求,因此要在服务器端
做处理,如果URL匹配不到任何静态资源,应该返回同一个index.html页面,这个页面就是app依赖的页面,在访问二级页面时,做
刷新操作会出现404错误,需要和后端配合配置一下Apache或是nginx的重定向,重定向到路由首页)
abstract模式:
支持所有的JS运行环境。如果发现没有浏览器的API,路由会自动强制进入这个模式。
Hash和history区别
Hash的URL会更改、浏览器可以前进和后退,但浏览器不会刷新并且不会和服务端交流。
History是规范的URL,无'#',能够访问到后台但是要和服务端的同事配合。
a.缓存组件,提升项目的性能。
b.假设首页进入详情页,如果用户在首页每次点击都是相同的,那么详情页就没必要重复请求,直接缓存起来。
如果点击的不是同一个,则直接请求。
c.提供 include 和 exclude 属性, include 表示只有名称匹配的组件会被缓存,exclude表示任何名称匹配的组件都不会被
缓存,其中 exclude 的优先级比 include 高
d.对应两个钩子函数 activated 和 deactivated ,当组件被激活时,触发钩子函数activated,当组件被移除时,触发钩子
函数 deactivated。
1.Props/$emit 适用父子组件通信
2.Ref父子组件通信
3.$parent/$children 父子组件通信
4.EventBus($emit/$on) 适用于父子、隔代、兄弟组件通信:以一个空的vue实例作为中央事件总线,用它来触发
和监听事件(发布订阅模式,)
5.$attrs/$listeners 适用于隔代组件通信($attrs包含了所有父组件在子组件上设置的属性,除了props传递的属性,
class,style。$listeners接收父组件的方法)
6.Provide/inject 适用于隔代组件通信(在父组件中通过provide来提供变量,在子组件通过inject来注入变量)
7.Vuex适用于父子、隔代、兄弟组件通信
a.computed 计算属性,依赖其他属性值有,有缓存;可以用getter获取数据,也可以用setter改变数据;
b.watch 监听数据,数据变化再进行后续操作;(immediate如果为true 代表如果在 wacth 里声明了之后,就会立即先去执行
里面的handler方法)
c.watch可以实现一些异步操作,比如在定时器多少秒之后触发方法,而computed靠return;
a.使回调函数延迟在DOM更新之后
b.比如说data中有个str,插值表达式在button里,我改变str的值,str在页面上的值发生了改变,但是打印dom元素依然是
以前的值,若要获取改变后的dom,需要将其放在$nextTick中
全局前置守卫:
beforeEach((to, from) => {
// ...to: 即将要进入的目标 from:当前导航正要离开的路由
// 返回 false 以取消导航
return false
})
全局后置钩子:
afterEach((to, from, failure) => {
if (!failure) sendToAnalytics(to.fullPath)
})
路由独享的守卫:
const routes = [
{
path: '/users/:id',
component: UserDetails,
beforeEnter: (to, from) => {
// reject the navigation
return false
},
},
]
组件内的守卫: beforeRouteEnter,beforeRouteUpdate,beforeRouteLeave
const UserDetails = {
template: `...`,
beforeRouteEnter(to, from) {
// 在渲染该组件的对应路由被验证前调用
// 不能获取组件实例 `this` !
// 因为当守卫执行时,组件实例还没被创建!
},
beforeRouteUpdate(to, from) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 `/users/:id`,在 `/users/1` 和 `/users/2` 之间跳转的时候,
// 由于会渲染同样的 `UserDetails` 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 因为在这种情况发生的时候,组件已经挂载好了,导航守卫可以访问组件实例 `this`
},
beforeRouteLeave(to, from) {
// 在导航离开渲染该组件的对应路由时调用
// 与 `beforeRouteUpdate` 一样,它可以访问组件实例 `this`
},
}
主要采用数据劫持+观察者模式。通过Object.defineProperty()来劫持各个属性的 setter,getter,在数据变动时发布消息
给订阅者,触发相应的监听回调。
双向数据绑定原理对初学者来说理解起来可能会比较复杂。但是面试过程中又是必问的点。所以会专门出一篇关于双向数据绑定原理。
的文章。
$route 获取路由信息
$router 进行路由跳转(传参:params和query)
query和params传参的区别:
query类似get,页面跳转url后面会拼接参数,类似?id=1,刷新页面id还存在。
params类似post,跳转之后url后面不会拼接参数,但是刷新页面id会消失。
vue实例有一个完整的生命周期,从开始创建、初始化数据、编译模板、挂载DOM->渲染、更新->渲染、卸载等一系列过程.
Ajax请求应该放在哪个生命周期?
created、beforeMount、Mounted都行,但最好放在created里面,因为此时已经可以访问this了(data已经被创建),
请求到数据就可以放在this里面.
在created中,能更快获得服务端数据,减少页面loading时间
SSR不支持beforemount、mounted钩子函数,放在created中有助于一致性
关于dom的操作都要放在mounted里面,此时vue已经将编译好的模板挂载在页面上,在mounted前访问dom会是undefined。
vue的父组件和子组件生命周期钩子函数执行顺序:
a) 加载渲染过程:父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate ->
子 created -> 子 beforeMount -> 子 mounted -> 父 mounted
b) 子组件更新过程:父 beforeUpdate -> 子 beforeUpdate -> 子 updated -> 父 updated
c) 父组件更新过程:父 beforeUpdate -> 父 updated
d) 销毁过程:父 beforeDestroy -> 子 beforeDestroy -> 子 destroyed -> 父 destroyed
a.vuex是状态管理器,在main.js中注入。
b.vuex有state,getter,mutation,action,module等5种属性。
c.state:存放数据,是响应式的,若是store中的数据发生改变,依赖这个数据的组件也会更新。
使用方法:
第一种:this.$store.state.全局数据名称
第二种:import { mapState } from "vuex";
computed;{
...mapState(["name""sex"])
}
d.getter:对state进行计算。可认为是store的计算属性,通过属性和方法访问。
e.mutation:唯一更改store中状态的方法,且必须是同步函数。
第一种:this.$store.commit("addcount",10)
第二种:
methods:{
...mapMutations(['addcount'])
}
f.action:类似mutation,action提交的是mutation,而不是直接变更状态,可以包含异步操作。
第一种:this.$store.dispatch("asynAdd")
第二种:
...Mapactions(['add'])
g.Module:允许将单一的store拆分为多个store且同时保存在单一的状态中
普通插槽渲染的作用域是父组件
作用域插槽渲染的作用域是当前子组件
单向数据流主要是vue组件间传递数据是单向的,即数据总是由父组件传递给子组件,子组件在其内部维护自己的数据,但它无权修改
父组件传递给它的数据,当开发者尝试这样做的时候,vue 将会报错。这样做是为了组件间更好的维护。
在开发中可能有多个子组件依赖于父组件的某个数据,假如子组件可以修改父组件数据的话,一个子组件变化会引发所有依赖这个数据
的子组件发生变化,所以 vue 不推荐子组件修改父组件的数据
通过用this.$set(对象,‘属性‘,值)实现动态添加属性,以实现数据的响应.如果是修改引用类型属性的值,是可以自动渲染的.
a.为了能简单复用每个元素,高效更新虚拟DOM。(Vue diff中有个过程是如果新老节点都有子节点的情况下,需要进行
updateChildren的操作,对比新老节点开始节点、结束节点共有四种比较方式,如果都没有匹配,设置了key就可以通
过key来比较
b.最好不要用index作为key,如果事件项顺序改变,会产生没有必要的真实DOM更新,页面效果没有问题但效率低。如果结
构中还包含输入类dom,那么可能会产生错误DOM更新。
query语法:
this.$router.push({path:"地址",query:{id:"123"}}); 这是传递参数
this.$route.query.id; 这是接受参数
params语法:
this.$router.push({name:"地址",params:{id:"123"}}); 这是传递参数
this.$route.params.id; 这是接受参数
1.写法的不同
query的语法用于path编写传参地址
params的语法用于name编写传参地址
2.接收方式不同
接受参数的时候用this.$route.params.name或者this.$route.query.name
3.两者中query在刷新页面的时候参数不会消失 但[params]
(https://so.csdn.net/so/search?q=params&spm=1001.2101.3001.7020)
在刷新页面的时候参数会消失 可以考虑本地存储解决此问题
4.query传过来的参数会显示到地址栏中 而params传过来的参数不会显示到地址栏中 直白的来说 query相当于get请求,
而params相当于post请求
在vue中,当我们像对象中添加属性,当数据变化时,页面也要随着变化,这时用到set()
set()原理
目标是对象,就用defineReactive 给新增的属性去添加getter 和 setter;
目标是数组,就直接调用数组本身的 splice 方法去触发响应式
关于vue的知识点这些还远远不够,还有一些原理部分,正在整理中.....
水平有限,如有错误,敬请指正。