内容很饱满,过程可能会枯燥,愿你经过风雨,过后能成为不一样的烟火🎇,为了奖励看到最后的小伙伴,博主为你们准备了礼物哦
开发版本:包含完整的警告和调试模式
生产版本:删除了警告,体积更小
1.
引入vue.js后,给我们提供了一个构造函数 Vue
1.
在js中,
1.
后会返回一个vue实例对象,我们用变量接着它
1.
1.
传递一个配置对象{} – >
类型: 字符串
全称:element(元素)
作用:配置控制的元素,表示Vue要控制的区域,值为css选择器
- 作用和el一致,都是配置控制的元素,使用哪个都可以,二选一
- 问:和el有什么不同?
答:本质上没什么不同,\(mount为手动挂载,在项目中有时要进行延迟挂载,比如有时要在挂载之前进行一些其他的操作,比如判断等等(但是,这样做的时候很少,比邓哥回家的次数还少,emmmmm)</li></ul><ul><li>类型:对象</li><li>作用:存放要用到的数据,数据为响应式的</li></ul><ul><li></li></ul><p>使用方法: {{ }}<br/>*<br/>可以将vue中的数据填在插值表达式中,如:</p><ul><li></li></ul><p>除了填写data之外,还可以直接填写数据值(数字、字符串、布尔值、undefined、null、数组、对象),如:</p><ul><li></li></ul><p>注意:在插值表达式中直接书写对象类型值时,不要将三个{}连在一起,这样会报错,如:</p><ul><li></li></ul><p>还可在插值表达式中写表达式,如:</p><ul><li></li></ul><p>还可以填写其他的吗?不可以,No,以下这些都是不行滴:</p><ul><li></li></ul><p>记住:插值表达式中,可以写:data、js数据、表达式,其他的想都不要想。<br/>*<br/>注意,只要插值表达式中使用了数据,必须在data中声明过,否则会报错</p><ul><li></li></ul><p>还有另外一种可能,使用了未被声明过的数据,不报错:</p><ul><li></li></ul><p>数据变化,页面就会重新渲染<br/>*<br/>怎么更改数据?so easy</p><ul><li><p>问:为什么data会直接出现在vm实例对象中咧?<br/>答:当创建vue实例时,vue会将data中的成员代理给vue实例,目的是为了实现响应式,监控数据变化,执行某个监听函数(怎么实现的?想一想,提示:Object.defineProperty,试着实现一下)</p></li><li><p>问:实例中除了data数据外,其他东西是啥子?<br/>为了防止名称冲突。因为会将data中数据代理给vue,假如说我们自己写的data名称和vue中自带的属性冲突了,那么就会覆盖vue内部的属性,所以vue会把自己内部的属性成员名称前加上\)或_,如果加上的是\(,代表是我们可以使用的,如果加上的是_,是vue自己内部使用的方法或属性,我们不需要调用</p></li><li><p>更改的数据必须是存在的数据,否则不能重新渲染页面,因为他监听不到,如:</p></li></ul><ul><li>更改的数据必须已渲染过的数据,否则从性能角度考虑,不会重新渲染页面,如:</li></ul><ul><li>更改数据后,页面会立刻重新渲染吗?<br/>vue更新DOM的操作是异步执行的,只要侦听到数据变化,将开启一个异步队列,如果一个数据被多次变更,那么只会被推入到队列中一次,这样可以避免不必要的计算和DOM操作。</li></ul><p>同步执行栈执行完毕后,会执行异步队列</p><ul><li>值为被Vue控制的元素(或者说,Vue挂载的元素)</li></ul><ul><li>如何在更改数据后,看到渲染后的页面上的值?<br/>答:利用vm.\)nextTick或Vue.nextTick,在页面重新渲染,DOM更新后,会立刻执行vm.\(nextTick</li></ul><ul><li>vm.nextTick和Vue.nextTick还可以作为Promise使用</li></ul><ul><li>vm.\)nextTick 和 Vue.nextTick的区别?
Vue.nextTick内部函数的this指向window
vm.\(nextTick内部函数的this指向Vue实例对象</p><ul><li>好奇nextTick是怎么实现的吗?</li><li>异步任务分为宏任务(macro)和微任务(micro)</li><li>宏任务比较慢(如setTimeout等),微任务比较快(如Promise.then()等)</li><li>微任务在前,宏任务在后(eventloop,事件环)</li></ul><ul><li>在nextTick的实现源码中,会先判断是否支持微任务,不支持后,才会执行宏任务</li></ul><ul><li><p>曾经vue用过的宏任务</p></li><li><p>MessageChannel 消息通道 宏任务</p></li></ul><ul><li></li></ul><p>除了未被声明过和未被渲染的数据外,还有什么数据更改后不会渲染页面?<br/>1. 利用索引直接设置一个数组项时:</p><p>2. 修改数组的长度时:</p><p>3. 添加或删除对象:</p><ul><li></li></ul><p>问:要如何响应式的更新数组和对象?<br/>更改数组:</p><ol><li>利用数组变异方法:push、pop、shift、unshift、splice、sort、reverse </li><li>利用vm.\)set/Vue.set实例方法
使用方法:Vue.set(object, propertyName, value),也就是这个意思:Vue.set(要改谁,改它的什么,改成啥)
vm.\(delete是Vue.delete的别名<br/>使用方法:Vue.delete(object, target),也就是这个意思:Vue.delete(要删除谁的值,删除哪个)</p><p>更改对象:</p><ol><li>添加利用vm.\)set/Vue.set实例方法
可以绑定动态事件,Vue版本需要2.6.0+
可以不带参数绑定一个对象,Vue版本需要2.4.0+。
- { 事件名:事件执行函数 }
- 使用此种方法不支持函数传参&修饰符
v-on指令简写:
- 扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。
- 因为你无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试
- 当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何清理它们
.stop
- 调用 event.stop,阻止事件冒泡
.prevent
- 调用 event.preventDefault(),阻止默认事件
.capture
- 事件捕获模式
.self
只当事件是从侦听器绑定的元素本身触发时才触发回调
.once
只触发一次回调
*
2.1.4新增
.passive
- 设置 addEventListener 中的 passive 选项
- 能够提升移动端的性能
- 2.3.0新增
why passive? - 即使在触发触摸事件时,执行了一个空的函数,也会让页面卡顿。因为浏览器不知道监听器到底会不会阻止默认事件,所以浏览器要等到执行完整个函数后,才能决定是否要滚动页面。passive事件监听器,允许开发者告诉浏览器,监听器不会阻止默认行为,从而浏览器可以放心大胆的滚动页面,这样可以大幅度提升移动端页面的性能,因为据统计只有20%的触摸事件会阻止默认事件。
- .passive 会告诉浏览器你不想阻止事件的默认行为
注意
- 使用修饰符时,顺序很重要。相应的代码会以同样的顺序产生。因此, v-on:click.prevent.self 会阻止所有的点击的默认事件 v-on:click.self.prevent 只会阻止对元素自身点击的默认事件
- 不要把 .passive 和 .prevent 一起使用,因为 .prevent 将会被忽略,同时浏览器可能会向你展示一个警告。
在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符
你可以直接将 KeyboardEvent.key 暴露的任意有效按键名转换为 kebab-case 来作为修饰符。
在上述示例中,处理函数只会在 \(event.key 等于 PageDown 时被调用。</p><h4 id="按键码">按键码</h4><p>使用 keyCode 特性也是允许的:</p><p>注意:keyCode 的事件用法已经被废弃了,并可能不会被最新的浏览器支持。</p><p>为了在必要的情况下支持旧浏览器,Vue 提供了绝大多数常用的按键码的别名:</p><ul><li>.enter(回车键)</li><li>.tab</li><li>.delete (捕获“删除”和“退格”键)</li><li>.esc</li><li>.space (空格键)</li><li>.up (箭头上键)</li><li>.down (箭头下键)</li><li>.left(箭头左键)</li><li>.right(箭头右键)</li></ul><p>除了使用Vue提供的按键别名之外,还可以自定义按键别名:</p><p>可以用如下修饰符来实现仅在按下相应按键时才触发鼠标或键盘事件的监听器。 修饰键与常规按键不同,在和 keyup 事件一起用时,事件触发时修饰键必须处于按下状态,换句话说,只有在按住 ctrl 的情况下释放其它按键,才能触发 keyup.ctrl。而单单释放 ctrl 也不会触发事件。如果你想要这样的行为,请为 ctrl 换用 keyCode:keyup.17。</p><ul><li>.ctrl</li><li>.alt</li><li>.shift</li><li>.meta 在 Mac 系统键盘上,meta 对应 command 键 (⌘)。 在 Windows 系统键盘 meta 对应 Windows 徽标键 (⊞)。 在 Sun 操作系统键盘上,meta 对应实心宝石键 (◆)。 在其他特定键盘上,尤其在 MIT 和 Lisp 机器的键盘、以及其后继产品,比如 Knight 键盘、space-cadet 键盘,meta 被标记为“META”。 在 Symbolics 键盘上,meta 被标记为“META”或者“Meta”</li></ul><h4 id="exact-修饰符">exact 修饰符</h4><ul><li>允许你控制由精确的系统修饰符组合触发的事件。</li><li>2.5.0 +</li></ul><ul><li>仅当点击特定的鼠标按钮时会处理执行函数</li><li>2.2.0 +</li><li>.left</li><li>.right</li><li>.middle</li></ul><p>利用v-for指令,基于数据多次渲染元素。</p><p>用法:(item, index) in items 参数:items: 源数据数组 item:数组元素别名 index:可选,索引 可以访问所有父作用域的属性</p><p>可以利用替代作为分隔符,因为它更接近迭代器的语法:</p><p>用法:(value, key, index) in Object 参数:value: 对象值 key:可选,键名 index:可选,索引</p><p>用法:n in num 参数:n: 数字,从1开始</p><p>用法:str in string 参数:str: 字符串,源数据字符串中的每一个</p><p>可以利用template元素循环渲染一段包含多个元素的内容</p><p>Vue更新使用v-for渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue 将不会移动 DOM 元素来匹配数据项的顺序,而是简单复用此处每个元素:</p><p>在"就地复用"策略中,点击按钮,输入框不随文本一起下移,是因为输入框没有与数据绑定,所以vuejs默认使用已经渲染的dom,然而文本是与数据绑定的,所以文本被重新渲染。这种处理方式在vue中是默认的列表渲染策略,因为高效。</p><p>这个默认的模式是高效的,但是在更多的时候,我们并不需要这样去处理,所以,为了给Vue一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,我们需要为每项提供一个唯一key特性,Vue会基于 key 的变化重新排列元素顺序,并且会移除 key 不存在的元素。</p><h4 id="key的使用方法">key的使用方法</h4><p>预期值:number | string 有相同父元素的子元素必须有独特的 key,重复的 key 会造成渲染错误,key应唯一。</p><p>不建议将数组的索引作为key值,如:</p><p>当改变数组时,页面会重新渲染,Vue会根据key值来判断要不要移动元素。例如当页面重新渲染时,key值为"杉杉"的元素为,页面重新渲染前,key值为"杉杉"的元素也为,那么Vue就会移动这个元素,而不是重新生成一个元素。 当使用数组的索引作为key值时,页面重新渲染后,元素的key值会重新被赋值,例如我们将数组进行反转, 反转前:</p><div><thead><tr><th>元素</th><th>key值</th></tr></thead><tbody><tr><td></td><td>0</td></tr><tr><td></td><td>1</td></tr><tr><td></td><td>2</td></tr><tr><td></td><td>3</td></tr></tbody></div><p>反转后:</p><div><thead><tr><th>元素</th><th>key值</th></tr></thead><tbody><tr><td></td><td>0</td></tr><tr><td></td><td>1</td></tr><tr><td></td><td>2</td></tr><tr><td></td><td>3</td></tr></tbody></div><p>Vue会比对渲染前后拥有同样key的元素,发现有变动,就会再生成一个元素,如果用索引作key值得话,那么此时,所有的元素都会被重新生成。</p><p>那么key如何唯一的?</p><p>跟后台协作时,传回来的每一条数据都有一个id值,这个id就是唯一的,用id做key即可。</p><p>key不仅为v-for所有,它可以强制替换元素,而不是重复使用它:</p><p>永远不要把 v-if 和 v-for 同时用在同一个元素上。 当 Vue 处理指令时,v-for 比 v-if 具有更高的优先级,所以这个模板:</p><p>将会经过如下运算:</p><p>因此哪怕我们只渲染出一小部分用户的元素,也得在每次重新渲染的时候遍历整个列表,不论活跃用户是否发生了变化。 所以以下两种场景,我们可以做出如下处理:</p><ol><li>为了过滤一个列表中的项目。</li></ol><p>可以把上面的代码更新为:</p><p>这种方式仅为演示,在日后学习完计算属性后,要利用计算属性来做。</p><ol><li>为了避免渲染本应该被隐藏的列表</li></ol><p>html部分可替换成为:</p><p>将 v-if 置于外层元素上,我们不会再对列表中的每个用户检查 shouldShowUsers。取而代之的是,我们只检查它一次,且不会在 shouldShowUsers 为否的时候运算 v-for。</p><p>css文件在文件夹中,自行拷贝 所需数据:</p><p>css文件在文件夹中,自行拷贝</p><p>可以在表单元素上创建双向数据绑定。即数据更新元素更新、元素更新数据也会更新。<br/>本质上v-model为语法糖</p><div><thead><tr><th>元素类型</th><th>属性</th><th>事件</th></tr></thead><tbody><tr><td>input[type=text]、textarea</td><td>value</td><td>input</td></tr><tr><td>input[checkbox]、input[radio]</td><td>checked</td><td>change</td></tr><tr><td>select</td><td>value</td><td>change</td></tr></tbody></div><h4 id="typetext-文本框">type=text 文本框</h4><h4 id="typecheckbox-复选框">type=checkbox 复选框</h4><p>单个复选框</p><p>绑定到布尔值,v-model="Boolean"</p><p>多个复选框</p><p>绑定到同一个数组,v-model="Array" 数组中的值为被选中的input框value值</p><h4 id="typeradio-单选框">type=radio 单选框</h4><p>被绑定的数据和value同步</p><p>匹配的值为option中的汉字</p><h4 id="单选">单选</h4><p>注意:如果 v-model 表达式的初始值未能匹配任何选项, 元素将被渲染为“未选中”状态。在 iOS 中,这会使用户无法选择第一个选项。因为这样的情况下,iOS 不会触发 change 事件。因此,可以提供一个值为空的禁用选项:</p><h4 id="多选">多选</h4><p>绑定到一个数组</p><h4 id="lazy">.lazy</h4><p>在默认情况下,v-model在每次input事件触发后将输入框的值与数据进行同步。如果要变为使用change事件同步可以添加lazy修饰符:</p><h4 id="number">.number</h4><p>自动将用户的输入值转为数值类型:</p><h4 id="trim">.trim</h4><p>自动过滤用户输入的<strong>首尾</strong>空白字符:</p><p>有些时候,我们在模板中放入了过多的逻辑,从而导致模板过重,且难以维护。例如:</p><p>碰到这样的情况,我们必须看一段时间才能意识到,这里是想要显示变量message的翻转字符串,而且,一旦我们想要在模板中多次使用翻转字符串时,会更加麻烦。 所以,当我们处理复杂逻辑时,都应该使用计算属性。</p><p>计算属性是Vue配置对象中的属性,使用方式如下:</p><p>例如,我们想要获取到一串字符串的翻转字符串,我们可以利用计算属性来做:</p><p>我们可以看到,reversedMsg的值取决于msg的值,所以,当我们更改msg的值是,reversedMsg的值也会随之更改。</p><p>其实,我们上述的功能,利用方法也可以实现,如:</p><p>虽然在表达式中调用方法也可以实现同样的效果,但是使用和使用有着本质的区别。 当使用方法时,每一次页面重新渲染,对应的方法都会重新执行一次,如:</p><p>在上面的例子中我们可以看到,一旦更改name的值,页面会重新渲染,此刻控制台中打印出这串字符串,代表着reversedMsg这个函数执行了,但是我们并不需要该方法执行,因为改动的数据和这个函数没有任何关系,如果这个函数内的逻辑很复杂,那么对于性能来讲,也是一种消耗。</p><p>但是利用计算属性做,就不会有这样的现象出现,如:</p><p>此时可以看到,当给数据name重新赋值时,计算属性并没有执行。 所以,计算属性和方法的最本质的区别,是:<strong>计算属性是基于响应式依赖进行缓存的</strong>,计算属性的值一直存于缓存中,只要它依赖的data数据不改变,每次访问计算属性,都会立刻返回缓存的结果,而不是再次执行函数。而方法则是每次触发重新渲染,调用方法将总会再次执行函数。</p><p>那么,为什么需要缓存呢?</p><p>假如说,我们有一个计算属性A,它需要遍历一个巨大的数组并且做巨大的计算。然后我们需要使用到这个计算属性A,如果没有缓存,我们就会再次执行A的函数,这样性能开销就变得很大了。</p><p>计算属性除了写成一个函数之外,还可以写成一个对象,对象内有两个属性,getter&setter,这两个属性皆为函数,写法如下:</p><h4 id="getter-读取">getter 读取</h4><p>在前面,我们直接将计算属性写成了一个函数,这个函数即为getter函数。也就是说,计算属性默认只有getter。 getter的this,被自动绑定为Vue实例。<br/>何时执行?</p><p>当我们去获取某一个计算属性时,就会执行get函数。</p><h4 id="setter-设置">setter 设置</h4><p>可选,set函数在给计算属性重新赋值时会执行。 参数:为被重新设置的值。 setter的this,被自动绑定为Vue实例。</p><p>要注意,即使给计算属性赋了值,计算属性也不会改变,在重复一遍,只有当依赖的响应式属性变化了,计算属性才会重新计算。</p><p>侦听属性,响应数据(data&computed)的变化,当数据变化时,会立刻执行对应函数,</p><h4 id="函数类型">函数类型</h4><p>例:</p><p>侦听器函数,会接收两个参数,第一个参数为newVal(被改变的数据),第二个参数为oldVal(赋值新值之前的值)。如在上述代码中,将侦听器watch更改一下,如:</p><h4 id="字符串类型">字符串类型</h4><p>值为方法名字,被侦听的数据改变时,会执行该方法。</p><h4 id="对象类型">对象类型</h4><p>写成对象类型时,可以提供选项。</p><p>handler</p><p>必需。handler时被侦听的数据改变时执行的回调函数。 handler的值类型为函数/字符串,写成字符串时为一个方法的名字。</p><p>deep</p><p>在默认情况下,侦听器侦听对象只侦听引用的变化,只有在给对象赋值时它才能被监听到。所以需要使用deep选项,让其可以发现对象内部值的变化,将deep的值设置为true,那么无论该对象被嵌套的有多深,都会被侦听到。</p><p>注意,当对象的属性较多的时候,性能开销会比较大,此时可以监听对象的某个属性,这个后面再说。</p><p>immediate</p><p>加上immediate选项后,回调将会在侦听开始之后立刻被调用。而不是等待侦听的数据更改后才会调用。</p><h4 id="数组类型">数组类型</h4><p>可以将多种不同值类型写在一个数组中。如:</p><h4 id="正常对象key值">正常对象key值</h4><p>以上演示的都是正常的对象key值,这里不再赘述。</p><h4 id="字符串类型key值">字符串类型key值</h4><p>当key值类型为字符串时,可以实现监听对象当中的某一个属性,如:</p><p>Vue实例将会在实例化时调用\)watch,遍历watch对象的每一个属性。 我们也可以利用vm.\(watch来实现侦听,用法与watch选项部分一致,略有不同。以下为使用方法。</p><ol><li>侦听某个数据的变化</li></ol><ol><li>侦听某个对象属性的变化</li></ol><ol><li>当监听的数据的在初始不确定,由多个数据得到时,此时可以将第一个参数写成函数类型</li></ol><p>侦听器函数执行后,会返回一个取消侦听函数,用来停止触发回调:</p><p>使用unwatch时,需要注意的是,在带有immediate选项时,不能在第一次回调时取消侦听数据。</p><p>如果仍然希望在回调内部用一个取消侦听的函数,那么可以先检查该函数的可用性:</p><ol><li></li></ol><p>两者都可以观察和响应Vue实例上的数据的变动。<br/>1.<br/>watch擅长处理的场景是:一个数据影响多个数据。计算属性擅长处理的场景是:多个数据影响一个数据。<br/>1.<br/>在侦听器中可以执行异步,但是在计算属性中不可以,例:</p><p>使用侦听器:</p><p>url: https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su</p><p>请求方式:jsonp</p><p>发送参数:</p><ol><li>wd:字符串,搜索的文字</li><li>cb:字符串,callback函数的名字</li></ol><p>返回结果:(JSON格式)</p><p>在Vue中实现异步加载需要使用到vue-resource库,利用该库发送ajax。</p><p>要注意的是,vue-resource依赖于Vue,所以要先引入Vue,再引入vue-resource。</p><p>引入vue-resource之后,在Vue的全局上会挂载一个\)http方法,在vm.\(http方法上有一系列方法,每个HTTP请求类型都有一个对应的方法。</p><p>vue-resource使用了promise,所以\)http中的方法的返回值是一个promise。
POST请求
用于提交数据
常用data格式:
- 表单提交:multipart/form-data,比较老的网站会使用表单提交去获取数据,现在基本都不用表单提交,而是使用ajax,但是现在表单提交仍然存在,有时候需要做图片上传、文件上传。
- 文件上传:application/json,现在大多数情况下都是用这个格式
使用方法:vm.\(http.post(url, [body], [options])</p><ul><li>url: 必需,请求目标url</li><li>body: 非必需,作为请求体发送的数据</li><li>options:非必需,作为请求体发送的数据</li></ul><h4 id="get请求">GET请求</h4><p>获取数据</p><p>使用方法:vm.\)http.get(url, [options])
在get请求时传参:
PUT请求
更新数据,将所有的数据全都推送到后端 使用方法:vm.\(http.put(url, [body], [config])</p><h4 id="patch请求">PATCH请求</h4><p>更新数据,只将修改的数据全都推送到后端 使用方法:vm.\)http.patch(url, [body], [config])
DELETE请求
删除数据 使用方法:vm.\(http.delete(url, [config])</p><h4 id="head请求">HEAD请求</h4><p>请求头部信息 使用方法:vm.\)http.head(url, [config])
JSONP请求
除了jsonp以外,以上6种的API名称是标准的HTTP方法。
使用方法:vm.\(http.jsonp(url, [options]);</p><div><thead><tr><th>参数</th><th>类型</th><th>描述</th></tr></thead><tbody><tr><td>url</td><td>String</td><td>请求目标url</td></tr><tr><td>body</td><td>Object, FormData, string</td><td>作为请求体发送的数据</td></tr><tr><td>headers</td><td>Object</td><td>作为请求头部发送的头部对象</td></tr><tr><td>params</td><td>Object</td><td>作为URL参数的参数对象</td></tr><tr><td>method</td><td>String</td><td>HTTP方法 (例如GET,POST,...)</td></tr><tr><td>responseType</td><td>String</td><td>设置返回数据的类型</td></tr><tr><td>timeout</td><td>Number</td><td>在请求发送之前修改请求的回调函数</td></tr><tr><td>credentials</td><td>Boolean</td><td>是否需要出示用于跨站点请求的凭据</td></tr><tr><td>emulateHTTP</td><td>Boolean</td><td>是否需要通过设置X-HTTP-Method-Override头部并且以传统POST方式发送PUT,PATCH和DELETE请求。</td></tr><tr><td>emulateJSON</td><td>Boolean</td><td>设置请求体的类型为application/x-www-form-urlencoded</td></tr><tr><td>before</td><td>function(request)</td><td>在请求发送之前修改请求的回调函数</td></tr><tr><td>uploadProgress</td><td>function(event)</td><td>用于处理上传进度的回调函数</td></tr><tr><td>downloadProgress</td><td>function(event)</td><td>用于处理下载进度的回调函数</td></tr></tbody></div><p>通过如下属性和方法处理一个请求获取到的响应对象:</p><h4 id="属性">属性</h4><div><thead><tr><th>属性</th><th>类型</th><th>描述</th></tr></thead><tbody><tr><td>url</td><td>String</td><td>响应的 URL 源</td></tr><tr><td>body</td><td>Object, Blob, string</td><td>响应体数据</td></tr><tr><td>headers</td><td>Header</td><td>请求头部对象</td></tr><tr><td>ok</td><td>Boolean</td><td>当 HTTP 响应码为 200 到 299 之间的数值时该值为 true</td></tr><tr><td>status</td><td>Number</td><td>HTTP 响应码</td></tr><tr><td>statusText</td><td>String</td><td>HTTP 响应状态</td></tr></tbody></div><h4 id="方法">方法</h4><div><thead><tr><th>方法</th><th>描述</th></tr></thead><tbody><tr><td>text()</td><td>以字符串方式返回响应体</td></tr><tr><td>json()</td><td>以格式化后的 json 对象方式返回响应体</td></tr><tr><td>blob()</td><td>以二进制 Blob 对象方式返回响应体</td></tr></tbody></div><p>以json()为例:</p><p>很不幸,Vue官方已不再维护这个库了,so...哈哈哈,我们再学点其他的୧[ /* ಡ ▽ ಡ /* ]୨</p><p>Axios是一个基于promise的HTTP库</p><p>浏览器支持情况:Chrome、Firefox、Safari、Opera、Edge、IE8+</p><ul><li>axios(config)</li><li>axios(url, [config])</li></ul><p>最常用的配置:</p><p>为方便起见,为所有支持的请求方法提供了别名。</p><ul><li>axios.request(config)</li><li>axios.get(url, [config])</li><li>axios.post(url, [data], [config]])</li><li>axios.delete(url, [config])</li><li>axios.head(url, [config])</li><li>axios.put(url, [data], [config])</li><li>axios.patch(url, [data], [config]])</li><li>axios.options(url, [config])</li></ul><p>可以指定将被用在各个请求的配置默认值</p><h4 id="全局配置">全局配置</h4><p>在实际项目中,很少用全局配置。</p><h4 id="实例配置">实例配置</h4><p>可以使用自定义配置新建一个axios实例</p><h4 id="请求配置">请求配置</h4><h4 id="配置的优先顺序">配置的优先顺序</h4><p>全局 < 实例 < 请求</p><p>同时进行多个请求,并统一处理返回值</p><ul><li>axios.all(iterable)</li><li>axios.spread(callback)</li></ul><p>interceptors,在发起请求之前做一些处理,或者在响应回来之后做一些处理。</p><h4 id="请求拦截器">请求拦截器</h4><h4 id="响应拦截器">响应拦截器</h4><h4 id="移除拦截器">移除拦截器</h4><h4 id="为axios实例添加拦截器">为axios实例添加拦截器</h4><p>用于取消正在进行的http请求</p><p>在请求错误时进行的处理 request / response 是error的上下文,标志着请求发送 / 得到响应 在错误中,如果响应有值,则说明是响应时出现了错误。 如果响应没值,则说明是请求时出现了错误。 在错误中,如果请求无值,则说明是请求未发送出去,如取消请求。</p><p>在实际开发过程中,一般在拦截器中统一添加错误处理 请求拦截器中的错误,会当请求未成功发出时执行,但是要注意的是:取消请求后,请求拦截器的错误函数也不会执行,因为取消请求不会抛出异常,axios对其进行了单独的处理。 在更多的情况下,我们会在响应拦截器中处理错误。</p><p>当axios的请求为非简单请求时,浏览器会进行预检,及发送OPTIONS请求。请求到服务器,询问是否允许跨域。如果响应中允许预检中请求的跨域行为,则浏览器会进行真正的请求。否则会报405错误。</p><p>关于el</p><p>提供一个在页面上已存在的 DOM 元素作为 Vue 实例的挂载目标。可以是 CSS 选择器,也可以是一个 HTML 元素 实例。</p><p>如果在实例化时存在这个选项,实例将立即进入编译过程,否则,需要显式调用 vm.\)mount() 手动开启编译。
template
一个字符串模板作为 Vue 实例的标识使用。模板将会 替换 挂载的元素,挂载元素的内容都将被忽略。
Vue初始化到挂载的流程
每个 Vue 实例在被创建时都要经过一系列的初始化过程,例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。

所有的生命周期钩子自动绑定 this 上下文到实例中,因此你可以访问数据,对属性和方法进行运算

beforeCreate
在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
打印顺序:
created
在实例创建完成后被立即调用。
在这一步,实例已完成以下的配置:数据观测 (data observer),属性和方法的运算,watch/event 事件回调。
如果要在第一时间调用methods中的方法,或者操作data中的数据,可在此钩子中进行操作。 需要注意的是,执行此钩子时,挂载阶段还未开始,\(el 属性目前不可见。</p><p>此时,可以进行数据请求,将请求回来的值赋值给data中的数据。</p><p>打印顺序:</p><h4 id="beforemount">beforeMount</h4><p>在挂载开始之前被调用,此时模板已经编译完成,只是未将生成的模板替换el对应的元素。</p><p>在此钩子函数中,可以获取到模板最初始的状态。</p><p>此时,可以拿到vm.\)el,只不过为旧模板
mounted
el 被新创建的 vm.\(el 替换,并挂载到实例上去之后调用该钩子。</p><p>在该钩子函数中的vm.\)el为新模板。
执行完该钩子函数后,代表实例已经被完全创建好。
如果要在第一时间,操作页面上的dom节点时,可以在此钩子函数中操作
beforeUpdate
数据更新时调用,发生在虚拟 DOM 打补丁之前。此时数据已经更新,但是DOM还未更新
updated
数据更改导致DOM重新渲染后,会执行该钩子函数。
此时数据和dom同步。
beforeDestroy
实例销毁之前调用。在这一步,实例仍然完全可用。
可以在该钩子函数中,清除定时器。
destroyed
Vue 实例销毁后调用。调用后,Vue 实例指示的所有东西都会解绑定,所有的事件监听器会被移除。
1.轮播图
baseURL: ‘https://developer.duyiedu.com/vue/bz’ url: ‘/banner’
2.导航
baseURL: ‘https://developer.duyiedu.com/vue/bz’ url: ‘/nav’
3.视频
baseURL: ‘https://developer.duyiedu.com/vue/bz’ url: ‘/video’ Request:
组件是可复用的Vue实例,且带有一个名字,例如名字为shanshan-cmp,那么我们则可以在一个通过new Vue创建的根实例中,把这个组件作为自定义元素来使用:
因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 data、computed、watch、methods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。
全局组件
Vue.component
利用Vue.component创建的组件组件是全局注册的。也就是说它们在注册之后可以用在任何新创建的 Vue 根实例 (new Vue) 的模板中。
参数:
- {string}
- {Function | Object} [definition]
用法: 注册或获取全局组件。注册还会自动使用给定的id设置组件的名称。
示例:
局部组件
在components选项中定义要使用的组件。 对于 components 对象中的每一个属性来说,其属性名就是自定义元素的名字,其属性值就是这个组件的选项对象。
示例:
组件名
定义组件名的方式有两种:
使用kebab-case (横短线分隔命名)
当使用kebab-case定义一个组件时,你必须在引用这个自定义元素时使用kebab-case,例如:。
使用PascalCase (大驼峰命名)
当使用PascalCase定义一个组件时,你在引用这个自定义元素时两种命名法都可以。也就是说 和 都是可接受的。注意,尽管如此,直接在 DOM (即字符串模板或单文件组件) 中使用时只有 kebab-case 是有效的。
另:我们强烈推荐遵循 W3C 规范中的自定义组件名 (字母全小写且必须包含一个连字符)。这会帮助你避免和当前以及未来的 HTML 元素相冲突。
组件复用
可以将组件进行任意次数的复用:
自闭合组件
在单文件组件、字符串模板和 JSX 中没有内容的组件应该是自闭合的——但在 DOM 模板里永远不要这样做。
自闭合组件表示它们不仅没有内容,而且刻意没有内容。其不同之处就好像书上的一页白纸对比贴有“本页有意留白”标签的白纸。而且没有了额外的闭合标签,你的代码也更简洁。
不幸的是,HTML 并不支持自闭合的自定义元素——只有官方的“空”元素。所以上述策略仅适用于进入 DOM 之前 Vue 的模板编译器能够触达的地方,然后再产出符合 DOM 规范的 HTML。
组件的data选项
当我们定义一个组件时,它的 data 并不是像这样直接提供一个对象:
取而代之的是,一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:
如果 Vue 没有这条规则,点击一个按钮就可能会像下面一样影响到其它所有实例:

单个根元素
每个组件必须只有一个根元素,当模板的元素大于1时,可以将模板的内容包裹在一个父元素内。
如:
在上述模板中,你会发现我们能够在组件实例中访问这个值,就像访问 data 中的值一样:
HTML 中的特性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。故:当 传递的prop为 短横线分隔命名时,组件内 的props 应为 驼峰命名 。 如:
要注意的是:如果使用的是字符串模板,那么这个限制就不存在了。
像这样,我们已经知道了可以给 prop 传入一个静态的值:
若想要传递一个动态的值,可以配合v-bind指令进行传递,如:
传递一个对象的所有属性
如果你想要将一个对象的所有属性都作为 prop 传入,你可以使用不带参数的 v-bind 。例如,对于一个给定的对象 person:
传递全部属性:
上述代码等价于:
我们可以为组件的 prop 指定验证要求,例如你可以要求一个 prop 的类型为什么。如果说需求没有被满足的话,那么Vue会在浏览器控制台中进行警告,这在开发一个会被别人用到的组件时非常的有帮助。
为了定制 prop 的验证方式,你可以为 props 中的值提供一个带有验证需求的对象,而不是一个字符串数组。例如:
上述代码中,对prop进行了基础的类型检查,类型值可以为下列原生构造函数中的一种:、、、、、、、、任何自定义构造函数、或上述内容组成的数组。 需要注意的是 和 会通过任何类型验证。 除基础类型检查外,我们还可以配置高级选项,对prop进行其他验证,如:类型检测、自定义验证和设置默认值。 如:
为了更好的团队合作,在提交的代码中,prop 的定义应该尽量详细,至少需要指定其类型。
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
这里有两种常见的试图改变一个 prop 的情形:
- 这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用,在后续操作中,会将这个值进行改变。在这种情况下,最好定义一个本地的 data 属性并将这个 prop 用作其初始值:
- 这个 prop 以一种原始的值传入且需要进行转换。在这种情况下,最好使用这个 prop 的值来定义一个计算属性:
非Prop特性指的是,一个未被组件注册的特性。当组件接收了一个非Prop特性时,该特性会被添加到这个组件的根元素上。
想象一下 的模板是这样的:
为了给我们的日期选择器插件定制一个主题,我们可能需要像这样添加一个特别的类名:
在这种情况下,我们定义了两个不同的 class 的值:
- my-cmp,这是在组件的模板内设置好的
- b,这是从组件的父级传入的
对于绝大多数特性来说,从外部提供给组件的值会替换掉组件内部设置好的值。所以如果传入 type="text" 就会替换掉 type="date" 并把它破坏!庆幸的是,class 和 style 特性会稍微智能一些,即两边的值会被合并起来,从而得到最终的值:my-cmp b。
如果不希望组件的根元素继承特性,那么可以在组件选项中设置 。如:
在这种情况下,非常适合去配合实例的 \(attrs 属性使用,这个属性是一个对象,键名为传递的特性名,键值为传递特性值。</p><p>使用 和 相互配合,我们就可以手动决定这些特性会被赋予哪个元素。如:</p><p>注意:inheritAttrs: false 选项不会影响 style 和 class 的绑定。</p><p>首先,我们来写一个博文组件,如:</p><p>可以看到每一个博文组件中,都有一个按钮,可以去放大页面中字体的字号,也就是说,当点击这个按钮时,我们要告诉父组件改变数据去放大所有博文的文本。碰见这样的情况,该如何做呢?</p><p>Vue 实例提供了一个自定义事件来解决这个问题。父组件可以像处理原生DOM元素一样,通过 指令,监听子组件实例的任意事件,如:</p><p>那么,怎么样能够去监听到一个 这么奇怪的事件呢?这就需要在组件内,去主动触发一个<strong>自定义事件</strong>了。</p><p>如何触发? 通过调用 \)emit 方法 并传入事件名称来触发一个事件,如:
这样,父组件就可以接收该事件,更新数据 的值了。
在有些情况下,我们可能想让 组件决定它的文本要放大多少。这是可以使用 \(emit 的第二个参数来提供这个值,如:</p><p>在父组件监听这个事件时,可以通过 \)event 访问到被抛出的这个值:
或者,将这个事件处理函数写成一个方法:
那么,这个值将会作为第一个参数,传入这个方法:
不同于组件和prop,事件名不存在任何自动化的大小写转换。而是触发的事件名需要完全匹配监听这个事件所有的名称。如果触发一个camelCase名字的事件:
则监听这个名字的kabab-case版本是不会有任何效果的。
与组件和prop不同的是,事件名不会被当作一个 JS 变量名或者属性名,所以就没有理由使用camelCase 或 PascalCase 了。
并且 v-on 事件监听器在 DOM 模板中会被自动转换为全小写,所以 @myEvent 将会变成 @myevent,导致 myEvent 不可能被监听到。
因此,推荐始终使用 kebab-case 的事件名。
在组件上去监听事件时,我们监听的是组件的自动触发的自定义事件,但是在一些情況下,我们可能想要在一个组件的根元素上直接监听一个原生事件。这是,可以使用 v-on 指令的 .native 修饰符,如:
这样处理,在有些时候是很有用的,不过在尝试监听一个类似元素时,这并不是一个好主意,例如组件可能做了重构,如:
可以看到,此时组件的根元素实际上是一个<label>元素,那么父级的.native监听器将静默失败。它不会产生任何报错,但是处理函数不会如预期被调用。
为了解决这个问题,Vue提供了一个\(listeners属性,它是一个对象,里面包含了作用在这个组件上的所有监听器。例如:</p><p>有了这个 \)listeners 属性,我们可以配合 v-on="\(listeners" 将所有的事件监听器指向这个组件的某个特定的子元素,如:</p><p>由于自定义事件的出现,在组件上也可以使用v-model指令。</p><p>在 input 元素上使用v-mode指令时,相当于绑定了value特性以及监听了input事件:</p><p>等价于:</p><p>当把v-model指令用在组件上时:</p><p>则等价于:</p><p>同 input 元素一样,在组件上使用v-model指令,也是绑定了value特性,监听了input事件。</p><p>所以,为了让 v-model 指令正常工作,这个组件内的必须:</p><ul><li>将其value特性绑定到一个叫 value 的prop 上</li><li>在其input事件被触发时,将新的值通过自定义的input事件抛出 如:</li></ul><p>这样操作后,v-model就可以在这个组件上工作起来了。</p><p>通过上面的学习,我们知道了,一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value 特性用于不同的目的。碰到这样的情况,我们可以利用 model 选项来避免冲突:</p><p>使用组件:</p><p>这里的 lovingVue 的值将会传入这个名为 checked 的 prop。同时当 <base-checkbox> 触发一个 change 事件并附带一个新的值的时候,这个 lovingVue 的属性将会被更新。</p><p>除了使用 v-model 指令实现组件与外部数据的双向绑定外,我们还可以用 v-bind 指令的修饰符 .sync 来实现。</p><p>那么,该如何实现呢? 先回忆一下,不利用 v-model 指令来实现组件的双向数据绑定:</p><p>那么,我们也可以试着,将监听的事件名进行更改,如:</p><p>这样也是可以实现双向数据绑定的,那么和 .sync 修饰符 有什么关系呢? 此时,我们对代码进行修改:</p><p>所以,.sync 修饰符 本质上也是一个语法糖,在组件上使用:</p><p>等价于:</p><p>当我们用一个对象同时设置多个prop时,也可以将.sync修饰符和 v-bind配合使用:</p><p><strong>注意:</strong></p><ul><li>带有.sync修饰符的v-bind指令,只能提供想要绑定的属性名,<strong>不能</strong>和表达式一起使用,如:,这样操作是无效的</li><li>将 用在 一个字面量对象上,如 ,是无法工作的,因为在解析一个像这样的复杂表达式的时候,有很多边缘情况需要考虑。</li></ul><p>先明确一件事情,在 vue 1.x 时,就已经支持 .sync 语法,但是此时的 .sync 可以完全在子组件中修改父组件的状态,造成整个状态的变换很难追溯,所以官方在2.0时移除了这个特性。然后在 vue2.3时,.sync又回归了,跟以往不同的是,现在的.sync完完全全就是一个语法糖的作用,跟v-model的实现原理是一样的,也不容易破环院有的数据模型,所以使用上更安全也更方便。</p><ul><li>两者都是用于实现双向数据传递的,实现方式都是语法糖,最终通过 + 来达成目的。</li><li>vue 1.x 的 .sync 和 v-model 是完全两个东西,vue 2.3 之后可以理解为一类特性,使用场景略微有区别</li><li>当一个组件对外只暴露一个受控的状态,切都符合统一标准的时候,我们会使用v-model来处理。.sync则更为灵活,凡是需要双向数据传递时,都可以去使用。</li></ul><p>和 HTML 元素一样,我们经常需要向一个组件传递内容,像这样:</p><p>如果有这样的需求,我们就可以通过插槽来做。</p><p>通过插槽,我们可以这样合成组件:</p><p>组件模板中可以写成:</p><p>当组件渲染时,将会被替换为“写在组件标签结构中的内容”。 插槽内可以包含任何模板代码,包括HTML和其他组件。 如果没有包含元素,则该组件起始标签和结束标签之间的任何内容都会被抛弃。</p><p>当在插槽中使用数据时:</p><p>该插槽跟模板的其他地方一样可以访问相同的实例属性,也就是相同的“作用域”,而不能访问的作用域。 请记住: <strong>父级模板里的所有内容都是在父级作用域中编译的;子模板里的所有内容都是在子作用域中编译的。</strong></p><p>我们可以设置默认插槽,它会在没有提供内容时被渲染,如,在组件中:</p><p>我们希望这个内绝大多数情况下都渲染文本“Submit”,此时就可以将“Submit”作为后备内容,如:</p><p>当使用组件未提供插槽时,后备内容将会被渲染。如果提供插槽,则后备内容将会被取代。</p><p>有时我们需要多个插槽,如组件:</p><p>此时,可以在元素上使用一个特殊的特性:name。利用这个特性定义额外的插槽:</p><p>一个不带 name 的 出口会带有隐含的名字“default”。 在向具名插槽提供内容的时候,我们可以在一个 元素上使用 v-slot 指令,并以 v-slot 的参数的形式提供其名称:</p><p>现在元素中的所有内容都会被传入相应的插槽。任何没有被包裹在带有的中的内容都会被视为默认插槽的内容。 为了模板更清晰,也可以写成以下这样:</p><p><strong>注意:v-slot只能添加在上,只有一种例外情况。</strong></p><p>为了能够让插槽内容访问子组件的数据,我们可以将子组件的数据作为元素的一个特性绑定上去:</p><p>绑定在 元素上的特性被称为<strong>插槽 prop</strong>。 那么在父级作用域中,我们可以给带一个值来定义我们提供的插槽prop的名字:</p><h4 id="独占默认插槽的缩写语法">独占默认插槽的缩写语法</h4><p>当被提供的内容只有默认插槽时,组件的标签可以被当作插槽的模板来使用,此时,可以将直接用在组件上:</p><p>也可以更简单:</p><p>注意:<strong>默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确</strong>。</p><p>只要出现多个插槽,就需要为所有的插槽使用完整的基于的语法。</p><h4 id="解构插槽prop">解构插槽Prop</h4><p>我们可以使用解构传入具体的插槽prop,如:</p><p>这样模板会更简洁,尤其是在为插槽提供了多个prop时。 此外还可以有其他可能,如prop重命名:</p><p>以及自定义后备内容,当插槽prop是undefined时生效:</p><p>Vue 2.6.0新增</p><p>Vue 2.6.0新增</p><p>跟和一样,也有缩写,将替换为。</p><p>当然,和其它指令一样,该缩写只在其有参数的时候才可用。</p><h4 id="带有slot特性的具名插槽">带有slot特性的具名插槽</h4><p>自 2.6.0 起被废弃</p><h4 id="带有slot-scope特性的作用域插槽">带有slot-scope特性的作用域插槽</h4><p>自 2.6.0 起被废弃</p><p>当我们在一个多标签的界面中,在不同组件之间进行动态切换是非常有用的。</p><p>通过上面方法,我们可以实现组件间的切换,能够注意到的是:每一次切换标签时,都会创建一个新的组件实例,重新创建动态组件在更多情况下是非常有用的,但是在这个案例中,我们会更希望哪些标签的组件实例能够在它们第一次被创建的时候缓存下来。为了解决这个问题,我们可以用一个元素将动态组件包裹起来。如:</p><p>注意: 要求被切换到的组件都有自己的名字,不论是通过组件的 name 选项还是局部/全局注册。</p><p> 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中。 当组件在 内被切换,它的 activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。</p><p>activated:keep-alive 组件激活时调用。 deactivated: keep-alive 组件停用时调用。</p><p>接下来我们要学习的都是和处理边界情况有关的功能,即一些需要对 Vue 的规则做一些小调整的特殊情况。需要注意的是,这些功能都是有劣势或危险场景的。</p><p>在绝大多数情况下,我们最好不要触达另一个组件实例内部或手动操作 DOM 元素。不过也确实在一些情况下做这些事情是合适的。</p><h4 id="访问根实例">访问根实例</h4><p>在每个子组件中,可以通过 \)root 访问根实例。
所有的子组件都可以将这个实例作为一个全局 store 来访问或使用。
在demo或在有少量组件的小型应用中使用是非常方便的。但是在大型应用里使用就会很复杂了。所以,我们还是要用Vuex(后面会学)来管理应用的状态。
访问父级组件实例
在子组件中,可以通过 \(parent 访问 父组件实例。这可以替代将数据以prop的方式传入子组件的方式。</p><p>如:</p><p>若 cmp-parent 需要共享一个属性 share,它的所有子元素都需要访问 share 属性,在这种情况下 cmp-a 可以通过 this.\)parent.share的方式访问share。
但是,通过这种模式构建出来的组件内部仍然容易出现问题。比如,我们在cmp-a 中嵌套一个一个子组件 cmp-b,如:
那么,在cmp-b组件中去访问share时,需要先查看一下,其父组件中是否存在share,如果不存在,则在向上一级查找,落实到代码上为:
这样做,很快组件就会失控:触达父级组件会使应用更难调试和理解,尤其是当变更父组件数据时,过一段时间后,很难找出变更是从哪里发起的。
碰到上述情况,可以使用依赖注入解决。
依赖注入
在上面的例子中,利用 \(parent 属性,没有办法很好的扩展到更深层级的嵌套组件上。这也是依赖注入的用武之地,它用到了两个新的实例选项:provide 和 inject。</p><p>provide 选项允许我们指定想要提供给后代组件的数据/方法,例如:</p><p>然后再任何后代组件中,我们都可以使用 inject 选项来接受指定想要添加在实例上的属性。</p><p>相比 \)parent 来说,这个用法可以让我们在任意后代组件中访问share,而不需要暴露整个 cmp-parent 实例。这允许我们更好的持续研发该组件,而不需要担心我们可能会改变/移除一些子组件依赖的东西。同时这些组件之间的接口是始终明确定义的,就和 props 一样。
实际上,你可以把依赖注入看作一部分“大范围有效的 prop”,除了:
- 祖先组件不需要知道哪些后代组件使用它提供的属性
- 后代组件不需要知道被注入的属性来自哪里
然而,依赖注入还是有负面影响的。它将你应用程序中的组件与它们当前的组织方式耦合起来,使重构变得更加困难。同时所提供的属性是非响应式的。这是出于设计的考虑,因为使用它们来创建一个中心化规模化的数据跟使用 \(root做这件事都是不够好的。如果你想要共享的这个属性是你的应用特有的,而不是通用化的,或者如果你想在祖先组件中更新所提供的数据,那么这意味着你可能需要换用一个像 Vuex 这样真正的状态管理方案了。</p><h4 id="访问子组件实例或子元素">访问子组件实例或子元素</h4><p>尽管存在prop和事件,但是有时候我们仍可能需要在JS里直接访问一个子组件,那么此时,我们可以通过 ref 特性为子组件赋予一个ID引用:</p><p>这样就可以通过this.\)refs.cmp 来访问实例。 ref 也可以 对指定DOM元素进行访问,如:
那么,我们可以通过 this.\(refs.input 来访问到该DOM元素。</p><p>当ref 和 v-for 一起使用时,得到的引用将会是一个包含了对应数据源的这些子组件的数组。</p><p>注意:\)refs 只会在组件渲染完成之后生效,并且它们不是响应式的。应该避免在模板或计算属性中访问 \(refs。</p><p>除了 v-on 和 \)emit 外, Vue 实例在其事件接口中还提供了其它的方法。我们可以:
- 通过 \(on(eventName, eventHandler) 侦听一个事件</li><li>通过 \)once(eventName, eventHandler) 一次性侦听一个事件
- 通过 \(off(eventName, eventHandler) 停止侦听一个事件</li></ul><p>这几个方法一般不会被用到,但是,当需要在一个组件实例上手动侦听事件时,他们是可以派的上用场的。</p><p>例如,有时我们会在组件中集成第三方库:</p><p>使用上面的方法,有两个潜在的问题:</p><ul><li>它需要在这个组件实例中保存这个 picker,如果可以的话最好只有生命周期钩子可以访问到它。这并不算严重的问题,但是它可以被视为杂物。</li><li>我们的建立代码独立于我们的清理代码,这使得我们比较难于程序化地清理我们建立的所有东西。</li></ul><p>所有,我们可以通过程序化的侦听器解决这两个问题:</p><p>使用了这个策略,我们还可以让多个输入框元素使用不同的pikaday:</p><p>注意,即便如此,如果你发现自己不得不在单个组件里做很多建立和清理的工作,最好的方式通常还是创建更多的模块化组件,在这个例子中,我们推荐创建一个可复用的 组件。</p><h4 id="递归组件">递归组件</h4><p>组件是可以在它们自己的模板中调用自身的,不过它们只能通过name选项来做这件事:</p><p>不过当使用 Vue.component 全局注册一个组件时,全局的ID会自动设置为该组件的 name 选项。</p><p>稍有不慎,递归组件就可能导致无限循环:</p><p>类似上述的组件将会导致“max stack size exceeded”错误,所以要确保递归调用是条件性的 (例如使用一个最终会得到 false 的 v-if)。</p><h4 id="组件之间的循环引用">组件之间的循环引用</h4><p>有时,在去构建一些组件时,会出现组件互为对方的后代/祖先:</p><p>此时,我们使用的是全局注册组件,并不会出现悖论,但是如果使用的为局部组件就会出现悖论。</p><p>但是即使用了全局注册组件,在使用webpack去导入组件时,也会出现一个错误:Failed to mount component: template or render function not defined。</p><p>模块系统发现它需要 A,但是首先 A 依赖 B,但是 B 又依赖 A,但是 A 又依赖 B,如此往复。这变成了一个循环,不知道如何不经过其中一个组件而完全解析出另一个组件。为了解决这个问题,我们需要给模块系统一个点:“A 反正是需要 B 的,但是我们不需要先解析 B。”</p><p>或者,在本地注册组件的时候,你可以使用 webpack 的异步 import:</p><h4 id="内联模板">内联模板</h4><p>在使用组件时,写上特殊的特性:inline-template,就可以直接将里面的内容作为模板而不是被分发的内容(插槽)。</p><p>不过,inline-template 会让模板的作用域变得更加难以理解。所以作为**实践,请在组件内优先选择 template 选项或 .vue 文件里的一个 元素来定义模板。</p><h4 id="x-template">X-Template</h4><p>另一个定义模板的方式是在一个 元素中,并为其带上 text/x-template 的类型,然后通过一个 id 将模板引用过去。例如:</p><p>这些可以用于模板特别大的 demo 或极小型的应用,但是其它情况下请避免使用,因为这会将模板和该组件的其它定义分离开。</p><h4 id="强制更新">强制更新</h4><p>当 更改了某个数据,页面未重新渲染时,可以调用 \)forceUpdate 来做一次强制更新。
但是在做强制更新前,需要留意数组或对象的变更检测注意事项,99.9%的情况,都是在某个地方做错了事,如果做了上述检查,仍未发现问题,那么可以通过 \(forceUpdate来更新。</p><h4 id="通过v-once创建低开销的静态组件">通过v-once创建低开销的静态组件</h4><p>渲染普通的 HTML 元素在 Vue 中是非常快速的,但有的时候你可能有一个组件,这个组件包含了大量静态内容。在这种情况下,你可以在根元素上添加 v-once 特性以确保这些内容只计算一次然后缓存起来,就像这样:</p><p>试着不要过度使用这个模式。当你需要渲染大量静态内容时,极少数的情况下它会给你带来便利,除非你非常留意渲染变慢了,不然它完全是没有必要的——再加上它在后期会带来很多困惑。例如,设想另一个开发者并不熟悉 v-once 或漏看了它在模板中,他们可能会花很多个小时去找出模板为什么无法正确更新。</p><p>父组件传递数据给子组件时,可以通过特性传递。</p><p>推荐使用这种方式进行父->子通信。</p><p>子组件传递数据给父组件时,触发事件,从而抛出数据。</p><p>推荐使用这种方式进行子->父通信。</p><h4 id="v-model">v-model</h4><h4 id="sync">.sync</h4><p>祖先组件传递数据给子孙组件时,可以利用\)attrs传递。
demo或小型项目可以使用\(attrs进行数据传递,中大型项目不推荐,数据流会变的难于理解。</p><p>\)attrs的真正目的是撰写基础组件,将非Prop特性赋予某些DOM元素。
可以在子孙组件中执行祖先组件的函数,从而实现数据传递。
demo或小型项目可以使用\(listeners进行数据传递,中大型项目不推荐,数据流会变的难于理解。</p><p>\)listeners的真正目的是将所有的事件监听器指向这个组件的某个特定的子元素。
可以在子组件中访问根实例的数据。
对于 demo 或非常小型的有少量组件的应用来说这是很方便的。中大型项目不适用。会使应用难于调试和理解。
可以在子组件中访问父实例的数据。
对于 demo 或非常小型的有少量组件的应用来说这是很方便的。中大型项目不适用。会使应用难于调试和理解。
可以在父组件中访问子实例的数据。
对于 demo 或非常小型的有少量组件的应用来说这是很方便的。中大型项目不适用。会使应用难于调试和理解。
可以在父组件中访问子实例的数据。
\(refs 只会在组件渲染完成之后生效,并且它们不是响应式的,适用于demo或小型项目。</p><p>祖先组件提供数据(provide),子孙组件按需注入(inject)。</p><p>会将组件的阻止方式,耦合在一起,从而使组件重构困难,难以维护。不推荐在中大型项目中使用,适用于一些小组件的编写。</p><p>非父子组件通信时,可以使用这种方法,但仅针对于小型项目。中大型项目使用时,会造成代码混乱不易维护。</p><p>状态管理,中大型项目时强烈推荐使用此种方式,日后再学~</p><p>混入 (mixin) 提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。 一个混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被“混合”进入该组件本身的选项。</p><p>当组件和混入对象含有同名选项时,这些选项会以恰当的方式进行“合并”。</p><p>合并数据,以组件数据优先:</p><p>合并钩子函数,将合并为一个数组。先调用混入对象的钩子,再调用组件自身钩子。</p><p>合并值为对象的选项,如 methods、components 等,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对。</p><p>混入也可以进行全局注册。使用时格外小心!一旦使用全局混入,它将影响每一个之后创建的 Vue 实例。使用恰当时,这可以用来为自定义选项注入处理逻辑。</p><p>谨慎使用全局混入,因为它会影响每个单独创建的 Vue 实例 (包括第三方组件)。大多数情况下,只应当应用于自定义选项。</p><p>我们可以自己写一个自定义指令去操作DOM元素,以达到代码复用的目的。注意,在 Vue 中,代码复用和抽象的主要形式是组件。然而,有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。</p><p>全局注册指令:</p><p>局部注册指令</p><p>使用:</p><p>例如,写一个自动聚焦的输入框:</p><p>此时,在input元素上使用 v-focus 指令就可以实现自动聚焦了。</p><p>自定义指令对象提供了钩子函数供我们使用,这些钩子函数都为可选。</p><h4 id="bind">bind</h4><p>只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。</p><h4 id="inserted">inserted</h4><p>被绑定元素插入父节点时调用(仅保证父节点存在,但不一定已**入文档中)。</p><h4 id="update">update</h4><p>所在组件的 VNode 更新时调用,<strong>但是可能发生在其子 VNode 更新之前</strong>。</p><h4 id="componentupdated">componentUpdated</h4><p>指令所在组件的 VNode <strong>及其子 VNode</strong> 全部更新后调用。</p><h4 id="unbind">unbind</h4><p>只调用一次,指令与元素解绑时调用(被绑定的Dom元素被Vue移除)。</p><ul><li><p>el: 指令所绑定的元素,可以用来直接操作DOM。</p></li><li><p>binding:对象,包含以下属性:</p></li><li><p>name:指令名,不包括 v- 前缀。</p></li><li><p>value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。</p></li><li><p>oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。</p></li><li><p>expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。</p></li><li><p>arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。</p></li><li><p>modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。</p></li><li><p>vnode:Vue 编译生成的虚拟节点。</p></li><li><p>oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。</p></li></ul><h4 id="模拟-v-show">模拟 v-show</h4><h4 id="模拟-v-model">模拟 v-model</h4><h4 id="写一个-v-slice截取文本框">写一个 v-slice(截取文本框)</h4><h4 id="动态指令参数">动态指令参数</h4><p>指令的参数可以是动态的。如:,参数可以根据组件实例数据进行更新。<br/>重写 v-slice</p><p>当想在 bind 和 update 中触发相同行为,而不关心其他钩子时,可以写成函数的形式:</p><p>如果自定义指令需要多个值,可以传入一个 JS 对象字面量。指令函数能够接受所有合法的 JS 表达式。</p><p>自定义过滤器,用于一些常见的文本格式化。</p><p>过滤器可用在两个地方:双花括号插值 和 v-bind 表达式,添加在JS表达式的尾部,由“管道”符号表示:</p><p>全局过滤器:</p><p>局部过滤器:</p><p>当过滤器形式为 时,filter过滤器接收一个参数,参数为。</p><p>当过滤器形式为 时,filter过滤器接收两个参数,参数为</p><p>在这个例子中,filterA的参数为,filterB的参数为filterA。</p><h4 id="首字母大写">首字母大写</h4><h4 id="数字中间加上逗号">数字中间加上逗号</h4><h4 id="数字添加文字万">数字添加文字“万”</h4><p>node 版本要求: >8.9,推荐使用8.11.0 +。</p><p>关于旧版本: 如果在这之前已经全局安装了旧版本的vue-cli(1.x 或 2.x),那么需要先卸载掉。 运行: 或 。</p><p>安装:</p><p>安装之后,可以在命令行中访问vue命令。</p><p>检查版本是否正确:</p><p>安装:</p><p>名字:Vetur。用于高亮.vue文件代码</p><p>数据:</p><p>拉取 2.x 模板 (旧版本)</p><p>当我们需要使用JavaScript的编程能力时,可以利用渲染函数。渲染函数比模板更接近于编译器。</p><p>例如,我们想要生成一些标题:</p><p>如果,我们按照之前的方式,那么模板内将会十分冗余。如果此时利用渲染函数,那么代码写起来将会简洁很多。</p><p>在深入渲染函数之前,先来了解一些浏览器的工作原理。例如,下面这段HTML:</p><p>当浏览器读到这些代码时,它会建立一个<strong>DOM节点树</strong> 来保持追踪所有内容,如同你会画一张家谱树来追踪家庭成员的发展一样。 以上HTML对应的DOM节点树如下图所示: </p><p><img src="http://img.saoniuhuo.com/images//.jpg" alt=""/></p><p>每个元素都是一个节点。每段文字也是一个节点。甚至注释也都是节点。一个节点就是页面的一个部分。就像家谱树一样,每个节点都可以有孩子节点。</p><p>高效地更新所有这些节点是比较困难的,不过幸运的是,我们不需要手动完成这个工作。只需要告诉Vue希望页面上的HTML是什么,例如在模板中:</p><p>或者是在一个渲染函数中:</p><p>在这两种情况下,Vue 都会自动保持页面的更新,即便 blogTitle 发生了改变。</p><h4 id="虚拟dom">虚拟DOM</h4><p>Vue通过建立一个<strong>虚拟DOM</strong>来追踪自己要如何改变真实DOM。例如:</p><p>createElement 会返回什么呢? 它不会返回一个实际的DOM元素。更准确的名字可能是:,因为它所包含的信息会告诉Vue页面上需要渲染什么样的节点,包括其子节点的描述信息。我们把这样的节点描述为“虚拟节点(virtual node)”,也常简写它为“VNode”。“虚拟DOM”是我们对由Vue组件树建立起来的整个VNode树的称呼。</p><p>createElement接收的参数:</p><h4 id="深入数据对象">深入数据对象</h4><h4 id="v-if-和-v-for">v-if 和 v-for</h4><p>只要在原生的 JavaScript 中可以轻松完成的操作,Vue 的渲染函数就不会提供专有的替代方法。比如,在模板中使用的 v-if 和 v-for:</p><p>这些都可以在渲染函数中用 JavaScript 的 if/else 和 map 来重写:</p><h4 id="v-model-1">v-model</h4><p>渲染函数中没有与v-model的直接对应---必须自己实现相应的逻辑:</p><h4 id="事件按键修饰符">事件&按键修饰符</h4><p>对于 .passive、.capture 和 .once 这些事件修饰符, Vue 提供了相应的前缀可以用于 on:</p><div><thead><tr><th>修饰符</th><th>前缀</th></tr></thead><tbody><tr><td>.passive</td><td>&</td></tr><tr><td>.capture</td><td>!</td></tr><tr><td>.once</td><td>~</td></tr><tr><td>.capture.once 或 .once.capture</td><td>~!</td></tr></tbody></div><p>例如:</p><p>对于所有其它的修饰符,私有前缀都不是必须的,因为你可以在事件处理函数中使用事件方法:</p><div><thead><tr><th>修饰符</th><th>处理函数中的等价操作</th></tr></thead><tbody><tr><td>.stop</td><td>event.stopPropagation()</td></tr><tr><td>.prevent</td><td>event.preventDefault()</td></tr><tr><td>.self</td><td>if (event.target !== event.currentTarget) return</td></tr><tr><td>按键:.enter, .13</td><td>if (event.keyCode !== 13) return </td></tr><tr><td>对于别的按键修饰符来说,可将 13 改为另一个按键码</td></tr><tr><td>修饰键:.ctrl, .alt, .shift, .meta</td><td>if (!event.ctrlKey) return (将 ctrlKey 分别修改为 altKey、shiftKey 或者 metaKey)</td></tr></tbody></div><h4 id="插槽">插槽</h4><p>可以通过 this.\)slots 访问静态插槽的内容,每个插槽都是一个 VNode 数组:
也可以通过 this.\(scopedSlots 访问作用域插槽,每个作用域插槽都是一个返回若干 VNode 的函数:</p><p>如果要用渲染函数向子组件中传递作用域插槽,可以利用 VNode 数据对象中的 scopedSlots 字段:</p><p>在Vue中使用JSX语法。可以让我们回到更接近模板的语法上。</p><p>在JSX中,一些指令并不存在,所以我们可以换一种方式来处理。</p><h4 id="v-text-1">v-text</h4><h4 id="v-html-1">v-html</h4><h4 id="v-show-1">v-show</h4><p>jsx支持v-show指令:</p><h4 id="v-if-1">v-if</h4><h4 id="v-for">v-for</h4><h4 id="v-on">v-on</h4><h4 id="v-bind">v-bind</h4><p>在JSX中可以直接使用class="xx"来指定样式类,内联样式可以直接写成style="xxx"</p><h4 id="v-model-2">v-model</h4><p>有相应的插件 支持 v-model,所以可以直接使用:</p><h4 id="v-slot">v-slot</h4><h4 id="v-pre-1">v-pre</h4><h4 id="v-cloak-1">v-cloak</h4><h4 id="v-once-1">v-once</h4><p>以上三个指令,不常用,无替代方案</p><p>当遍历元素或组件时,如:</p><p>会发现从 this.\)refs.xxx 中获取的并不是期望的数组值,此时就需要将refInFor属性设置为true了:
模板写法:
JSX写法:

作用域插槽: 模板写法:
JSX写法:
当一个组件不需要状态(即响应式数据)、不需要任何生命周期场景、只接受一些props来显示组件时,我们可以将其标记为函数式组件。
因为函数式组件只是函数,所以渲染开销会低很多。
在 2.3.0 之前的版本中,如果一个函数式组件想要接收 prop,则 props 选项是必须的。在 2.3.0 或以上的版本中,你可以省略 props 选项,所有组件上的 attribute 都会被自动隐式解析为 prop。
为了弥补缺少的实例,render 函数提供第二个参数context作为上下文。context包括如下字段:
- props:提供所有 prop 的对象
- slots: 一个函数,返回了包含所有插槽(非作用域)的对象
- scopedSlots: (2.6.0+) 一个暴露传入的作用域插槽的对象。也以函数形式暴露普通插槽。
- data:传递给组件的整个数据对象,作为 createElement 的第二个参数传入组件
- parent:对父组件的引用
- listeners: (2.3.0+) 一个包含了所有父组件为当前组件注册的事件监听器的对象。这是 data.on 的一个别名。
- injections: (2.3.0+) 如果使用了 inject 选项,则该对象包含了应当被注入的属性。
- children: VNode 子节点的数组,包含了所有的非作用域插槽和非具名插槽。
示例1:
slots()的结果为:
children的结果为:
示例2:
slots()的结果为:
children的结果为:
在 2.5.0 及以上版本中,如果你使用了单文件组件,那么基于模板的函数式组件可以这样声明:
Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。
Vue 提供了 transition 的封装组件,在下列情形中,可以给任何元素和组件添加进入/离开过渡
- 条件渲染 (使用 v-if)
- 条件展示 (使用 v-show)
- 动态组件
- 组件根节点
在进入/离开的过渡中,会有 6 个 class 切换。
v-enter: 定义进入过渡的开始状态。 在元素**入之前生效,在元素**入之后的下一帧移除。
1.
v-enter-active: 定义进入过渡生效时的状态。 在整个进入过渡的阶段中应用,在元素**入之前生效,在过渡/动画完成之后移除。 这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
1.
v-enter-to: 定义进入过渡的结束状态(2.1.8+) 。 在元素**入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。v-leave: 定义离开过渡的开始状态。 在离开过渡被触发时立刻生效,下一帧被移除。
1.
v-leave-active: 定义离开过渡生效时的状态。 在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。 这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
1.
v-leave-to: 定义离开过渡的结束状态(2.1.8+) 。 在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。图示:

transition 无 name 特性 类名前缀为 v-。
1.
transition 有 name 特性 如 name 为 fade,则类名前缀为fade-。CSS 动画用法同 CSS 过渡,区别是在动画中 v-enter 类名在节点插入 DOM 后不会立即删除,而是在 animationend 事件触发时删除。
我们可以通过以下 attribute 来自定义过渡类名:
- enter-class
- enter-active-class
- enter-to-class (2.1.8+)
- leave-class
- leave-active-class
- leave-to-class (2.1.8+)
他们的优先级高于普通的类名,这对于 Vue 的过渡系统和其他第三方 CSS 动画库(如 Animate.css)结合使用十分有用。
Animate.css 官网地址:Redirecting to Animate.css 安装方式:
可使用 type 属性,来声明需要 Vue 监听的类型,type值可为 animation 或 transition 。
当不设置type时,默认会取 transitioned 和 animationed 两者更长的为结束时刻。
在一些情况下,Vue可以自动得出过渡效果的完成时机,从而对dom进行处理。
但是有些时候,我们会设置一系列的过渡效果,例如嵌套元素也有过渡动效,其过渡效果的时间长于父元素。此时我们可以设置duration属性,定制一个显性的过渡持续时间(以毫秒记):
也可以定制进入和移出的持续时间:
可以通过 attribute 设置节点在初始渲染的过渡。
和进入/离开过渡一样,同样也可以自定义 CSS 类名。如:
可以在属性中声明 JavaScript 钩子:
- before-enter 动画入场前,可以在其中设置元素开始动画之前的起始样式
- enter 动画入场中,可以在其中写动画
- after-enter 动画完成后
- enter-cancelled 取消动画
对于仅使用 JavaScript 过渡的元素添加 v-bind:css="false",Vue 会跳过 CSS 的检测。这也可以避免过渡过程中 CSS 的影响。
设置了 appear 特性的 transition 组件,也存在自定义 JavaScript 钩子:
结合 Velocity.js
Velocity.js 官网地址:Velocity.js 安装方式:
当切换展示的元素标签名相同时,需要给每一个元素设置不同的key值,否则Vue为了效率只会替换相同标签内部的内容。
在一些场景中,可以通过给同一个元素的key值设置不同的状态来替代 v-if 和 v-else。如:
Vue提供一个一个 mode 特性,可以给多个元素过渡应用不同的模式,mode 的值可为:
- in-out:新元素先进行过渡,完成之后当前元素过渡离开。
- out-in:当前元素先进行过渡,完成之后新元素过渡进入。
我们可以使用动态组件切换展示不同的组件。
当想要给一个列表添加过渡动效时,我们可以使用 组件。
该组件的特点:
- 不同于 <transition>,它会以一个真实元素呈现:默认为一个 。你也可以通过 tag attribute 更换为其他元素。
- 过渡模式不可用,因为我们不再相互切换特有的元素。
- 内部元素 总是需要 提供唯一的 key 属性值。
- CSS 过渡的类将会应用在内部的元素中,而不是这个组/容器本身。
组件提供了一个新的特性:v-move,它会在元素改变定位的过程中应用。 如何使用?通过类名即可设置:.v-move {}。 当给 设置 name 特性时,例如name为fade,则 v-move 在使用时,需要替换为 fade-move。
注意:当移除一个列表元素时,需要将移除的元素脱离文档流,否则,要溢出的元素在移除过渡中一直处于文档流中,会影响到后面元素的move过渡效果。
内部的实现:Vue 使用了一个叫 FLIP 简单的动画队列,使用 transforms 将元素从之前的位置平滑过渡新的位置。
需要注意的是使用 FLIP 过渡的元素不能设置为 display: inline 。作为替代方案,可以设置为 display: inline-block 或者放置于 flex 中。
如果要给列表中的元素,应用更丰富的过渡效果,可以配合JavaScript钩子。
过渡可以通过 Vue 的组件系统实现复用。要创建一个可复用过渡组件,你需要做的就是将 <transition> 或者 <transition-group> 作为根组件,然后将任何子组件放置在其中就可以了。
注意:当使用函数式组件复用过渡时,不要设置css作用域。
在项目中,有些组件不会在第一次进入首屏时加载,而是当执行了某些操作时,才会加载进来,所以此时,我们可以将该组件设置成异步加载,什么时候用,什么时候再加载进来,以达到提升首屏性能的目的。
使用方法:
将多个需要同时加载的组件合并到一个文件中:
异步加载的文件,会在link标签上设置 el="prefech"。浏览器会在空闲时间内下载对应的资源,使用时可以直接从缓存中获取。与之对应的 el="preload",会及时下载对应的资源。
路由是根据不同的url地址展现不同的内容或页面。 早期的路由都是后端直接根据url来重载页面实现的,即后端控制路由。 后来页面越来越复杂,服务器压力越来越大,随着ajax(异步刷新技术)的出现,页面的实现非重载就能刷新数据,让前端也可以控制url自行管理,前端路由由此而生。
前端路由更多用在单页应用上,也就是SPA(Single Page Web Application),在单页面应用中,大部分页面结果不变,只改变部分内容的使用。
安装:。
JavaScript
- 引入路由
- 使用路由
- 定义路由组件
- 定义路由
- 创建 router 实例,然后传 配置
- 创建和挂载根实例
html
- router-link-exact-active 当前展示路径完全匹配组件to属性的值
- router-link-active 当前展示路径包含to属性的值
更改class名
vue-router 默认 hash 模式 —— 使用 URL 的 hash 来模拟一个完整的 URL,于是当 URL 改变时,页面不会重新加载。
如果不想要很丑的 hash,我们可以用路由的 history 模式,这种模式充分利用 history.pushState API 来完成 URL 跳转而无须重新加载页面。 在路由配置中设置:
当你使用 history 模式时,URL 就像正常的 url,例如 http://yoursite.com/user/id, 也好看!
不过这种模式要玩好,还需要后台配置支持。因为我们的应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问 OURSITE.COM 就会返回 404,这就不好看了。
所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。
可以通过一个名称标识一个路由,这样在某些时候会显得更方便一些,特别是在链接一个路由,或者是执行一些跳转时,可以在创建Router实例时,在routes配置中给某个路由设置名称:
要链接到一个命名路由,可以给 的 to 属性传一个对象:
一个被 router-view 渲染的组件想要包含自己的嵌套 router-view 时,可以使用嵌套路由,如:
经过这样的设置,在 Activity 组件中就可以使用 router-view 了。 子路由的path可以简写:
这样会自动将父路由的路径,拼接在子路由前,最终结果为:/activity/personal。
当访问 /activity 下的其他路径时,并不会渲染出来任何东西,如果想要渲染点什么,可以提供一个空路由:
重定向也是通过 routes 配置来完成,下面例子是从 /a 重定向到 /b
重定向的目标也可以是一个命名的路由:
甚至是一个方法,动态返回重定向目标:
“重定向”的意思是,当用户访问 /a时,URL 将会被替换成 /b,然后匹配路由为 /b,那么“别名”又是什么呢?
/a 的别名是 /b,意味着,当用户访问 /b 时,URL 会保持为 /b,但是路由匹配则为 /a,就像用户访问 /a 一样。
上面对应的路由配置为:
通过在 Vue 根实例的 router 配置传入 router 实例,\(router、 \)route 两个属性会被注入到每个子组件。
路由实例对象。
除了使用 创建 a 标签来定义导航链接,我们还可以借助 router 的实例 方法,通过编写代码来实现。
\(router.push</h4><p>想要导航到不同的 URL,则使用 router.push 方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,则回到之前的 URL。</p><p>当你点击 时,这个方法会在内部调用,所以说,点击 等同于调用 \)router.push(…)。
声明式编程式this. \(router.push(...)</td></tr></tbody></div><p>该方法的参数可以是一个字符串路径,或者一个描述地址的对象。例如:</p><h4 id="routerreplace">\)router.replace跟 router.push 很像,唯一的不同就是,它不会向 history 添加新记录,而是替换掉当前的 history 记录。
声明式编程式this. \(router.replace(...)</td></tr></tbody></div><h4 id="routergon">\)router.go(n)这个方法的参数是一个整数,意思是在 history 记录中向前或者后退多少步,类似 window.history.go(n)。
只读,路由信息对象。
\(route.path</h4><p>字符串,对应当前路由的路径,总是解析为绝对路径,如 "/foo/bar"。</p><h4 id="routeparams">\)route.params
一个 key/value 对象,包含了动态片段和全匹配片段,如果没有路由参数,就是一个空对象。
\(route.query</h4><p>一个 key/value 对象,表示 URL 查询参数。例如,对于路径 /foo?user=1,则有 \)route.query.user == 1,如果没有查询参数,则是个空对象。
\(route.hash</h4><p>路由的 hash 值 (带 /#) ,如果没有 hash 值,则为空字符串。</p><h4 id="routefullpath">\)route.fullPath
完成解析后的 URL,包含查询参数和 hash 的完整路径。
\(route.matched</h4><p>一个数组,包含当前路由的所有嵌套路径片段的路由记录 。路由记录就是 routes 配置数组中的对象副本 (还有在 children 数组)。 </p><h4 id="routename">\)route.name
当前路由的名称,如果有的话
\(route.redirectedFrom</h4><p>如果存在重定向,即为重定向来源的路由的名字。</p><p>当我们需要把某种模式匹配到的所有路由,全都映射到同个组件。例如,我们有一个 User 组件,对于所有 ID 各不相同的用户,都要使用这个组件来渲染。那么,我们可以在 vue-router 的路由路径中使用“动态路径参数”来达到这个效果:</p><p>经过这样的设置,像 /user/foo 和 /user/bar 都将映射到相同的路由。</p><p>一个“路径参数”使用冒号 : 标记。当匹配到一个路由时,参数值会被设置到 this.\)route.params,可以在每个组件内使用。
想同时展示多个视图时,并且每个视图展示不同的组件时,可以使用命名视图。
可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果 router-view 没有设置名字,那么默认为 default。
一个视图使用一个组件渲染,因此对于同个路由,多个视图就需要多个组件。确保正确使用 components 配置 (带上 s):
在组件中使用 \(route 会使之与其对应路由形成高度耦合,从而使组件只能在某些特定的 URL 上使用,限制了其灵活性。</p><p>使用 props 将组件和路由解耦。</p><h4 id="布尔模式">布尔模式</h4><p>如果 props 被设置为 true,route.params 将会被设置为组件属性。</p><h4 id="对象模式">对象模式</h4><p>如果 props 是一个对象,它会被按原样设置为组件属性。当 props 是静态的时候有用。</p><h4 id="函数模式">函数模式</h4><p>你可以创建一个函数返回 props。函数的第一个参数是 route (即\)route)。
导航:路由正在发生变化。
导航守卫主要用来通过跳转或取消的方式守卫导航。
导航守卫被分成三种:全局的、单个路由独享的、组件内的。
是指路由实例上直接操作的钩子函数,触发路由就会触发这些钩子函数。
全局前置守卫 beforeEach
在路由跳转前触发,一般被用于登录验证。
参数说明:
- to 目标路由对象
- from 即将要离开的路由对象
- next 三个参数中最重要的参数。
- 必须调用next(),才能继续往下执行一个钩子,否则路由跳转会停止
- 若要中断当前的导航,可以调用next(false)。
- 可以使用next跳转到一个不同的地址。终端当前导航,进入一个新的导航。next参数值和\(routet.push一致。</p></li><li><p>next(error)。2.4+,如果传入的参数是一个Error实例,则导航会被终止,且该错误会被传递给router.onError() 注册过的回调。</p></li></ul><h4 id="全局解析守卫-beforeresolve">全局解析守卫 beforeResolve</h4><p>和boforeEach类似,路由跳转前触发。</p><p>和beforeEach的区别:在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。</p><h4 id="全局后置钩子-aftereach">全局后置钩子 afterEach</h4><p>和beforeEach相反,路由跳转完成后触发。</p><p>是指在单个路由配置的时候也可以设置的钩子函数。</p><h4 id="beforeenter">beforeEnter</h4><p>和beforeEach完全相同,如果都设置则在beforeEach之后紧随执行。</p><p>是指在组件内执行的钩子函数,类似于组件内的生命周期,相当于为配置路由的组件添加的生命周期钩子函数。</p><h4 id="beforerouteenter">beforeRouteEnter</h4><p>路由进入之前调用。</p><p>在该守卫内访问不到组件的实例,this值为undefined。在这个钩子函数中,可以通过传一个回调给 next来访问组件实例。在导航被确认的时候执行回调,并且把组件实例作为回调方法的参数,可以在这个守卫中请求服务端获取数据,当成功获取并能进入路由时,调用next并在回调中通过 vm访问组件实例进行赋值等操作,(next中函数的调用在mounted之后:为了确保能对组件实例的完整访问)。</p><h4 id="beforerouteupdate">beforeRouteUpdate</h4><p>在当前路由改变时,并且该组件被复用时调用,可以通过this访问实例。</p><p>何时组件会被复用?</p><ul><li>动态路由间互相跳转</li><li>路由query变更</li></ul><h4 id="beforerouteleave">beforeRouteLeave</h4><p>导航离开该组件的对应路由时调用,可以访问组件实例this。</p><ol><li>导航被触发。</li><li>在失活的组件里调用离开守卫。</li><li>调用全局的 beforeEach 守卫。</li><li>在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。</li><li>在路由配置里调用 beforeEnter。</li><li>解析异步路由组件。</li><li>在被激活的组件里调用 beforeRouteEnter。</li><li>调用全局的 beforeResolve 守卫 (2.5+)。</li><li>导航被确认。</li><li>调用全局的 afterEach 钩子。</li><li>触发 DOM 更新。</li><li>用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。</li></ol><p>定义路由的时候可以配置 meta 字段,用于自定义一些信息。</p><p><router-view> 是基本的动态组件,所以我们可以用 <transition> 组件给它添加一些过渡效果。</p><p>使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。vue-router 可以自定义路由切换时页面如何滚动。</p><p>注意: 这个功能只在支持 history.pushState 的浏览器中可用。</p><p>当创建一个 Router 实例,你可以提供一个 scrollBehavior 方法:</p><p>scrollBehavior 方法接收 to 和 from 路由对象。第三个参数 savedPosition 当且仅当 popstate 导航 (通过浏览器的 前进/后退 按钮触发) 时才可用。</p><p>scrollBehavior 返回滚动位置的对象信息,长这样:</p><ul><li>{ x: number, y: number }</li><li>{ selector: string, offset? : { x: number, y: number }} (offset 只在 2.6.0+ 支持)</li></ul><p>Vuex是vue的状态管理工具,为了更方便的实现多个组件共享状态。</p><p>单一状态树,使用一个对象就包含了全部的应用层级状态。</p><h4 id="在vue组件中获得vuex状态">在Vue组件中获得Vuex状态</h4><p>Vuex 通过store 选项,提供了一种机制将状态从跟组件“注入”到每一个子组件中(调用Vue.use(Vuex))。</p><p>通过在根实例中注册store选项,该store实例会注入到根组件下的所有子组件中,且子组件能通过this.\)store访问。
mapState 辅助函数
当一个组件需要获取多个状态时,将这些状态都声明为计算属性会有些重复和冗余。为了解决这个问题,我们可以使用mapState辅助函数帮助我们生成计算属性:
使用不同的名字:
store的计算属性。getter的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算。
Getter 接收state作为其第一个参数、getters作为其第二个参数。
Getter会暴露为store.getters对象:
也可以让getter返回一个函数,来实现给getter传参
如果你想将一个 getter 属性另取一个名字,使用对象形式:
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。
不能直接调用一个mutation handler。这个选项更像是事件注册:“当触发一个类型为的mutation时,调用次函数。”:
除了在组件中使用 提交 mutation之外,还可以使用 mapMutations 辅助函数:
你可以向store.commit传入额外的参数,即mutation的载荷(payload):
在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的mutation会更易读:
提交 mutation 的另一种方式是直接使用包含 type 属性的对象:
当使用对象风格的提交方式,整个对象都作为载荷传给 mutation 函数,因此 handler 保持不变:
把这些常量放在单独的文件中可以让你的代码合作者对整个 app 包含的 mutation 一目了然:
用不用常量取决于自己,在需要多人协作的大型项目中,这会很有帮助。
既然 Vuex 的 store 中的状态是响应式的,那么当我们变更状态时,监视状态的 Vue 组件也会自动更新。这也意味着 Vuex 中的 mutation 也需要与使用 Vue 一样遵守一些注意事项:
- 最好提前在你的 store 中初始化好所有所需属性。
- 当需要在对象上添加新属性时,你应该
- 使用 Vue.set(obj, ‘newProp’, 123), 或者
- 以新对象替换老对象。例如,利用对象展开运算符我们可以这样写:
在Vuex的state上使用v-model时,由于会直接更改state的值,所以Vue会抛出错误。
如果想要使用双向数据的功能,就需要自己模拟一个v-model: :value="msg" @input="updateMsg"。
双向绑定的计算属性
上面的做法,比v-model本身繁琐很多,所以我们还可以使用计算属性的setter来实现双向绑定:
要记住 mutation 必须是同步函数。why?
执行上端代码,我们会发现更改state的操作是在回调函数中执行的,这样会让我们的代码在devtools中变的不好调试:当 mutation 触发的时候,回调函数还没有被调用,devtools 不知道什么时候回调函数实际上被调用,任何在回调函数中进行的状态的改变都是不可追踪的。
开启严格模式,仅需在创建 store 的时候传入 strict: true:
在严格模式下,无论何时发生了状态变更且不是由 mutation 函数引起的,将会抛出错误。这能保证所有的状态变更都能被调试工具跟踪到。
开发环境与发布环境
不要在发布环境下启用严格模式!严格模式会深度监测状态树来检测不合规的状态变更,要确保在发布环境下关闭严格模式,以避免性能损失。
Action 类似于 mutation,不同在于:
- Action 提交的是 mutation,而不是直接变更状态。
- Action 可以包含任意异步操作
Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.state 和 context.getters 来获取 state 和 getters:
虽然和mutation差不多,但是在action中,可以执行异步操作,但是mutation中不行!!!
Action 通常是异步的,那么如何知道 action 什么时候结束呢?

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。
为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter。
- 获取 state:this.\(store.state.moduleName.xxx</li><li>获取 getter:this.\)store.getters.xxx
- 提交 mutation:this.\(store.commit('xxx');</li><li>分发 action:this.\)store.dispatch(‘xxx’);
- 可以通过mapXXX的方式拿到getters、mutations、actions,但是不能拿到state,如果想通过这种方式获得state,需要加命名空间。
可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。
- 获取 state:this.\(store.state.moduleName.xxx</li><li>获取 getter:this.\)store.[‘moduleName/getters’].xxx
- 提交 mutation:this.\(store.commit('moduleName/xxx');</li><li>分发 action:this.\)store.dispatch(‘moduleName/xxx’);
- 可以通过mapXXX的方式获取到state、getters、mutations、actions。
对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象。
同样,对于模块内部的 action,局部状态通过 context.state 暴露出来,根节点状态则为 context.rootState。
对于模块内部的 getter,根节点状态会作为第三个参数暴露出来。




版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/144189.html