(1)轻量级框架,简单易学;
(2)可以进行组件化开发,数据与结构相分离,使代码量减少,从而提升开发效率,易于理解;
(3)最突出的优势是可以对数据进行双向绑定;
(4)相比传统的页面通过超链接实现页面的切换和跳转,Vue 使用路由不会刷新页面;
(5)vue 是单页面应用,使页面局部刷新,不用每次跳转页面都要请求所有数据和 dom,这样大大加快了访问速度和提升用户体验;
(6)它的第三方UI组件库用起来节省很多开发时间,从而提升开发效率。
(1)MVVM(model-view-viewmodel),即模型-视图-视图模型。模型指的是后端传递的数据,视图指的是看到的页面,视图模型是MVVM模式的核心,是连接view和model的桥梁,并且它有两个方向:一个是将模型转换为视图,即将后端的数据转换为页面,实现的方式是数据绑定;二是将视图转换为模型,即将看到的页面转换为后端的数据,实现的方式为DOM事件监听。这两个方向都实现的,称之为数据的双向绑定。是基于MVC的一种架构模式,将视图和模型之间绑定自动化,减少代码量,但是会增加额外的学习成本。
(2)MVC(model-view-controller),即模型-视图-控制器。其中m和v同上,c/controller指的是页面业务逻辑。使用MVC的目的就是将M和V的代码分离。MVC是单向通信,也就是view和model,必须通过controller来承上启下,MVC和MVVM的区别并不是vm完全取代了c,只是在MVC 的基础上增加了一层VM,只不过是弱化了c的概念,其中,模型代表数据和业务逻辑,视图代表用户界面,控制器作为中介负责调度和控制模型和视图之间的交互。MVC模式的优点是可以将应用程序的功能进行清晰的分离,提高代码的可维护性和重用性。MVC模式的缺点是需要手动编写代码实现视图和模型之间的数据交互,代码量较大,测试相对困难。
(3)区别:(区别不大,都是一种设计思想)
(4)适合场景:
MVC模式适用于简单的应用程序,比如一些新闻网站等,它能够将应用程序的功能进行清晰的分离,并提高代码的复用性和可维护性。
MVVM模式适用于需要大量操作DOM元素,比如电商网站、社交网络等,它能够减少手动编写的代码量,并提高开发效率。
vue使用数据劫持以及发布订阅的模式,通过Object.defineProperty()来劫持各个属性的setter、getter,在数据变动时发布消息给订阅者,触发响应的监听回调。
具体步骤:
(1)需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上setter和getter,这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据的变化。
(2)compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听函数的订阅者,一旦数据有变动,收到通知,更新视图。
(3)watcher订阅者是observer和compile之间通信的桥梁,相当于VM。
(4)MVVM作为数据绑定的入口,整合observer、compile和watcher三者,通过observer来监听自己的model数据变化,通过compile来解析模板指令,最终利用watcher搭起observer和compile之间的通信桥梁,达到数据变化->视图更新;视图交互变化->数据model变更的双向绑定效果。
(1)proxy可以直接监听对象而不是属性;
(2)proxy可以直接监听数组的变化【.数组的某些方法(push、unshift和splice)Object.defineProperty监听不到,Proxy可以监听到】
(3)proxy有多达13种拦截方法;
(4)proxy返回的是一个新对象,我们可以只操作新的对象达到目的,而Object.defineProperty只能遍历对象属性直接修改;【对象上定义新属性时,Proxy可以监听到,Object.defineProperty监听不到,需要借助$set方法】
(5)proxy在ie浏览器存在兼容性问题。
vue实例从创建到销毁的过程,也就是vue生命周期。也就是从开始创建、初始化数据、编译模板、挂载DOM->渲染、更新->渲染、卸载等一系列过程,我们称之为Vue的生命周期。
【beforeCreate(创建前)、created(创建后)、beforeMount(载入前)、mounted(载入后)、beforeUpdate(更新前)、updated(更新后)、beforeDestroy(销毁前)、destroyed(销毁后)】
(1)beforeCreate--在实例初始化之后,数据观测(data observer)和event watcher事件配置之前被调用。
(2)created--在实例创建完成后被立即调用,同时,已经完成以下配置:数据观测(data observer)、属性和方法的运算,watch/event事件回调。但是,挂载阶段还没有开始,$el属性目前不可见。
(3)beforeMount--在挂载开始之前被调用:相关的render函数首次被调用。
(4)mounted--mounted是平时我们使用最多的函数了,一般我们的异步请求都写在这里。在这个阶段,数据和DOM都已被渲染出来。
(5)beforeUpdate--在这一阶段,vue遵循数据驱动DOM的原则;beforeUpdate函数在数据更新后虽然没立即更新数据,但是DOM中的数据会改变,这是Vue双向数据绑定的作用。
(6)updated--由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子。
(7)activated--keep-alive组件激活时调用,该钩子在服务器端渲染期间不被调用。
(8)deactived--keep-alive组件停用时调用,该钩子在服务器端渲染期间不被调用。
(9)beforeDestroy--实例销毁前调用,在这一步,实例仍然完全可以用,该钩子在服务器端渲染期间不被调用。
(10)destroyed--vue实例销毁后使用,调用后,vue实例指示的所有东西都会被解除绑定,所有的事件监听器都会被移除,所有的子实例也会被销毁,该钩子在服务器端渲染期间不被调用。
(11)errorCaptured--当捕获一个来自子孙组件的错误时被调用,此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回false以阻止该错误继续向上传播。
beforeCreate、created、beforeMount、mounted
(1)分析需求:确定业务需求,把页面中可以复用的结构,样式以及功能,单独抽离成一个文件,实现复用。(把页面抽象成多个相对独立的模块,可以提升整个项目的开发效率)
(2)具体步骤:
(1)父组件向子组件传数据
父组件内设置要传的数据,在父组件中引用的子组件上绑定一个自定义属性并把数据绑定在自定义属性上,在子组件添加参数props接收即可。
(2)子组件向父组件传数据
子组件通过vue实例方法$emit进行处罚并且可以携带参数,父组件监听使用@(v-on)进行监听,然后进行方法处理。
(3)非父子组件之间传数据
(1)项目中使用keep-alive时,可以搭配组件name进行缓存过滤;
(2)DOM做递归组件时需要调用自身name;
(3)vue-devtools调试工具里显示的组件名称是由vue组件name决定的。
(1)因为Vue组件可以同时存在多个实例,如果直接使用对象形式的data选项,那么所有的实例将会共享同一个data对象,这样就会造成数据互相干扰的问题,即防止多个组件实例对象之间共用一个data,产生数据污染;
(2)采用函数的形式,initData时会将其作为工厂函数都会返回全新data对象。当将组件中的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data,拥有自己的作用域,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。
(1)使用链式命名,即my-component,例如
(2)使用大驼峰命名MyComponent,例如
有两种方法可以监听路由参数的变化,但是只能用在包含
(1)watch:{
'$route'(to,from){
//在此处监听
}
}
(2)beforeRouteUpdate(to,from,next){
//在此处监听
}
(1)使用errorCaptured这个组件内部钩子,当捕获一个来自子孙组件的错误时被调用,接收error、vm、info三个参数,return false后可以阻止错误继续向上抛出。
(2)使用errorHandler这个全局钩子,使用Vue.config.errorHandler配置,接收参数与errorCaptured一致,2.6后可以捕捉v-on与promise链的错误,可用于统一错误处理与错误兜底。
(1)如果有很多个定时器,可以在data选项中创建一个对象timer,给每个定时器去个名字一一映射在对象timer中,在beforeDestroy构造函数中for(let k in this.timer){clearInterval(k)}。
(2)如果只有单个定时器,可以这样做。const timer=setInterval(()=>{},5000);this.$once(‘hook:beforeDestroy’,()=>{clearInterval(timer);})
(1)在components目录新建你的组件文件(indexPage.Vue),script一定要export default{};
(2)在需要用的页面(组件)中导入:import indexPage from '@/components/indexPage.Vue';
(3)注入到Vue的子组件的components属性上面,components:{indexPage}
(4)在template视图view中使用。【注意:用indexPage命名,使用的时候则是index-page】
使用方式:当组件当做标签进行使用的时候,用slot可以用来接收组件标签包裹的内容,当给slot标签添加name属性的时候,可以调换相应的位置
插槽作用域:作用域插槽其实就是带数据的插槽,父组件接收来自子组件的slot标签上通过v-bind绑定进而传递过来的数据,父组件通过scope来进行接受子组件传递过来的数据。
在面向组件化开发过程中,我们会把整个项目拆分成很多业务组件,然后按照合理的方式组织起来,那么自然会存在组件之间切换的问题,Vue有个动态组件的概念,它能够帮助开发者更好的实现组件之间的切换,但是在面对需求比较频繁的变化,去要切换组件时,动态组件在切换的过程中,组件的实例都是重新创建的,而我们需要保留组件的状态,为了解决这个问题,需要使用到Vue中内置组件
【比如:有一个列表和详情,那么用户就会经常执行打开详情-->返回列表-->打开详情......这样的列表和详情都是使用频率很高的页面,那么就可以对列表组件使用
在开发Vue项目的时候,大部分组件没必要多次渲染的,所以Vue提供了一个内置组件keep-alive来缓存组件内部状态,避免重新渲染。
在被keep-alive包含的组件中,会多出两个生命周期钩子函数--activated和deactivated;
activted:在组件第一次渲染时会被调用,之后在每次缓存组件时被激活时调用。
activated钩子调用时机:第一次进入缓存路由/组件,在mounted后面,beforeRouteEnter守卫传给next的回调函数之前调用,并且给因为组件被缓存了,再次进入缓存路由、组件时,不会触发这些钩子函数,beforeCreate created ,beforeMount mounted都不会触发;
deactivated:组件被停用时(离开路由时)调用。
deactivated调用时机:使用keep-alive就不会调用beforeDestroy(组件销毁前钩子)和destroyed(组件销毁),因为组件没有被销毁,而是被缓存起来了,这个钩子可以被看作是beforeDestroy的替代,如果你缓存了组件,要在组件销毁的时候做一些事情,可以防在这个钩子里,组件内的离开当前路由钩子beforeRouterLeave=>路由前置守卫beforeEach=>全局后置钩子afterEach=>deactivated离开缓存组件=>activated进入缓存组件(如果你进入的也是缓存路由)
.prevent:提交事件不再重载页面;
.stop:阻止单击事件冒泡;
.self:当事件发生在该元素本身而不是子元素的时候会触发;
.capture:事件侦听,事件发生时会调用。
(1)v-model:多用于表单元素实现双向数据绑定(同angular中的ng-model);
(2)v-for:格式--相当于【字段名 in/of 数组 json】循环数组或json(同angular中的ng-repeat),需要注意从vue2开始取消了$index;
(3)v-show:显示内容(同angular中的ng-show);
(4)v-hide:隐藏内容(同angular中的ng-hide);
(5)v-if:显示与隐藏(dom元素的删除添加,同angular中的ng-if默认值为false);
(6)v-else-if:必须与v-if连用;
(7)v-else:同上;
(8)v-bind:动态绑定 作用:及时对页面的数据进行更改;
(9)v-on:click 给标签绑定函数,可以缩写为@;
(10)v-text:解析文本;
(11)v-html:解析html标签;
(12)v-bind:class 三种绑定方法 --对象型‘{red:isred}’
--三元型‘isred?red:blue’
--数组型‘[{red:isred},{blue:isblue}]’
(13)v-once:进入页面时,只渲染一次,不在进行渲染;
(14)v-cloak:防止闪烁;
(15)v-pre:把标签内部的元素原位输出。
全局定义指令:在Vue对象的directive方法里面有两个参数,一个是指令名称,另一个是函数,组件内定义指令:directives;
钩子函数:bind(绑定事件触发)、inserted(节点插入的时候触发)、update(组件内相关更新);
钩子函数参数:el、binding。
共同点:v-show和v-if都能控制元素的显示隐藏;
不同点:
(1)实现的本质不同:v-show的本质是通过设置css中的display为none,从而控制隐藏;而v-if则是动态的向DOM树中添加或者删除DOM元素;
(2)编译的不同:v-show就是在控制css;而v-if切换有一个局部编译、卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;
(3)编译的条件不同:v-show都会编译,初始值为false,只是将display设置为none,但它也编译了;而v-if如果初始值为false,就不会编译了;
(4)性能的比较:v-show只编译一次,后面都是控制css,而v-if不停的销毁和创建,所以v-show性能更好一点。
【总结:如果要频繁切换某个节点时,使用v-show(无论false还是true初始都会渲染,此后通过css来控制显示隐藏,因此切换开销比较小,初始开销比较大),如果不需要频繁切换某节点时,使用v-if(因为懒加载,初始为false时,不会渲染,但是它是通过添加和删除dom元素来控制显示和隐藏的,因此初始渲染开销较小,切换开销较大)】
当vue处理指令的时候,v-for比v-if具有更高的优先级,通过v-if移动到容器元素,不会再重复遍历列表中的每个值。取而代之的是,我们只检查它一次,且不会在v-if为否的时候运算v-for。
基本说明:
(1)computed:计算属性将被混入到Vue实例中,所有getter和setter的this上下文自动地绑定为Vue实例。
(2)methods:将被混入到vue实例中,可以直接通过VM实例访问到这些方法,或者在指令表达式中使用。方法中的this自动绑定为Vue实例。
(3)watch:观察和响应vue实例上的数据变动,一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象,vue实例将会在实例化时调用$watch(),遍历watch对象的每一个属性。
三者的加载顺序:
(1)computed是在HTML DOM加载后马上执行,比如赋值;
(2)methods则必须有一定的触发条件才能执行,比如点击事件;
(3)watch用于观察Vue实例上的数据变动。
默认加载的时候:先是computed,再是watch,不执行methods。
触发某个事件后:先是computed再是methods接着是watch;其中computed计算属性是基于它们的依赖进行缓存的。
【总结:computed只会在它的相关依赖发送改变时才会重新求值,当有一个性能开销比较大的计算属性A,它需要遍历一个极大的数组和做大量的计算,然后我们可能有其他的计算属性依赖于A,这时候,我们就需要缓存,每次确实需要重新加载,不需要缓存时用methods。】
在选项参数中指定immediate:true将立即以表达式的当前值触发回调。
直接写一个监听函数,当每次监听到cityName值发生变化时,执行函数,也可以在所监听的数据后面直接加字符串形式的方法名:watch:{ cityName:‘nameChange’}
不能,因为不管是computed属性名还是data数据名还是props数据名都会被挂载在vm实例上,因此这三个都不能同名。
因为在模板中放入太多逻辑会使得模板过重并且难以维护,所以在需要对数据进行复杂处理,且可能多次使用的情况下,尽量采取计算属性的方式。
好处:使得数据处理结构清晰;
特点:
(1)依赖于数据,数据更新,处理结构自动更新;
(2)计算属性内部this指向vm实例;
(3)在template调用时,直接写计算属性名就行;
(4)常用的是getter方法,获取数据,也可以使用set方法改变数据;
(5)相较于methods,不管数据会不会变化,methods都会重新计算,但是依赖数据不变的时候,computed从缓存中获取,不会重新计算。
为了高效的更新虚拟DOM。
当vue用v-for正在更新已渲染过的元素列表时,它默认使用“就地复用”策略,如果数据项的顺序被改变,vue将不会移动DOM元素来匹配数据项的顺序,而是简单复用此处每个元素,并且确保它在特定索引下显示已经被渲染过的每个元素。
vue-loader
本质上是一个 webpack 的 loader,它可以解析和转换.vue文件。提取出其中的逻辑代码 script,样式代码style,以及HTML 模板template,再分别把他们交给对应的loader去处理。
其中loader 用于对模块的源代码进行转换。它可以使你在 import 或"加载"模块时预处理文件。简单点说就是它可以将文件从不同的语言(如 TypeScript)转换为 JavaScript,或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import CSS文件。
用途:降级----js可以写es6,style样式可以写scss或less、template可以加jade等
在vue中,过滤器可以被用在两个地方:双花括号插值和v-bind表达式。而且过滤器应该被添加在JavaScript表达式的尾部,由“管道”符号指示。
可以用全局方法vue.filter()注册一个自定义过滤器,它接收两个参数:过滤器ID和过滤器函数。过滤器函数以值为参数,返回转换后的值。过滤器同样接收全局和局部注册。
//全局注册
Vue.filter('capitalize', function(value) {
if (!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase() + value.slice(1)
})
var app = new Vue({
el: '#app',
data: {
message: 'hello world'
}
})
{{ message | capitalize }}
//局部注册
{{ message | uppercase }}
vuex可以理解为是一种开发模式或者框架。比如php有thinkphp,java有spring等,通过状态(数据源)集中管理驱动组件的变化(好比spring的ioc容器对bean进行集中管理)
(1)应用级的状态集中在store中;
(2)改变状态的方式是提交mutations,这里必须是同步的;
(3)异步逻辑应该封装在action中。
分别是state、getter、mutation、action、module
(1)state,即单一状态树,只有在state里面定义了我们所需要管理的数组、对象、字符串等等,在vue.js的组件中才能获取你定义的这个对象的状态。
(2)getter,即类似vue.js的计算属性,当我们需要从store的state中派生出一些状态,那么我们就需要使用getter,getter会接收state作为第一个参数,而且getter的返回值会根据它的依赖被缓存起来,只有getter中的依赖值(state中需要派生状态的值)发生改变的时候才会被重新计算。
(3)mutation,即更改store中state状态的唯一办法就是提交mutation,每个mutation都有一个字符串类型的事件类型和一个回调函数,我们需要改变state的值就要在回调函数中改变。我们要执行这个回调函数,那么我们需要执行一个相应的调用方法:store.commit。
(4)action,即可以提交mutation,在action中可以执行store.commit,而且action中可以有任何的异步操作。在页面中如果我们要调用这个action,则需要执行的是store.dispatch。
(5)module,即只是解决了当state中很复杂的时候,module可以将store分割成模块,每个模块中拥有自己的state、mutation、action和getter。
(1)多个组件依赖同一个状态时,对于多层嵌套的组件的传参将会非常繁琐,并且对于兄弟组件间的状态传递无能为力。
(2)来自不同组件的行为需要变更同一个状态。以往采用父子组件直接引用或者通过事件来变更和同步状态的多份拷贝。
当组件进行数据修改的时候我们需要调用dispatch来触发actions里面的方法。
actions里面的每个方法都会有一个commit方法,当方法执行的时候会通过commit来触发mutations里面的方法进行数据的修改。
mutations里面的每个函数都会有一个state参数,这样就可以在mutations里面进行state的数据修改。
当数据修改完毕后,会传导给页面。页面的数据从而发生改变。
(1)流程顺序
“相应视图”-->“修改state”拆分成两个部分:视图触发action,action再触发mutation。
(2)角色定位
基于流程顺序,这俩扮演了不同的角色:
mutation--专注修改state,理论上是修改state的唯一途径。
action--业务代码,异步请求。
(3)限制
角色不同,所以有不同的限制:
mutation:必须同步执行。
action:可以异步,但是不能直接操作state。
vue-router是vue.js官方的路由插件,和vue.js是深度集成的,适用于构建单页面应用。vue的单页面应用是基于路由和组件的,路由用于设定访问路径,并将路径和组件映射起来。传统的页面应用,是用一些超链接来实现页面切换和跳转的。在vue-router单页面应用中,则是路径之间的切换,也就是组件的切换。
路由模块的本质,就是建立起url和页面直接的映射关系。
“更新视图但不重新请求页面”是前端路由原理的核心之一,目前在浏览器环境中这一功能的实现主要有两种方式:
利用URL中的hash(‘#’);
利用history interface在h5中新增的方法。
(1)声明式导航:
(2)编程式导航:
路由跳转--this.$router.push()跳转到指定的url,并且在history中添加记录,点击回退返回到上一个页面。
路由替换--this.$router.replace()跳转到指定的url,并且在history中不会添加记录,点击回退返回到上上个页面。
·this.$router.go(n)向前或者后跳转n个页面,n可以是正数也可以是负数。
路由后退--this.$router.back()。
路由前进--this.$router.forward()。
在vue中配置路由分为5个步骤,分别是:
(1)安装
npm install --save Vue-Router
(2)引用
import VueRouter from 'Vue-Router'
(3)配置路由文件
const router=new VueRouter({
routes:[
{path:‘/hello’,component:HelloWorld}
]
})
(4)视图加载位置
默认App.vue文件中加
(5)跳转导航(渲染出来的是a标签)
(1)全局守卫:beforeEach;
(2)后置守卫:afterEach;
(3)全局解析守卫:beforeResolve;
(4)路由独享守卫:beforeEnter。
vue-router中的钩子函数主要分为3类:
(1)全局钩子函数要包含beforeEach
(2)单独路由独享组件:beforeEnter;
(3)组件内钩子:beforeRouterEnter、beforeRouterUpdate、beforeRouterLeave。
(1)router-link路由导航
父组件: 使用
例如:
子组件: this.$route.params.num接收父组件传递过来的参数
(2)调用$router.push实现路由传参
父组件: 绑定点击事件,编写跳转代码
methods: {
deliverParams (id) {
this.$router.push({
path: `/d/${id}`
})
}
}
子组件: this.$route.params.id接收父组件传递过来的参数
mounted () {
this.id = this.$route.params.id
}
(3)通过路由属性中的name匹配路由,再根据params传递参数
父组件: 匹配路由配置好的属性名
deliverByName () {
this.$router.push({
name: 'B',
params: {
sometext: '一只羊出没'
}
})
}
子组件:
This is page B!
传入参数:{{this.$route.params.sometext}}
(4)通过query来传递参数
父组件:
deliverQuery () {
this.$router.push({
path: '/c',
query: {
sometext: '这是小羊同学'
}
})
}
子组件:
This is page C!
这是父组件传入的数据: {{this.$route.query.sometext}}
动态路由就是把某种模式下匹配到的所有路由,全部映射到同个组件。其实本质就是通过url进行传参。
例如:有一个商品item的组件,我们需要让不同的商品id都映射到这个组件中,此时就需要用到动态路由了。
动态路径参数,使用“冒号”开头,一个路径参数,使用冒号标记,当匹配到一个路由时,参数会被设置到this.$router.params中,并且可以在每个组件中使用。
【通过动态路由传参,在路由中设置了多段路径参数后,对应的值分别都会设置到$router.query和$router.params中】
//query
this.$router.push({path;“地址”,query:{id:“123”JJ); //这是传递参数
this.$route.query.id; 这是接受参数
//params
this.$router.push({name:“地址”,params:{id:“123”]});//这是传递参数
this.$route.params.id; //这是接受参数
区别:
(1)首先就是写法的不同,query的写法是 用 path 来编写传参地址,而 params 的写法是用 name 来编写传参地址;
(2)接收方法不同, 一个用 query 来接收, 一个用 params 接收 ,总结就是谁发的 谁去接收;
(3)query 在刷新页面的时候参数不会消失,而 params 刷新页面的时候会参数消失,可以考虑本地存储解决;
(4)query 传的参数都是显示在url 地址栏当中,而 params 传参不会显示在地址栏。
路由跳转使用 “router”;获取参数使用“route”
$route是“路由信息对象”,包括path、params、hash、query、name等路由信息参数。每一个路由都会有一个$route对象,是一个局部的对象。
$router是VueRouter的实例,相当于一个全局的路由器对象,里面含有很多属性和子对象,例如history对象。
//$route
主要的属性有:
this.$route.path 字符串,等于当前路由对象的路径,会被解析为绝对路径,如/home/ews
this.$route.params 对象,包含路由中的动态片段和全匹配片段的键值对,不会拼接到路由的url后面
this.$route.query 对象,包含路由中查询参数的键值对。会拼接到路由url后面
this.$route.router 路由规则所属的路由器
this.$route.name 当前路由的名字,如果没有使用具体路径,则名字为空
//$router
//常规方法
this.$router.push("/login");
//使用对象的形式 不带参数
this.$router.push({ path:"/login" });
//使用对象的形式,参数为地址栏上的参数
this.$router.push({ path:"/login",query:{username:"jack"} });
使用对象的形式 ,参数为params 不会显示在地址栏
this.$router.push({ name:'user' , params: {id:123} });
(1)hash模式:
在浏览器中符号“#”,“#”以及“#”后面的字符称之为hash;
用window.location.hash读取。
特点:hash虽然在URL中,但不被包括在HTTP请求中,用来指导浏览器动作,对服务器安全无用,hash不会重新加载页面。
(2)history模式:
采用html5的新特性,且提供了两个新方法:pushState(),replaceState()可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更。
【区别:
1.hash模式地址栏中带#,history不带;
2.hash模式兼容性比history好;
3.由于hash值不会包含在http请求中(即hash值不会带给服务器),所以不会刷新404;但history部署上线后刷新会404(因为服务器把地址栏中的值当作服务器的接口了)】
路由配置参数:
path:跳转路径;
component:路径相对于的组件;
name:命名路由;
children:子路由的配置参数(路由嵌套);
props:路由解耦;
redirect:重定向路由。
首先,跨域是指浏览器不允许当前页面的所在的源去请求另一个源的数据。源指的是协议、端口、域名。只要这三个有一个不同的就是跨域。
怎么实现跨域?
(1)使用 vue-cli 脚手架搭建项目时 proxyTable 解决跨域问题
//打开 config/index.js,在 proxyTable 中添写如下代码:
proxyTable: {
'/api': { //使用"/api"来代替"http://f.apiplus.c"
target: 'http://f.apiplus.cn', //源地址
changeOrigin: true, //改变源
pathRewrite: {
'^/api': 'http://f.apiplus.cn' //路径重写
}
(2)使用 CORS(跨域资源共享)
//前端设置:vue 设置 axios 允许跨域携带 cookie(默认是不带 cookie)
axios.defaults.withCredentials = true;
//后端设置:跨域请求后的响应头中需要设置
Access-Control-Allow-Origin 为发起请求的主机地址
Access-Control-Allow-Credentials,当它被设置为 true 时,允许跨域 带 cookie,
但此时 Access-Control- Allow-Origin 不能为通配符*
Access-Control-Allow-Headers,设置跨域请求允许的请求头
Access-Control-Allow-Methods,设置跨域请求允许的请求方
哪个元素需要动画就给那个元素加transition标签,
(1)进入时class的类型可以分为以下几种:
(2)离开时class的类型可以分为以下几种:
如果需要一组元素发生动画需要用标签
简而言之,就是先转换为AST树,再得到的render函数返回VNode(vue的虚拟DOM节点)。
AST即abstract syntax tree也就是源代码的抽象语法结构的树状表现形式;
VNode是vue的虚拟DOM节点,里面有(标签名、子节点、文本等)。
在组件中将comments选项设置为true
...
vue-router默认使用是hash模式,所以在路由加载的时候,项目中的URL会自带“#”,如果不想使用“#”,可以使用vue-router的另一种模式--history:new Router({mode:‘history’,routes:[ ] })
【注意:因为我们启用history模式的时候,由于我们的项目是一个单页面应用,所以在路由跳转的时候,就会出现访问不到静态资源而出现“404”的情况,这时候就需要服务端增加一个覆盖所有情况的候选资源:如果URL匹配不到任何静态资源,则应该返回同一个“index.html”页面。】
采用ES6的import ... from ...语法或者CommonJS的require()方法引入插件。
使用全局方法 Vue.use(plugin)使用插件,可以传入一个选项对象Vue.use(MyPlugin,{someOption:true})。
(1)使用mini-css-extract-plugin插件抽离css;
(2)配置optimization把公共的js代码抽离出来;
(3)通过webpack处理文件压缩;
(4)不打包框架、库文件,通过cdn的方式引入;
(5)小图片使用base64;
(6)配置项目文件懒加载;
(7)UI库配置按需加载;
(8)开启Gzip压缩。
Vue-Router解决首次加载缓慢的问题,懒加载简单来说就是按需加载。
【像vue这单页面应用,如果没有应用懒加载,运用webpack打包后的文件将会异常的大,造成进入首页时,需要加载的内容过多,时间过长,会出现长时间的白屏,即使做了loading也是不利于用户体验,而运用懒加载,则可以将页面进行划分,需要的时候加载页面,可以有效的分担首页所承担的加载压力,减少首页加载用时】
【用法:在配置路由时使用:component:resolve=>require([“@components/路
由的路径”],resolve)。 就是用了懒加载后打完包直接运行那个 index.html 会报错,报文
件引用错误其实是打包时候路径配置有点问 题,找到 build 下面的
webpack.prod.conf.js 添加 publicPath:“./”,】
(1)assets文件夹是放静态资源;
(2)components是放组件;
(3)router是定义路由相关的配置;
(4)view视图
(5)app.vue是一个应用主组件;
(6)main.js是入口文件。
加上scoped是为了使样式私有化(模块化),不对全局造成污染,可以在style标签上添加scoped属性以表示它的只属于当下的模块,局部有效。(实现了样式的私有化)
实现原理:主要是通过PostCSS转译实现,给节点新增自定义属性,然后css根据属性选择器添加样式。
数据从父级组件传递给子组件,只能单向绑定;子组件内部不能直接修改从父级传递过来的数据。
【Vue的单向数据流指的是,数据在父组件中被定义和更新,然后通过props的形式传递给子组件,子组件可以读取这些props,但不能直接修改它们。如果子组件需要修改这些数据,需要通过$emit方法将事件发送给父组件,由父组件来更新数据。】
【这种单向数据流的好处是,可以更好地维护数据的可追溯性和可预测性,减少了代码的复杂度,方便开发和维护。】
{{ title }}
Count: {{ count }}
(1)VNode是什么?
VNode是javascript对象,VNode表示Virtual DOM(虚拟DOM)中的虚拟节点,用Javascript对象来描述真实的DOM把DOM标签属性,内容都变为对象属性
(2)VNode的优点?
兼容性强,不受执行环境的影响
减少操作DOM,提高页面性能
(3)什么是虚拟DOM?
虚拟 dom 是相对于浏览器所渲染出来的真实 dom而言的 就是一个普通的 JavaScript 对象,目的是为了进行最小化地DOM操作。
虚拟 DOM 主要做了两件事:
提供与真实 DOM 节点所对应的虚拟节点 vnode
将新的虚拟节点和旧的虚拟节点进行对比,然后更新页面
为什么不使用真实DOM?
创建真实DOM成本比较高,而如果用js对象来描述一个dom节点,成本比较低,另外我们在频繁操作dom是一种性能开销比较大。所以用虚拟dom来描述真实dom。
首先要建立一个VNode的类,DOM元素上的所有属性在VNode类实例化出来的对象上都存在对应的属性。
将VNode类实例化出来的对象进行分类。
然后通过编译将模板转成渲染函数render,执行渲染函数render,在其中创建不同类型的VNode类,最后整合就可以得到一个虚拟DOM。
最后通过patch将VNode和oldVNode进行比较后,生成真实的DOM。
可以触发视图更新的方法:
push()、pop()、shift()、unshift()、splice()、sort()、sort()、reverse()这些方法会改变被操作的数组;
filter()、concat()、slice()这些方法不会改变被操作的数组,返回一个新的数组;
不可以触发视图更新:
利用索引直接设置一个数组项,例如:this.array[index]=newValue;
直接修改数组的长度,例如:this.array.length=newLength.
解决方法:
(1)可以用this.$set(this.array,index,newValue)或者this.array.splice(index,1,newValue)
(2)可以用this.array.splice(newLength)
(1)使用Object.assign()方法,可以实现重置data中的数据。
基本定义:Object.assign()方法用于将所有的可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。
用法:Object.assign(target,...sources),第一个参数是目标对象,第二个参数是源对象,就是将源对象属性复制到目标对象,返回目标对象。
(2)利用v-bind和computed
首先在Vue组件内定义一个初始值对象originalData,之后利用v-bind指令绑定到各个表单元素上。最后,我们可以利用computed计算属性将data数据与原始数据进行比较,如果不同,就将data数据重置为初始状态。
(3)使用$refs指令
在Vue组件内使用ref来指定表单元素的名称,之后我们可以利用$refs指令来重置这些元素的值:
(1)将不常改变的库放到index.html中,通过cdn引入;
(2)vue路由的懒加载;
(3)不生成map文件;
(4)vue组件尽量不要全局引入;
(5)使用更轻量级的工具库;
(6)开启gzip压缩;
(7)首页单独做服务端渲染。
(1)为什么需要nextTick?
因为vue是异步修改DOM的并且不鼓励开发者直接接触DOM,但是有的时候业务需要必须对数据更改--刷新后的DOM做相应的处理,这时候就可以使用vue.nextTick(callback)这个api了。
(2)理解前的准备--什么是宏任务、什么是微任务?
常见的宏任务有:script、setTimeout、setInterval、I/O、UI rendering;
常见的微任务有:process、nextTick(node.js)、promise.then()、mutationObserver。
(3)理解原理是什么?
$nextTick 是vue中的异步更新,vue通过异步队列控制DOM更新和nextTick回调函数先后执行的方式。
因为箭头函数自己没有定义this上下文,而不是绑定到其父函数的上下文中。
当你在vue程序中使用箭头函数(=>)时,this关键字并不会绑定到vue实例上,因此会引发错误,所以建议使用标准函数声明。
1)动态组件
2)is 的用法
有些 HTML 元素,诸如