网页看着不方便,想要文档可以私聊我。要是有错别字和错误的地方,请各位大佬直接指出,谢谢啦!!
Vue生命周期
一共8个阶段
详细说明生命周期:
beforeCreate:(创建前)在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
created:(创建后)在实例创建完成后被立即调用。在这一步,实例已完成以下的配置:数据观测 (data observer),属性和方法的运算,watch/event 事件回调。然而,挂载阶段还没开始,$el 属性目前尚不可用。
beforeMount:(载入前)在挂载开始之前被调用:相关的 render 函数首次被调用。该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。
mounted:(载入后)实例被挂载后调用,这时 el 被新创建的 vm.$el 替换了。 如果根实例挂载到了一个文档内的元素上,当mounted被调用时vm.$el也在文档内。该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。
beforeUpdate:(更新前)数据更新时调用,发生在虚拟 DOM 打补丁之前。这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。该钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。
updated:(更新后)由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在这之后会调用该钩子。当这个钩子被调用时,组件 DOM 已经更新,所以你现在可以执行依赖于 DOM 的操作。然而在大多数情况下,你应该避免在此期间更改状态。如果要相应状态改变,通常最好使用计算属性或 watcher 取而代之。
beforeDestroy:(销毁前)实例销毁之前调用。在这一步,实例仍然完全可用。
destroyed:(销毁后)实例销毁后调用。该钩子被调用后,对应 Vue 实例的所有指令都被解绑,所有的事件监听器被移除,所有的子实例也都被销毁。
errorCaptured(2.5.0版本之后新增的):当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播。
什么是vue生命周期?
Vue 实例从创建到销毁的过程,就是生命周期。从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、销毁等一系列过程,称之为 Vue 的生命周期。
vue生命周期的作用是什么?
它的生命周期中有多个事件钩子,让我们在控制整个Vue实例的过程时更容易形成好的逻辑。
vue生命周期总共有几个阶段?
它可以总共分为8个阶段:创建前/后, 载入前/后,更新前/后,销毁前/销毁后。
第一次页面加载会触发哪几个钩子?
会触发 下面这几个beforeCreate, created, beforeMount, mounted 。
DOM 渲染在 哪个周期中就已经完成?
DOM 渲染在 mounted 中就已经完成了。
Vue和其他框架的区别
React篇
React和Vue有许多相似之处,它们都有:
使用 Virtual DOM
提供了响应式(Reactive)和组件化(Composable)的视图组件。
将注意力集中保持在核心库,伴随于此,有配套的路由和负责处理全局状态管理的库。
性能:
到目前为止,针对现实情况的测试中,Vue的性能是优于React的
生态圈
Vue.js: ES6 Webpack unit/e2e Vue vue一router 单文件组件 vuex iVew
React: ES6 Webpack Enzyme React React一router Redux
什么时候选择Vue.js
如果你喜欢用(或希望能够用)模板搭建应用,请使用Vue
如果你喜欢简单和”能用就行”的东西,请使用Vue
如果你的应用需要尽可能的小和快,请使用Vue
如果你计划构建一个大型应用程序,请使用React
如果你想要一个同时适用于Web端和原生App的框架,请选择React
如果你想要最大的生态圈,请使用React
jQuery篇
jQuery 专注视图层,通过操作 DOM 去实现页面的一些逻辑渲染; Vue 专注于数据层,通过数据的双向绑定,最终表现在 DOM 层面,减少了 DOM 操作
Vue 使用了组件化思想,使得项目子集职责清晰,提高了开发效率,方便重复利用,便于协同开发
AngularJS篇
相同点:
都支持指令:内置指令和自定义指令;都支持过滤器:内置过滤器和自定义过滤器;都支持双向数据绑定;都不支持低端浏览器。
不同点:
AngularJS的学习成本高,比如增加了Dependency Injection特性,而Vue.js本身提供的API都比较简单、直观;在性能上,AngularJS依赖对数据做脏检查,所以Watcher越多越慢;Vue.js使用基于依赖追踪的观察并且使用异步队列更新,所有的数据都是独立触发的。
V指令
Vue内置指令
完成指定功能分为两种:
1,内置的。
2.用户自定义的。
1.v-bind:属性名 = ‘变量’
功能:将data:{变量:值}中的属性值,绑定到html标签的属性上
2.v-if指令:
true 添加到当前DOM结构中
false 从当前DOM结构中移除
3.v-for="value in 数组"
遍历数组或对象
4.v-on:事件名="事件处理函数"
事件绑定 可以绑定多个方法
5.v-model 双向数据绑定的指令:
将变量和表单项进行绑定
6.v-once只绑定一次
<span v-once>Message:{{msg}}</span><br><!—v-once类似jquery的one()-->
7.v-html把字符串转成HTML编译
你的站点上动态渲染的任意 HTML 可能会非常危险,
因为它很容易导致 XSS 攻击。请只对可信内容使用 HTML 插值,
绝不要对用户提供的内容插值。
vue-cli如何新增自定义指令?
1.创建局部指令
var app = new Vue({
el: '#app',
data: {
},
// 创建指令(可以多个)
directives: {
// 指令名称
dir1: {
inserted(el) {
// 指令中第一个参数是当前使用指令的DOM
console.log(el);
console.log(arguments);
// 对DOM进行操作
el.style.width = '200px';
el.style.height = '200px';
el.style.background = '#000';
}
}
}
})
2.全局指令
Vue.directive('dir2', {
inserted(el) {
console.log(el);
}
})
3.指令的使用
<div id="app">
<div v-dir1></div>
<div v-dir2></div>
</div>
v-if 和 v-show 区别
v-show 仅仅控制元素的显示方式,将 display 属性在 block 和 none 来回切换;而v-if会控制这个 DOM 节点的存在与否。当我们需要经常切换某个元素的显示/隐藏时,使用v-show会更加节省性能上的开销;当只需要一次显示或隐藏时,使用v-if更加合理。
Vue模板语法-插值
插入文本:数据绑定最常见的形式就是使用 “Mustache” 语法(双大括号)的文本插值
插入属性: {{ }}不能在 HTML 属性中使用,应使用 v-bind 指令
vue几种常用的指令
v-for 、 v-if 、v-bind、v-on、v-show、v-else
修饰符:(Modifiers)
是以半角句号 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。
事件修饰符:
例如:
.prevent 修饰符告诉 v-on 指令对于触发的事件调用
.stop 阻止单击事件冒泡
.prevent 提交事件不再跳转
.capture 添加事件侦听器时使用事件捕获模式(由外而内触发) demo7
.self 只当事件在该元素本身(比如不是子元素)触发时触发回调 ,不会引发事件冒泡
.once 点击事件将只会触发一次
说明:<a v-on:click.stop.prevent="doThat"></a>修饰符可以串联
例:
<!-- v-on:click.prevent阻止a标记默认动作,类似于原生的e.preventDefault() -->
<a v-bind:href="url" v-on:click.prevent="show">去百度</a>
键值修饰符:
在监听键盘事件时,我们经常需要监测常见的键值。 Vue 允许为 v-on 在监听键盘事件时添加关键修饰符:
计算属性
computed
可以像绑定普通属性一样在模板中绑定计算属性。Vue 知道 vm.reversedMessage 依赖于 vm.message ,因此当 vm.message 发生改变时,所有依赖于 vm.reversedMessage 的绑定也会更新。而且最妙的是我们已经以声明的方式创建了这种依赖关系:
计算属性的 getter 是没有副作用,这使得它易于测试和推理。
计算属性与methods的区别
可以将同一函数定义为一个 method 而不是一个计算属性。对于最终的结果,两种方式确实是相同的。然而,不同的是计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会重新求值。这就意味着只要 message 还没有发生改变,多次访问 reversedMessage 计算属性会立即返回之前的计算结果,而不必再次执行函数。相比而言,只要发生重新渲染,method 调用总会执行该函数。
计算属性与watch的区别
计算属性是把属性缓存起来,如果从新render时,属性没有变化,则不会再从新渲染这个属性。
Watch是监控data属性,如果data改变,就可以在watch中做一些改变。
什么是vue的计算属性?
在模板中放入太多的逻辑会让模板过重且难以维护,在需要对数据进行复杂处理,且可能多次使用的情况下,尽量采取计算属性的方式。好处:①使得数据处理结构清晰;②依赖于数据,数据更新,处理结果自动更新;③计算属性内部this指向vm实例;④在template调用时,直接写计算属性名即可;⑤常用的是getter方法,获取数据,也可以使用set方法改变数据;⑥相较于methods,不管依赖的数据变不变,methods都会重新计算,但是依赖数据不变的时候computed从缓存中获取,不会重新计算。
插槽slot
在实际项目开发当中,时常会把父组件的内容与子组件自己的模板混合起来使用。而这样的一个过程在Vue中被称为内容分发。也常常被称为slot插槽。
Vue的双向绑定数据的原理
vue 实现数据双向绑定主要是:采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty() 来劫持各个属性的 setter,getter,在数据变动时发布消息给订阅者,触发相应监听回调。
单向数据流和双向数据绑定
单向数据流:
顾名思义,数据流是单向的。数据流动方向可以跟踪,流动单一,追查问题的时候可以更快捷。缺点就是写起来不太方便。要使UI发生变更就必须创建各种 action 来维护对应的 state
双向数据绑定:
数据之间是相通的,将数据变更的操作隐藏在框架内部。优点是在表单交互较多的场景下,会简化大量与业务无关的代码。缺点就是无法追踪局部状态的变化,增加了出错时 debug 的难度
Vue 如何去除url中的 #
vue-router 默认使用 hash 模式,所以在路由加载的时候,项目中的 url 会自带 #。如果不想使用 #, 可以使用 vue-router 的另一种模式 history
new Router({
mode: 'history',
routes: [ ]
})
需要注意的是,当我们启用 history 模式的时候,由于我们的项目是一个单页面应用,所以在路由跳转的时候,就会出现访问不到静态资源而出现 404 的情况,这时候就需要服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面
组件通信
父组件向子组件通信
子组件通过 props 属性,绑定父组件数据,实现双方通信
子组件向父组件通信
将父组件的事件在子组件中通过 $emit 触发
非父子组件、兄弟组件之间的数据传递
vue-router相关
vue-router是什么 它有哪些组件?
vue用来写路由一个插件。router-link、router-view
vue-router 路由实现
路由就是用来跟后端服务器进行交互的一种方式,通过不同的路径,来请求不同的资源,请求不同的页面是路由的其中一种功能
$route和$router的区别
$router 为 VueRouter 实例,想要导航到不同 URL,则使用 $router.push 方法
$route 为当前 router 跳转对象里面可以获取 name 、 path 、 query 、 params 等
$route是“路由信息对象”,包括path,params,hash,query,fullPath,matched,name等路由信息参数。而$router是“路由实例”对象包括了路由的跳转方法,钩子函数等。
怎么定义vue-router的动态路由?
在router目录下的index.js文件中,对path属性加上/:id。 使用router对象的params.id
vue路由的钩子函数
怎么获取传过来的动态参数?
首页可以控制导航跳转,beforeEach,afterEach等,一般用于页面title的修改。一些需要登录才能调整页面的重定向功能。
beforeEach主要有3个参数to,from,next:
to:route即将进入的目标路由对象,
from:route当前导航正要离开的路由
next:function一定要调用该方法resolve这个钩子。执行效果依赖next方法的调用参数。可以控制网页的跳转。
Vue的路由实现:
hash模式 和 history模式
hash模式:在浏览器中符号“#”,#以及#后面的字符称之为hash,用window.location.hash读取。
特点:hash虽然在URL中,但不被包括在HTTP请求中;用来指导浏览器动作,对服务端安全无用,hash不会重加载页面。
hash 模式下,仅 hash 符号之前的内容会被包含在请求中,因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回 404 错误。
history模式:history采用HTML5的新特性;且提供了两个新方法:pushState(),replaceState()可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更。
history 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致。后端如果缺少对 /items/id 的路由处理,将返回 404 错误。Vue-Router 官网里如此描述:“不过这种模式要玩好,还需要后台配置支持……所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。”
前端怎么控制管理路由
可以通过vue-router实例来配置路由规则列表,指定路径path与组件component的对应关系。可以通过mode这一参数控制路由的实现模式,默认值是hash,基于hash的实现方式,如果显示设置为history,则会设为基于history API的实现方式,如果浏览器不支持,可以设置fallback来控制是否需要回滚为'hash'模式。另外,如果是非浏览器端运行(如nodejs中),会将mode强制设为'abstract'模式。
vue-router支持路由嵌套、动态路由的配置、重定向及别名等,可参看官方文档。
前端路由的实现方式
在HTML5的 history API出现之前,前端路由主要是通过 hash 来实现的,hash能兼容低版本的浏览器。下面分别来介绍这2种方式。
方法一:基于hash(location.hash hashchange事件)
我们知道location.hash的值是url中#后面的内容,如http://www.163.com#netease此网址中,location.hash='#netease'。hash满足以下几个特性,才使得其可以实现前端路由:
url中hash值的变化并不会重新加载页面,因为hash是用来指导浏览器行为的,对服务端是无用的,所以不会包括在http请求中。
hash值的改变,都会在浏览器的访问历史中增加一个记录,也就是能通过浏览器的回退、前进按钮控制hash的切换
我们可以通过hashchange事件,监听到hash值的变化,从而响应不同路径的逻辑处理。
window.addEventListener("hashchange", funcRef, false)
如此一来,我们就可以在hashchange事件里,根据hash值来更新对应的视图,但不会去重新请求页面,同时呢,也在history里增加了一条访问记录,用户也仍然可以通过前进后退键实现UI的切换。
触发hash值的变化有2种方法:
一种是通过a标签,设置href属性,当标签点击之后,地址栏会改变,同时会触发hashchange事件
<a href="#kaola">to KAOLA</a>
另一种是通过js直接赋值给location.hash,也会改变url,触发hashchange事件。
location.hash="#kaola"
route是一条路由,是将一个URL路径和一个处理函数相关联,是一条url和函数的映射规则,如上面代码中通过原型上的route可以设置一条路由规则,将一个path和其callback关联起来。
而router则更像是一个容器,或者说一种机制,它管理了一组route。简单来说,route只是进行了URL和函数的映射,而在当接收到一个URL之后,去路由映射表中查找相应的函数,这个过程是由router来处理的,如上面代码,Router管理传入的route,并且在hash改变的时候,根据当前的url响应其对应的函数。
方法二:基于History新API(history.pushState() popState事件)
HTML5中history对象上新的API,同样能实现前端的路由。通过pushState()方法或replaceState()方法可以修改url的地址,并在popstate事件中能监听地址的改变,不同的是,手动的进行pushState()并不会触发popstate事件。
先认识下两个新增的API:history.pushState和 history.replaceState,这两个API都接收三个参数:
window.history.pushState(null, null, "http://www.163.com");
状态对象(state object),一个JavaScript对象,与用pushState()方法创建的新历史记录条目关联。无论何时用户导航到新创建的状态,会触发popstate事件,并能在事件中使用该对象。
标题(title) :传入一个短标题给当前state。现在大多数浏览器不支持或者会忽略此参数,最好传入null代替;
地址(URL):新的历史记录条目的地址。浏览器不会在调用pushState()方法后加载该地址,但之后,可能会试图加载,例如用户重启浏览器。新的URL不一定是绝对路径;如果是相对路径,它将以当前URL为基准;传入的URL与当前URL应该是同源的,否则,pushState()会抛出异常。该参数是可选的;不指定的话则为文档当前URL。
这两个API的相同之处是都会操作浏览器的历史记录,而不会引起页面的刷新。不同之处在于,pushState会增加一条新的历史记录,而replaceState则会替换当前的历史记录。这两个api,加上state改变触发的popstate事件,提供了单页应该的另一种路由方式。
当我们在历史记录中切换时就会触发 popstate 事件,可以在事件中还原当前state对应的UI。对于触发popstate 事件的方式,各浏览器实现也有差异,我们可以根据不同浏览器做兼容处理。
两种方式对比,基于Hash的路由,兼容性更好;基于History API的路由,则更正式,可以设置与当前URL同源的任意URL,路径更直观。另外,基于Hash的路由不需要对服务器做改动,基于History API的路由需要对服务器做一些改造,配置不同的路由都返回相同的页面。
使用路由时出现问题如何解决
路由的匹配规则是按照书写的顺序执行的,第一条匹配成功则不去匹配下一条,利用这一特性,可以在所有匹配路由的下面拦截匹配所有路由:
//创建路由对象并配置路由规则
let router = new VueRouter({
routes:[
{path:'/',redirect:{name:"home"}}, // 重定向到主页
{name:'home',path:'/home',component:Home},
{name:'login',path:'/login',component:Login},
{path:'*',component:NotFound},//全不匹配的情况下,匹配NotFound组件,路由按顺序从上到下,依次匹配。最后一个*能匹配全部,
]
});
原理同方法2,只不过在匹配到*时,重定向到根路径:
//创建路由对象并配置路由规则
let router = new VueRouter({
routes:[
{path:'/',redirect:{name:"home"}}, // 重定向到主页
{name:'home',path:'/home',component:Home},
{name:'login',path:'/login',component:Login},
{path:'*',redirect:'/'},//路由按顺序从上到下,依次匹配。最后一个*能匹配全部,然后重定向到主页面
]
});
history 路由和 hash 路由的区别, 在浏览器有什么影响?
hash前端路由,无刷新
history 会去请求接口
vue-router提供两种模式的原因?
vue 是渐进式前端开发框架,为了实现 SPA ,需要引入前端路由系统(vue-router)。前端路由的核心是:改变视图的同时不会向后端发出请求。
为了达到这一目的,浏览器提供了 hash 和 history 两种模式。
1. hash :hash 虽然出现在 URL 中,但不会被包含在 http 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。
2. history :history 利用了 html5 history interface 中新增的 pushState() 和 replaceState() 方法。这两个方法应用于浏览器记录栈,在当前已有的 back、forward、go 基础之上,它们提供了对历史记录修改的功能。只是当它们执行修改时,虽然改变了当前的 URL ,但浏览器不会立即向后端发送请求。
因此可以说, hash 模式和 history 模式都属于浏览器自身的属性,vue-router 只是利用了这两个特性(通过调用浏览器提供的接口)来实现路由。
实现的原理
1. hash 模式的原理是 onhashchange 事件,可以在 window 对象上监听这个事件。
2. history :hashchange 只能改变 # 后面的代码片段,history api (pushState、replaceState、go、back、forward) 则给了前端完全的自由,通过在window对象上监听popState()事件。
pushState()、replaceState() 方法接收三个参数:stateObj、title、url。 // 设置状态
history.pushState({color: "red"}, "red", "red");
// 监听状态window.onpopstate = function(event){
console.log(event.state);
if(event.state && event.state.color === "red"){
document.body.style.color = "red";
}} // 改变状态history.back();history.forward();复制代码
应用场景
通过 pushState 把页面的状态保存在 state 对象中,当页面的 url 再变回到这个 url 时,可以通过 event.state 取到这个 state 对象,从而可以对页面状态进行还原,如页面滚动条的位置、阅读进度、组件的开关等。
调用 history.pushState() 比使用 hash 存在的优势:
• pushState 设置的 url 可以是同源下的任意 url ;而 hash 只能修改 # 后面的部分,因此只能设置当前 url 同文档的 url
• pushState 设置的新的 url 可以与当前 url 一样,这样也会把记录添加到栈中;hash 设置的新值不能与原来的一样,一样的值不会触发动作将记录添加到栈中
• pushState 通过 stateObject 参数可以将任何数据类型添加到记录中;hash 只能添加短字符串
• pushState 可以设置额外的 title 属性供后续使用
劣势:
• history 在刷新页面时,如果服务器中没有相应的响应或资源,就会出现404。因此,如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面
• hash 模式下,仅 # 之前的内容包含在 http 请求中,对后端来说,即使没有对路由做到全面覆盖,也不会报 404
单页应用,如何实现其路由功能---路由原理
写在前面:通常 SPA 中前端路由有2种实现方式:
1. window.history
2. location.hash
下面就来介绍下这两种方式具体怎么实现的
一.history
1.history基本介绍
window.history 对象包含浏览器的历史,window.history 对象在编写时可不使用 window 这个前缀。history是实现SPA前端路由是一种主流方法,它有几个原始方法:
- history.back() - 与在浏览器点击后退按钮相同
- history.forward() - 与在浏览器中点击按钮向前相同
- history.go(n) - 接受一个整数作为参数,移动到该整数指定的页面,比如go(1)相当于forward(),go(-1)相当于back(),go(0)相当于刷新当前页面
- 如果移动的位置超出了访问历史的边界,以上三个方法并不报错,而是静默失败
在HTML5,history对象提出了 pushState() 方法和 replaceState() 方法,这两个方法可以用来向历史栈中添加数据,就好像 url 变化了一样(过去只有 url 变化历史栈才会变化),这样就可以很好的模拟浏览历史和前进后退了,现在的前端路由也是基于这个原理实现的。
2.history.pushState
pushState(stateObj, title, url) 方法向历史栈中写入数据,其第一个参数是要写入的数据对象(不大于640kB),第二个参数是页面的 title, 第三个参数是 url (相对路径)。
- stateObj :一个与指定网址相关的状态对象,popstate事件触发时,该对象会传入回调函数。如果不需要这个对象,此处可以填null。
- title:新页面的标题,但是所有浏览器目前都忽略这个值,因此这里可以填null。
- url:新的网址,必须与当前页面处在同一个域。浏览器的地址栏将显示这个网址。
关于pushState,有几个值得注意的地方:
pushState方法不会触发页面刷新,只是导致history对象发生变化,地址栏会有反应,只有当触发前进后退等事件(back()和forward()等)时浏览器才会刷新
这里的 url 是受到同源策略限制的,防止恶意脚本模仿其他网站 url 用来欺骗用户,所以当违背同源策略时将会报错
3.history.replaceState
replaceState(stateObj, title, url) 和pushState的区别就在于它不是写入而是替换修改浏览历史中当前纪录,其余和 pushState一模一样
4.popstate事件
定义:每当同一个文档的浏览历史(即history对象)出现变化时,就会触发popstate事件。
注意:仅仅调用pushState方法或replaceState方法 ,并不会触发该事件,只有用户点击浏览器倒退按钮和前进按钮,或者使用JavaScript调用back、forward、go方法时才会触发。另外,该事件只针对同一个文档,如果浏览历史的切换,导致加载不同的文档,该事件也不会触发。
用法:使用的时候,可以为popstate事件指定回调函数。这个回调函数的参数是一个event事件对象,它的state属性指向pushState和replaceState方法为当前URL所提供的状态对象(即这两个方法的第一个参数)。
二.Hash
1.Hash基本介绍
url 中可以带有一个 hash http://localhost:9000/#/a.html
window 对象中有一个事件是 onhashchange,以下几种情况都会触发这个事件:
- 直接更改浏览器地址,在最后面增加或改变#hash;
- 通过改变location.href或location.hash的值;
- 通过触发点击带锚点的链接;
- 浏览器前进后退可能导致hash的变化,前提是两个网页地址中的hash值不同。
vue-router如何做用户登录权限等
router官网中进阶部分提供了导航守卫的功能,可以通过设置全局前置守卫或者路由独享守卫来做用户登陆权限的判别。
怎么定义 vue-router 的动态路由? 怎么获取传过来的值
答:在 router 目录下的 index.js 文件中,对 path 属性加上 /:id,使用 router 对象的 params.id 获取。
vue-router原理
一、vue-router——路由管理
路由配置主要有三个关键字:route routes router
route(单数)表示一条路由,它是一个对象由两部分构成(path——路径;component——组件)
例如:homeBtn——homeContent(点击homeBtn按钮页面切换到homeContent组件);sideBtn——sideContent;这是两条路由(route)
如果路由多,这样一条一条表示显然不合理。
由此出现routes(复数)表示一组路由(路由的数组),上面的两条路由就可以这样表示:
image
具体写法:const routes = [{path:'/home',component:homeContent},{path:'/sidebar',component:sidebarContent}]
router表示路由机制(即路由的管理者),实现原理:点击homeBtn按钮——到routes里去查找到‘/home’对应得组件homeContent,并显示页面。
写法:const router = new VueRouter({routes:routes}),简写:const router = new VueRouter({routes})
最后将router实例注入到vue根实例中,便可以使用路由
配置好路由再定义好路由的出口router-view就可以使用路由实现页面跳转了。
ps:router-link相当于a标签。
二、vuex——数据状态管理
简单说下vuex的作用:主要用于组件直接通讯。比如A和B和C为兄弟组件,组件中都用到name这个字段,A组件中如果对name字段进行更改,那该如何通知B和C组件name字段已经发生变化了呢?这个时候就可以使用Vuex来进行通讯了。先将name存起来(state管理变量初始状态的),A组件中通过触发mutation来通知state中的name发生改变。那么B和C组件就可以从vuex获取state中的name。大概就是这么个意思。
另外说一下:vuex中的几个关键要素:state、mutation、action以及vuex中自带的函数:mapState、mapMutation、mapAction、mapGetter(都是个人的理解,如有不当请指出。)
state主要定义一些初始化的变量;
mutation定义修改State的方法,有两个参数(state、value)
action定义触发mutation行为的方法;语法:方法名(context)、通过context.commit来触发mutation的方法;
getter定义获取state的方法,参数state;
上面内容主要说如何定义这些变量,下面说下如果在组件中使用这些方法:
第一种情况:设置/修改变量的两种方式:
a、在计算属性中或方法中调用mutation方法:this.$store.commit(‘方法名’,参数值)
b、使用action触发mutation方法:this.$store.dispatch(mutaion的方法)
官方不建议使用a,建议使用b。
第二种情况:获取参数
两种方式:1、this. store.getter.方法名
使用this.$store.state等这些书写方式太长。所以可以通过vuex的辅助函数:mapState等来简化书写
辅助函数的使用方法:
1、mapGetters/apState放在computed属性中。
书写方式:a、...mapGetters(['Getter定义的方法名'])
b、参数如果是count:...mapState({state=>state.count})
2、mapMutation和mapAction,一般放在method中写:...mapMutation(['mutation定义的方法名'])
active-class是哪个组件的属性?嵌套路由怎么定义?
答:vue-router模块的router-link组件。children数组来定义子路由
MVVM
谈谈你对MVVM开发模式的理解
MVVM分为Model、View、ViewModel三者。
Model 代表数据模型,数据和业务逻辑都在Model层中定义;
View 代表UI视图,负责数据的展示;
ViewModel 负责监听 Model 中数据的改变并且控制视图的更新,处理用户交互操作;
Model 和 View 并无直接关联,而是通过 ViewModel 来进行联系的,Model 和 ViewModel 之间有着双向数据绑定的联系。因此当 Model 中的数据改变时会触发 View 层的刷新,View 中由于用户交互操作而改变的数据也会在 Model 中同步。
这种模式实现了 Model 和 View 的数据自动同步,因此开发者只需要专注对数据的维护操作即可,而不需要自己操作 dom。
为什么会出现MVVM
前端开发中暴露出了三个痛点问题:
• 开发者在代码中大量调用相同的 DOM API,处理繁琐 ,操作冗余,使得代码难以维护。
• 大量的 DOM 操作使页面渲染性能降低,加载速度变慢,影响用户体验。
• 当 Model 频繁发生变化,开发者需要主动更新到 View ;当用户的操作导致 Model 发生变化,开发者同样需要将变化的数据同步到 Model 中,这样的工作不仅繁琐,而且很难维护复杂多变的数据状态。其实,早期 jquery 的出现就是为了前端能更简洁的操作 DOM 而设计的,但它只解决了第一个问题,另外两个问题始终伴随着前端一直存在。MVVM 的出现,完美解决了以上三个问题。
DOM
什么是虚拟
虚拟DOM概念随着react的诞生而诞生,由facebook提出,其卓越的性能很快得到广大开发者的认可;继react之后vue2.0也在其核心引入了虚拟DOM的概念
vdom可以看作是一个使用javascript模拟了DOM结构的树形结构,这个树结构包含整个DOM结构的信息.。dom 树对应的虚拟 dom 对象( js 对象)
虚拟dom的原理
diff算法 深度优先遍历
diff的过程就是调用patch函数,就像打补丁一样修改真实dom
virtual dom有哪些好处
• 虚拟 DOM 不会立马进行排版与重绘操作
• 虚拟 DOM 进行频繁修改,然后一次性比较并修改真实 DOM 中需要改的部分,最后在真实 DOM 中进行排版与重绘,减少过多DOM节点排版与重绘损耗
• 虚拟 DOM 有效降低大面积真实 DOM 的重绘与排版,因为最终与真实 DOM 比较差异,可以只渲染局部
虚拟DOM主要做了什么虚拟DOM本身是什么(JS对象)为什么虚拟 DOM 的操作比 DOM 更快;
总之,一切为了减弱频繁的大面积重绘引发的性能问题,不同框架不一定需要虚拟DOM,关键看框架是否频繁会引发大面积的DOM操作
你的知道浏览器的虚拟DOM与真实DOM的区别(注意:需不需要虚拟DOM,其实与框架的DOM操作机制有关):
虚拟DOM不会进行排版与重绘操作
虚拟DOM进行频繁修改,然后一次性比较并修改真实DOM中需要改的部分(注意!),最后并在真实DOM中进行排版与重绘,减少过多DOM节点排版与重绘损耗
真实DOM频繁排版与重绘的效率是相当低的
虚拟DOM有效降低大面积(真实DOM节点)的重绘与排版,因为最终与真实DOM比较差异,可以只渲染局部(同2)
使用虚拟DOM的损耗计算:
总损耗=虚拟DOM增删改 (与Diff算法效率有关)真实DOM差异增删改 (较少的节点)排版与重绘
直接使用真实DOM的损耗计算:
总损耗=真实DOM完全增删改 (可能较多的节点)排版与重绘
总之,一切为了减弱频繁的大面积重绘引发的性能问题,不同框架不一定需要虚拟DOM,关键看框架是否频繁会引发大面积的DOM操作
说一下virtual Dom中key的作用
实际的标签中可能存在两个一模一样的两个节点,但是在virtual Dom中无法体现这个区别,另一方面为了加快diff算法的速度,一个区别节点的变量的需求变得非常必要。virtual Dom中需要给每个节点一个标识,作为判断是同一个节点的依据。所以这也是 Vue 和 React 中官方推荐列表里的节点使用唯一的 key 来保证性能。其中在diff算法中,大量使用了利用tagName和key组合判断节点之间差异的逻辑代码
为什么要使用虚拟DOM?
虚拟 dom 是相对于浏览器所渲染出来的真实 dom 的,在react,vue等技术出现之前,我们要改变页面展示的内容只能通过遍历查询 dom 树的方式找到需要修改的 dom 然后修改样式行为或者结构,来达到更新 ui 的目的。这种方式相当消耗计算资源,因为每次查询 dom 几乎都需要遍历整颗 dom 树,如果建立一个与 dom 树对应的虚拟 dom 对象( js 对象),以对象嵌套的方式来表示 dom 树,那么每次 dom 的更改 就变成了 js 对象的属性的更改 ,这样一来就能查找 js 对象的属性变化要比查询 dom 树的 性能开销小。
其实并不是查询 dom 树性能开销大而是 dom 树的实现模块和 js 模块是分开的这些跨模块的通讯增加了成本,以及 dom 操作引起的浏览器的回流和重绘,使得性能开销巨大,原本在 pc 端是没有性能问题的,因为 pc 的计算能力强,但是随着移动端的发展,越来越多的网页在智能手机上运行,而手机的性能参差不齐,会有性能问题。
他们的思想是每次更新 dom 都尽量避免刷新整个页面,而是有针对性的 去刷新那被更改的一部分 ,来释放掉被无效渲染占用的 gpu,cup 性能。
Vuex
是什么?怎么使用?哪种功能场景使用它?
vue框架中状态管理。在main.js引入store,注入。
新建了一个目录store.js,….. export 。
场景有:单页应用中,组件之间的状态。音乐播放、登录状态、加入购物车
vuex有哪几种属性?
有五种,分别是 State、 Getter、Mutation 、Action、 Module
state => 基本数据(数据源存放地)
getters => 从基本数据派生出来的数据
mutations => 提交更改数据的方法,同步!
actions => 像一个装饰器,包裹mutations,使之可以异步。
modules => 模块化Vuex
你是怎么认识vuex的?
vuex可以理解为一种状态管理的开发模式或者框架,data中的属性需要共享给其他vue组件使用。状态为state集中放在store中; 改变状态的方式是提交mutations,这是个同步的事物; 异步逻辑应该封装在action中。
vuex数据流动过程
1、vuex是什么
公共状态管理
解决多个非父子组件传值问题。
多个页面都能用Vuex中store公共的数据
a、并不是所有的数据都要放在Vuex中,只有各个组件公用的一些数据会放在Vuex当中
b、Vuex是一个公共状态管理模式 并不是数据库 所以不可能持久保存一些数据,当用户刷新浏览器的时候那么数据就有可能消失
c、Vuex主要应用在大型的单页面开发中
2、vuex的特点
1、遵循单向数据流
2、Vuex中的数据是响应式的
3、vuex的流程图:
总结下vuex数据传输流程
1、通过new Vuex.Store()创建一个仓库 state是公共的状态,state—>components渲染页面
2、在组件内部通过this.$store.state.属性 来调用公共状态中的state,进行页面的渲染。
3、当组件需要修改数据的时候,必须遵循单向数据流。组件里在methods中扩展mapActions,调用store里的actions里的方法。
4、actions中的每个方法都会接受一个对象 这个对象里面有一个commit方法,用来触发mutations里面的方法
5、mutations里面的方法用来修改state中的数据 mutations里面的方法都会接收到2个参数 一个是store中的state, 另外一个是需要传递到参数
6、当mutations中的方法执行完毕后state会发生改变,因为vuex的数据是响应式的 所以组件的状态也会发生改变
vuex的理解 对无状态组件的理解,使用过程中遇到的问题,如何解决的
watch computed区别
1、methods,computed的区别
例子:
var vm = new Vue({
el: '#app',
data: {
msg: 'nihao',
text: 'byebye'
},
computed: {
getmsg: function () {
return this.msg
}
},
methods:{
gettext:function () {
return this.msg
}
}
})
<p>msg:{{getmsg}}</p>
<p>text:{{gettext()}}</p>
在这个例子中,只要msg值发生变化,getmsg方法就会触发,而text的值发生变化,只要没有调用gettext方法,显示的值不会动态改变。就是说,methods中就是普通的方法,通过调用执行,computed中的方法会监听自己的依赖,依赖发生变化方法会自动执行。
1. computed 和methods 达到的效果是相同的
2. 计算属性computed和methods都不应该使用箭头函数来定义计算属性 因为箭头函数绑定了父级作用域的上下文,所以 this 将不会按照期望指向Vue
不同点是:
3. 计算属性compute是基于他们的依赖(如果是实例范畴之外的依赖,比如非响应式的not reactive是不会触发属性更新的)进行缓存(计算属性的结果会被缓存),只有相关依赖会发生改变时才会重新求值,未改变只会返回只之前的结果,不在执行函数 .原值与新值一样不会触发,函数的返回值就是最终获取的值.
4. computed是响应式的,methods并非响应式。
5. 调用方式不一样,computed定义的成员像属性一样访问,methods定义的成员必须以函数形式调用。
6. computed是带缓存的,只有其引用的响应式属性(属性绑定)发生改变时才会重新计算(如果引用的属性没有改变,则调用上一次缓存值),而methods里的函数在每次调用时都要执行
7. computed中的成员可以只定义一个函数作为只读属性,也可以定义get/set变成可读写属性,这点是methods中的成员做不到的。 computed 计算属性的方法在用属性时不用加(),而methods 方法在使用时要像方法一样去用,必须必须要加(){{ mes() }}
默认加载的时候先computed再watch,不执行methods;等触发某一事件后,则是:先methods再watch。
watch适合处理的场景是,侦听一个数的变化,当该数据变化,来处理其他与之相关数据的变化(该数据影响别的多个数据)==当数据发生变化时,执行异步操作或较大开销操作的情况。
computed适合处理的场景是,一个数据属性在它所依赖的属性发生变化时,也要发生变化,这种情况下,我们最好使用计算属性。
vuex, mobx, redux各自的特点和区别 你在项目中怎么实现路由的嵌套
需要在 VueRouter 的参数中使用 children 配置,这样就可以很好的实现路由嵌套。
Vue 3.0
对它的了解
关于Vue 3.0有幸看过尤大的关于3.0版本的RFC Vue Function-based API RFC。 大致说了三个点,第一个是关于提出的新API setup()函数,第二个说了对于Typescript的支持,最后说了关于替换Object.defineProperty为Proxy的支持。
详细说了下关于Proxy代替带来的性能上的提升,因为传统的原型链拦截的方法,无法检测对象及数组的一些更新操作,但使用Proxy又带来了浏览器兼容问题。
1、速度方面:
通过更新 runtime-core 与 runtime-dom ,支持了包括 Fragments、Portals与Suspense w/ async setup() 等(似乎有点越来越像 react),支持 Composition API 、Options API 和 typings,配合 Proxy 的引入,极大程度上提高了响应式的能力。
Composition API 与 Proxy 的运用使得组件化更加灵活,逻辑业务组件的编写与UI组件的多样化能够更好的实现。
2、体积方面:
runtime-core 体积压缩成了 约10kb
3、维护性:
代码迁移成 TypeScript (还没学的抓紧啦)
编译器(Compiler)优化,以下借用尤大大的特性更新图翻译一下:
使用模块化架构
优化 "Block tree"
更激进的 static tree hoisting 功能
支持 Source map
内置标识符前缀(又名 "stripWith")
内置整齐打印功能
移除 source map 和标识符前缀功能后,使用 Brotli 压缩的浏览器版本精简了大约 10KB
可见,编译器更多从数据结构入手,优化架构层级,降低使用成本。
4、更接近原生开发
5、让你更轻松开发
其次是 GitHub 上的源码目录:
reactivity 目录:数据响应式系统,主要使用 Proxy。
runtime-core 目录:支持 v-dom 与 Vue 原生的各种 API 在浏览器上的调用,调用 Vue 特性的相关代码。
runtime-dom 目录: 调用各类浏览器原生 DOM 事件的相关代码。
runtime-test 目录: 测试用的runtime的相关代码。
server-renderer 目录: SSR 相关代码。
compiler-core 目录: 支持 Vue 原生编写的 编译器特性,以及开发者编写的编译器特性的相关代码。
compiler-dom 目录: 调用浏览器的编译器的相关代码。
shared 目录: 无内置API。
vue 目录: 实现 vue 构建与编译的相关代码。
Vue3 proxy解决了哪些问题?Vue3 proxy的优劣Vue响应式原理
在官方文档中,有简单介绍一点,是基于 Object.defineProperty 去实现的;但是有一个要求,就是在 实例化 Vue 构造函数前,所有熬进行双向绑定的数据,都是要在 data 里面去做初始化的,哪怕是一个空值;因为在每次实例化的时候,Vue 会去检测 data ,查看并把存在属性用 Object.defineProperty 进行监听;在每一个需要判断或者展示当前响应式监听的数据时。
初始化的时候,我绑定了一个 name 属性,它在一个 div 里面做了展示;当我在 div 里面添加 name 展示的时候,其实在模板编译的时候,获取了一下 name 属性;因为前面有提到,我给当前的属性绑定了 Object.defineProperty ,所以在获取的时候,我会调用到 get 方法;
在这之前,我有实例化一个 dep 队列,把每次获取 name 属性的地方,做一个 push ;
当我接下来要做数据修改的时候,比如把 zhangsan 变成了 lisi ,那么在 set 方法里,把我当前属性的队列有监听当前属性的位置,全部更新一遍;最后把 data 对象里面的属性值做修改;
Vue 组件 data 为什么必须是函数
因为js本身的特性带来的,如果 data 是一个对象,那么由于对象本身属于引用类型,当我们修改其中的一个属性时,会影响到所有Vue实例的数据。如果将 data 作为一个函数返回一个对象,那么每一个实例的 data 属性都是独立的,不会相互影响了
Vue 中怎么自定义过滤器
可以用全局方法 Vue.filter() 注册一个自定义过滤器,它接收两个参数:过滤器 ID 和过滤器函数。过滤器函数以值为参数,返回转换后的值
Vue.filter('reverse', function (value) {
return value.split('').reverse().join('')
})
<!-- 'abc' => 'cba' -->
<span v-text="message | reverse"></span>
过滤器也同样接受全局注册和局部注册
对 keep-alive 的了解
keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染
<keep-alive>
<component>
<!-- 该组件将被缓存! -->
</component>
</keep-alive>
可以使用API提供的props,实现组件的动态缓存
Vue 中 key 的作用
key 的特殊属性主要用在 Vue 的虚拟 DOM 算法,在新旧 nodes 对比时辨识 VNodes。如果不使用 key,Vue 会使用一种最大限度减少动态元素并且尽可能的尝试修复/再利用相同类型元素的算法。使用 key,它会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。
有相同父元素的子元素必须有独特的 key。重复的 key 会造成渲染错误。
当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用“就地复用”策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。key的作用主要是为了高效的更新虚拟DOM。
简述Vue的响应式原理
当一个Vue实例创建时,vue会遍历data选项的属性,用 Object.defineProperty 将它们转为 getter/setter并且在内部追踪相关依赖,在属性被访问和修改时通知变化。
每个组件实例都有相应的 watcher 程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。
Vue中如何监控某个属性值的变化?
比如现在需要监控data中,obj.a 的变化。Vue中监控对象属性的变化你可以这样:
watch: {
obj: {
handler (newValue, oldValue) {
console.log('obj changed')
},
deep: true
}
}
deep属性表示深层遍历,但是这么写会监控obj的所有属性变化,并不是我们想要的效果,所以做点修改:
watch: {
'obj.a': {
handler (newName, oldName) {
console.log('obj.a changed')
}
}
}
还有一种方法,可以通过computed 来实现,只需要:
computed: {
a1 () {
return this.obj.a
}
}
利用计算属性的特性来实现,当依赖改变时,便会重新计算一个新值。
Vue中给data中的对象属性添加一个新的属性时会发生什么,如何解决?
示例:
<template>
<div>
<ul>
<li v-for="value in obj" :key="value">
{{value}}
</li>
</ul>
<button @click="addObjB">添加obj.b</button>
</div>
</template>
<script>
export default {
data () {
return {
obj: {
a: 'obj.a'
}
}
},
methods: {
addObjB () {
this.obj.b = 'obj.b'
console.log(this.obj)
}
}
}
</script>
<style></style>
点击button会发现,obj.b 已经成功添加,但是视图并未刷新:
原因在于在Vue实例创建时,obj.b并未声明,因此就没有被Vue转换为响应式的属性,自然就不会触发视图的更新,这时就需要使用Vue的全局api $set():
addObjB () {
// this.obj.b = 'obj.b'
this.$set(this.obj, 'b', 'obj.b')
console.log(this.obj)
}
$set()方法相当于手动的去把obj.b处理成一个响应式的属性,此时视图也会跟着改变了:
delete和Vue.delete删除数组的区别
delete只是被删除的元素变成了 empty/undefined 其他的元素的键值还是不变。
Vue.delete直接删除了数组 改变了数组的键值。
var a=[1,2,3,4]
var b=[1,2,3,4]
delete a[1]
console.log(a)
this.$delete(b,1)
console.log(b)
Vue组件间的参数传递
1.父组件与子组件传值
父组件传给子组件:子组件通过props方法接受数据;
子组件传给父组件:$emit方法传递参数
2.非父子组件间的数据传递,兄弟组件传值
eventBus,就是创建一个事件中心,相当于中转站,可以用它来传递事件和接收事件。项目比较小时,用这个比较合适。(虽然也有不少人推荐直接用VUEX,具体来说看需求咯。技术只是手段,目的达到才是王道。)
场景有:单页应用中,组件之间的状态、音乐播放、登录状态、加入购物车
state
Vuex 使用单一状态树,即每个应用将仅仅包含一个store 实例,但单一状态树和模块化并不冲突。存放的数据状态,不可以直接修改里面的数据。
mutations
mutations定义的方法动态修改Vuex 的 store 中的状态或数据。
getters
类似vue的计算属性,主要用来过滤一些数据。
action
actions可以理解为通过将mutations里面处里数据的方法变成可异步的处理数据的方法,简单的说就是异步操作数据。view 层通过 store.dispath 来分发 action。
const store = new Vuex.Store({ //store实例
state: {
count: 0
},
mutations: {
increment (state) {
state.count
}
},
actions: {
increment (context) {
context.commit('increment')
}
}
})
modules
项目特别复杂的时候,可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理。
const moduleA = {
state: { ... },
mutations: { ... },
actions: { ... },
getters: { ... }
}
const moduleB = {
state: { ... },
mutations: { ... },
actions: { ... }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
})
对keep-alive 的了解?
keep-alive是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。
在vue 2.1.0 版本之后,keep-alive新加入了两个属性: include(包含的组件缓存) 与 exclude(排除的组件不缓存,优先级大于include) 。
使用方法
<keep-alive include='include_components' exclude='exclude_components'>
<component>
<!-- 该组件是否缓存取决于include和exclude属性 -->
</component>
</keep-alive>
参数解释
include - 字符串或正则表达式,只有名称匹配的组件会被缓存
exclude - 字符串或正则表达式,任何名称匹配的组件都不会被缓存
include 和 exclude 的属性允许组件有条件地缓存。二者都可以用“,”分隔字符串、正则表达式、数组。当使用正则或者是数组时,要记得使用v-bind 。
使用示例
<!-- 逗号分隔字符串,只有组件a与b被缓存。 -->
<keep-alive include="a,b">
<component></component>
</keep-alive>
<!-- 正则表达式 (需要使用 v-bind,符合匹配规则的都会被缓存) -->
<keep-alive :include="/a|b/">
<component></component>
</keep-alive>
<!-- Array (需要使用 v-bind,被包含的都会被缓存) -->
<keep-alive :include="['a', 'b']">
<component></component>
</keep-alive>
css只在当前组件起作用
答:在style标签中写入scoped即可 例如:<style scoped></style>
vue.js的两个核心是什么?
答:数据驱动、组件系统
vue常用的修饰符?
答:.prevent: 提交事件不再重载页面;.stop: 阻止单击事件冒泡;.self: 当事件发生在该元素本身而不是子元素的时候会触发;.capture: 事件侦听,事件发生的时候会调用
vue等单页面应用及其优缺点
答:优点:Vue 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件,核心是一个响应的数据绑定系统。MVVM、数据驱动、组件化、轻量、简洁、高效、快速、模块友好。
缺点:不支持低版本的浏览器,最低只支持到IE9;不利于SEO的优化(如果要支持SEO,建议通过服务端来进行渲染组件);第一次加载首页耗时相对长一些;不可以使用浏览器的导航按钮需要自行实现前进、后退。
优点:
良好的交互体验
良好的前后端工作分离模式
减轻服务器压力
缺点:
SEO难度较高
前进、后退管理
初次加载耗时多
MVC
1. MVC 是 Model-View-Controller 的缩写,即 模型—视图—控制器。
Model:后端传递的数据。
View:所看到的页面。
Controller:页面业务逻辑。
2. MVC是单向通信。即View和Model,必须通过Controller来承上启下。
3. 使用MVC的目的就是将M和V的代码分离。
4. MVC 和 MVVM 的区别 并不是VM完全取代了C,ViewModel 存在目的 在于抽离 Controller 中展示的业务逻辑,而不是替代Controller,其它视图操作业务等还是应该放在 Controller 中实现。也就是说MVVM实现的是业务逻辑组件的重用。
beforeCreate(创建前) 在数据观测和初始化事件还未开始
created(创建后) 完成数据观测,属性和方法的运算,初始化事件,$el属性还没有显示出来
beforeMount(载入前) 在挂载开始之前被调用,相关的render函数首次被调用。实例已完成以下的配置:编译模板,把data里面的数据和模板生成html。注意此时还没有挂载html到页面上。
mounted(载入后) 在el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用。实例已完成以下的配置:用上面编译好的html内容替换el属性指向的DOM对象。完成模板中的html渲染到html页面中。此过程中进行ajax交互。
beforeUpdate(更新前) 在数据更新之前调用,发生在虚拟DOM重新渲染和打补丁之前。可以在该钩子中进一步地更改状态,不会触发附加的重渲染过程。
updated(更新后) 在由于数据更改导致的虚拟DOM重新渲染和打补丁之后调用。调用时,组件DOM已经更新,所以可以执行依赖于DOM的操作。然而在大多数情况下,应该避免在此期间更改状态,因为这可能会导致更新无限循环。该钩子在服务器端渲染期间不被调用。
beforeDestroy(销毁前) 在实例销毁之前调用。实例仍然完全可用。
destroyed(销毁后) 在实例销毁之后调用。调用后,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩子在服务器端渲染期间不被调用。
vue父子组件生命周期执行顺序
加载渲染过程
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
子组件更新过程
父beforeUpdate->子beforeUpdate->子updated->父updated
父组件更新过程
父beforeUpdate->父updated
销毁过程
父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
介绍JSX
jsx可以像我们写HTML文件一样写业务代码,借助于babel,会将jsx语法转换成render语法,没有什么副作用。
vue template语法简单明了,数据操作与视图分离,开发体验友好。但是在某些特定场合中,会限制一些功能的扩展,如动态使用过滤器、解析字符串类型的模板文件等。以上功能的实现可以借助vue的render语法,render语法比template更偏底层,允许在HTML中使用js语法,可以极大的扩展HTML的能力。render函数注入了一个参数createElement,用来创建我们所需要的标签内容,有三个参数:HTML标签(elementTag),标签属性(option),子元素(children);从createElement的参数列表里面可以看出,如果组件内部结构嵌套比较深,render的语法写起来会比较繁琐,需要不断的调用createElement,对于想偷懒的我,还是想想有没有什么比较简易的写法,jsx无疑是一种很好的选择,区别在于jsx可以像我们写HTML文件一样写业务代码,借助于babel,会将jsx语法转换成render语法,没有什么副作用。
vue.nextTick实现原理
Vue 实现响应式并不是数据发生变化之后 DOM 立即变化,而是按一定的策略进行 DOM 的更新。
1.在Vue生命周期的created()钩子函数进行DOM操作一定要放到Vue.nextTick()的回调函数中。
在created()钩子函数执行的时候DOM 其实并未进行任何渲染,而此时进行DOM操作无异于徒劳,所以此处一定要将DOM操作的js代码放进Vue.nextTick()的回调函数中。与之对应的就是mounted()钩子函数,因为该钩子函数执行时所有的DOM挂载和渲染都已完成,此时在该钩子函数中进行任何DOM操作都不会有问题。
2.在数据变化后要执行的某个操作,而这个操作需要使用随数据改变而改变的DOM结构的时候,这个操作都应该放进Vue.nextTick()的回调函数中。
Vue 异步执行 DOM 更新。只要观察到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作上非常重要。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作。Vue 在内部尝试对异步队列使用原生的Promise.then和MessageChannel,如果执行环境不支持,会采用setTimeout(fn, 0)代替。
例如,当你设置vm.someData = 'new value',该组件不会立即重新渲染。当刷新队列时,组件会在事件循环队列清空时的下一个“tick”更新。多数情况我们不需要关心这个过程,但是如果你想在 DOM 状态更新后做点什么,这就可能会有些棘手。虽然 Vue.js 通常鼓励开发人员沿着“数据驱动”的方式思考,避免直接接触 DOM,但是有时我们确实要这么做。为了在数据变化之后等待 Vue 完成更新 DOM ,可以在数据变化之后立即使用Vue.nextTick(callback)。这样回调函数在 DOM 更新完成后就会调用。
Emit事件怎么发,需要引入什么
子组件: 通过 emit("listenToChildEvent", deliver)
父组件:进行绑定事件的,调用方法
v-on:listenToChildEvent="showMsgFromChild"
使用import时,webpack对node_modules里的依赖会做什么
配置相关路径
vue怎么监听数组
在将数组处理成响应式数据后,如果使用数组原始方法改变数组时,数组值会发生变化,但是并不会触发数组的setter来通知所有依赖该数组的地方进行更新,为此,vue通过重写数组的某些方法来监听数组变化,重写后的方法中会手动触发通知该数组的所有依赖进行更新。
我们知道通过Object.defineProperty()劫持数组为其设置getter和setter后,调用的数组的push、splice、pop等方法改变数组元素时并不会触发数组的setter,这就会造成使用上述方法改变数组后,页面上并不能及时体现这些变化,也就是数组数据变化不是响应式的(对上述不了解的可以参考这篇文章)。但实际用vue开发时,对于响应式数组,使用push、splice、pop等方法改变数组时,页面会及时体现这种变化,那么vue中是如何实现的呢?通过vue源码可以看出,vue重写了数组的push、splice、pop等方法
因为监听的数组带来的代价和一些问题,Vue使用了重写原型的方案代替。拦截了数组的一些方法,在这个过程中再去做通知变化等操作。
Proxy 相比于 defineProperty 的优势
Proxy的优势:
可以直接监听对象而非属性
• 可以直接监听数组的变化
• 拦截方式较多
• Proxy返回一个新对象,可以只操作新对象达到目的,而Object.defineProperty只能遍历对象属性直接修改
• Proxy作为新标准将受到浏览器厂商重点持续的性能优化
Object.defineProperty的优势如下:
• 兼容性好,支持IE9
restful接口架构的优缺点
RESTful
架构优点:
1. 前后端分离,减少流量
2. 安全问题集中在接口上,由于接受json格式,防止了注入型等安全问题
3. 前端无关化,后端只负责数据处理,前端表现方式可以是任何前端语言(android,ios,html5)
4. 前端和后端人员更加专注于各自开发,只需接口文档便可完成前后端交互,无需过多相互了解
5. 服务器性能优化:由于前端是静态页面,通过nginx便可获取,服务器主要压力放在了接口上
什么是RESTful API?怎么使用?
是一个api的标准,无状态请求。请求的路由地址是固定的,如果是tp5则先路由配置中把资源路由配置好。标准有:.get .post .put .delete
RESTful架构设计原则(不同公司具体细节可能不同):
1. 在接口命名时应该用名词,不应该用动词,因为通过接口操作到是资源。
2. 在url中加入版本号,利于版本迭代管理更加直观
<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">https://www.rgc.com/v1/</pre>
3. 对于资源的操作类型应该是通过http动词表示。
• GET /zoos:列出所有动物园
• POST /zoos:新建一个动物园
• GET /zoos/ID:获取某个指定动物园的信息
• PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息)
• DELETE /zoos/ID:删除某个动物园
• GET /zoos/ID/animals:列出某个指定动物园的所有动物
• DELETE /zoos/ID/animals/ID:删除某个指定动物园的指定动物
4. 排序规则:默认时升序,‘-’为降序;多个排序规则时以逗号间隔组合。使用sort查询参数限制
<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">GET /tickets?sort=-time,created_at
优先以time倒序显示,其次以created_at正序显示</pre>
5. 限制返回值的字段域:明确指定输出字段列表,用于控制网络带宽和速度。使用fields查询参数来限制。
<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">GET /tickets?fileds=id,subject,customer_name,time&sort=-time
返回参数列表为id,subject,customer_name,time,并且以time字段倒序显</pre>
6. HTTP Method分别对于资源的CURD操作
POST(CREATE):在服务器新建一个资源。
PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
DELETE(DELETE):从服务器删除资源。</pre>
保证 POST,PUT,DELETE,PATCH,GET 操作幂等性。
7. 使用SSL(Secure Sockets Layer 安全套接层)
8. 参数和url采用蛇行命名方式。如:updated_time
9. 服务器请求和返回的数据格式,应该尽量使用JSON,避免使用XML。在 request中的Accept和Response中的Content-Type:application/json
总结:优秀的RESTful接口设计,能够根据请求的路径及请求方法就能看出这个接口主要是对具体某个资源进行什么方法的操作以及返回数据的规则等等。
vue 组件的优点,以及注册使用的过程
首先,组件可以提升整个项目的开发效率。能够把页面抽象成多个相对独立的模块,解决了我们传统项目开发:效率低、难维护、复用性等问题。
使用Vue.component方法注册组件。子组件需要数据,可以在props中接受定义。而子组件修改好数据后,想把数据传递给父组件。可以采用emit方法。
例举3种强制类型转换 强制parseInt,parseFloat,number。
Vue.js中ajax请求代码应该写在组件的methods中还是vuex的actions中?
如果请求来的数据是不是要被其他组件公用,仅仅在请求的组件内使用,就不需要放入vuex 的state里。
如果被其他地方复用,这个很大几率上是需要的,如果需要,请将请求放入action里,方便复用
axios是什么 怎么使用?
请求后台资源的模块。npm install axios --save装好,
js中使用import进来,然后.get或.post。返回在.then函数中如果成功,失败则是在.catch函数中
axios tp5进阶中,调用axios.post(‘api/user’)是进行的什么操作?axios.put(‘api/user/8′)呢?
添加用户操作,更新操作。
要是有错别字和错误的地方,请各位大佬直接指出,谢谢啦!!