概述
Vue 2
所有的 Vue 组件都是 Vue 实例,并且接受相同的选项对象 (一些根实例特有的选项除外)。
值得注意的是只有当实例被创建时就已经存在于 data
中的 property 才是响应式的。也就是说如果你添加一个新的 property,那么他不是响应的。
如果你知道你会在晚些时候需要一个 property,但是一开始它为空或不存在,那么你仅需要设置一些初始值。
这里唯一的例外是使用 Object.freeze()
,这会阻止修改现有的 property,也意味着响应系统无法再追踪变化。
v-bind
可以直接绑定一个对象
<div v-bind='info'></div>
data(){
return {
info:{
name:'zs',
age:18
}
}
}
===>编译成
<div name='zs' age=18>
</div>
v-if
false:隐藏
true:显示
v-show
false:隐藏
true:显示
强制更新视图
this.$forceUpdate()
动态参数
从2.6.0开始有动态参数,使用方括号括起来
<a v-bind:[attributeName]="url"> ... </a>
<a v-on:[eventName]="doSomething"> ... </a>
这里的 attributeName
会被作为一个 JavaScript 表达式进行动态求值,求得的值将会作为最终的参数来使用。例如,如果你的 Vue 实例有一个 data
property attributeName
,其值为 "href"
,那么这个绑定将等价于 v-bind:href
。就是说这里的 attributeName
可以放在data中转为参数
计算属性VS方法
可能你会发现计算属性和方法都可以同时做到某些事情。如:
methods: {
reversedMessage: function () {
return this.message.split('').reverse().join('')
}
}
computed: {
// 计算属性的 getter
reversedMessage: function () {
// `this` 指向 vm 实例
return this.message.split('').reverse().join('')
}
}
但是我们这里最好使用计算属性,因为如果里面的this.message没有发生改变,那么多次调用计算属性,它还是
返回之前计算过的结果,但是如果使用的是方法,那么方法返回从新调用,从新计算里面的值
也就是说,计算属性会缓存,方法不会
计算属性传递参数
<view v-for="(item,index) in tabbarList" :key="index">
<image :src="computeSrc(index,item.selectedIconPath,item.iconPath)" mode="widthFix"></image>
</view>
computed: {
computeSrc() {
return function(index,selectedIconPath,iconPath) {
const src = index === this.currentIndex ? selectedIconPath : iconPath;
return src;
}
}
},
过滤器:filters
使用:
<template>
<div>{{xxx | filter_data}}</div>那么这个标签最终会显示成<div>11</div>
</template>
<script>
export default {
filters:{
filter_data(data){
console.log(data);//这个参数就是xxx
return 11;
}
}
}
</script>
侦听器:watch
watch:监听组件实例身上的属性值的变化
watch:当需要在数据变化时执行异步或开销较大的操作时,这个方式是最有用的。
一般监听的数据是data中的或props
还可以用vue实例.$watch(a,{…})
监听对象数组的话,我们一般很少直接监听的,可以创建一个组件,然后,接着可以将数组中的对象传递进去,然后在在组件中监听item.xxx
data: {
question: '',
answer: 'I cannot give you an answer until you ask a question!',
number:{
a:1,
b:2
}
},
//监视的简写,当配置对象中只有handler的时候可以简写
//watch: {
// 如果 `question` 发生改变,这个函数就会运行(data中定义的数据)
//newQuestion:修改后的值
//oldQuestion:修改前的值
// question: function (newQuestion, oldQuestion) {
// this.answer = 'Waiting for you to stop typing...'
// this.debouncedGetAnswer()
// }
// },
//写法二
watch: {
//"变量名":{配置对象}
question:{
// 如果 `question` 发生改变,这个函数就会运行(data中定义的数据)
//newQuestion:修改后的值
//oldQuestion:修改前的值
handler(newQuestion, oldQuestion) {
this.answer = 'Waiting for you to stop typing...'
this.debouncedGetAnswer()
},
immediate:true//初始化时,让handler调用一下,上来就立即监听一下
},
//监视多级结构中某个属性的变化
'number.a':{
handler(){
}
},
number:{
deep:true,//开启深度监视
handler(){
}
}
},
侦听器:vm.$watch
用法:vm.$watch( expOrFn, callback, [options] )
- 参数:
{string | Function} expOrFn
{Function | Object} callback
{Object} [options]
{boolean} deep
{boolean} immediate
- 返回值:
{Function} unwatch
示例:
// 键路径
vm.$watch('a.b.c', function (newVal, oldVal) {
// 做点什么
})
// 函数
vm.$watch(
//复杂的表达式用函数
function () {
// 表达式 `this.a + this.b` 每次得出一个不同的结果时
// 处理函数都会被调用。
// 这就像监听一个未被定义的计算属性
return this.a + this.b
},
function (newVal, oldVal) {
// 做点什么
}
)
vm.$watch
返回一个取消观察函数,用来停止触发回调:
var unwatch = vm.$watch('a', cb)
// 之后取消观察
unwatch()
选项:deep
为了发现对象内部值的变化,可以在选项参数中指定 deep: true
。注意监听数组的变动不需要这么做。
vm.$watch('someObject', callback, {
deep: true
})
vm.someObject.nestedValue = 123
// callback is fired
选项:immediate
在选项参数中指定 immediate: true
将立即以表达式的当前值触发回调:
vm.$watch('a', callback, {
immediate: true
})
// 立即以 `a` 的当前值触发回调
注意在带有 immediate
选项时,不能在第一次回调时取消侦听给定的 property。
// 这会导致报错
var unwatch = vm.$watch(
'value',
function () {
doSomething()
unwatch()
},
{ immediate: true }
)
如果你仍然希望在回调内部调用一个取消侦听的函数,你应该先检查其函数的可用性:
var unwatch = vm.$watch(
'value',
function () {
doSomething()
if (unwatch) {
unwatch()
}
},
{ immediate: true }
)
计算属性和侦听器
computed和watch之间的区别:
- computed能完成的功能,watch都可以完成
两个重要的小原则:
- 所有被Vue管理的函数,最好写成普通函数,这样this的指向才是vm(vue实例)或组件实例对象
- 所有不被Vue所管理的函数(定时器的回调函数,ajax的回调函数等,promise的回调函数),最好写成箭头函数,这样this的指向才是vm或组件实例对象
动态绑定Class和Style
Class动态绑定的对象语法:
<div
class="static"
v-bind:class="{ active: isActive, 'text-danger': hasError }"
></div>
//'text-danger':这个加引号是因为有个-,识别不出来,需要加上单引号
data: {
isActive: true,
hasError: false
}
//结果渲染为:
<div class="static active"></div>
还可以这样写
<div v-bind:class="classObject"></div>
data: {
classObject: {
active: true,
'text-danger': false
}
}
或者使用计算属性
<div v-bind:class="classObject"></div>
data: {
isActive: true,
error: null
},
computed: {
classObject: function () {
return {
active: this.isActive && !this.error,
'text-danger': this.error && this.error.type === 'fatal'
}
}
}
Class动态绑定的数组语法:
<div v-bind:class="[activeClass, errorClass]"></div>
data: {
activeClass: 'active',
errorClass: 'text-danger'
}
如果你也想根据条件切换列表中的 class,可以用三元表达式:
<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
数组中也可以使用对象
<div v-bind:class="[{ active: isActive }, errorClass]"></div>
Style动态绑定的对象语法
三元运算符:
<div :style="r.fixBind == 1 ?{'background-color': '#F7803C','border-color':'#F7803C'}:''">
</div>
<div :style="{color:1===1?'red':'#000'}">
</div>
<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
//fontSize可以使用驼峰或者font-size,但是使用短横线分割需要使用引号括起来
data: {
activeColor: 'red',
fontSize: 30
}
直接绑定到一个样式对象通常更好,这会让模板更清晰:
<div v-bind:style="styleObject"></div>
data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
同样的,对象语法常常结合返回对象的计算属性使用。
Style动态绑定的数组语法
数组语法可以将多个样式对象应用到同一个元素上:
<div v-bind:style="[baseStyles, overridingStyles]"></div>
data: {
baseStyles: {
color: 'red',
},
overridingStyles: {
fontSize: '13px'
},
}
自动添加前缀
当 v-bind:style
使用需要添加 浏览器引擎 前缀的 CSS property 时,如 transform
,Vue.js 会自动侦测并添加相应的前缀。
多重值
2.3.0+
从 2.3.0 起你可以为 style
绑定中的 property 提供一个包含多个值的数组,常用于提供多个带前缀的值,例如:
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
这样写只会渲染数组中最后一个被浏览器支持的值。在本例中,如果浏览器支持不带浏览器前缀的 flexbox,那么就只会渲染 display: flex
。
条件渲染v-if | v-show
如果需要非常频繁地切换,则使用 v-show
较好;如果在运行时条件很少改变,则使用 v-if
较好。
v-show
不支持 <template>
元素
v-if
和v-for
可以在<template>
元素上使用
永远不要把 v-if
和 v-for
同时用在同一个元素上。
(所以这里有个小技巧,可以外层嵌套template标签,然后将v-for放到标签上)但是这样:key怎么办
当 Vue 处理指令时,v-for
比 v-if
具有更高的优先级,所以这个模板:
<ul>
<li
v-for="user in users"
v-if="user.isActive"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
将会经过如下运算:
this.users.map(function (user) {
if (user.isActive) {
return user.name
}
})
因此哪怕我们只渲染出一小部分用户的元素,也得在每次重渲染的时候遍历整个列表,不论活跃用户是否发生了变化。
通过将其更换为在如下的一个计算属性上遍历:
computed: {
activeUsers: function () {
return this.users.filter(function (user) {
return user.isActive
})
}
}
<ul>
<li
v-for="user in activeUsers"
:key="user.id"
>
{{ user.name }}
</li>
</ul>
我们将会获得如下好处:
- 过滤后的列表只会在
users
数组发生相关变化时才被重新运算,过滤更高效。 - 使用
v-for="user in activeUsers"
之后,我们在渲染的时候只遍历活跃用户,渲染更高效。 - 解耦渲染层的逻辑,可维护性 (对逻辑的更改和扩展) 更强。
列表渲染v-for
可以遍历数组和对象
数组:v-for=“(item,index) in Array”–> item为当前遍历到的元素,index为元素索引,Array是数组
对象:v-for=“(value, name,index) in object”---->value为值,name为key,index为索引,object为对象
你也可以用 of
替代 in
作为分隔符,因为它更接近 JavaScript 迭代器的语法:
<div v-for="item in items"></div>
<div v-for="item of items"></div>
建议尽可能在使用 v-for
时提供 key
不要使用对象或数组之类的非基本类型值作为 v-for
的 key
。请用字符串或数值类型的值。
v-for
也可以接受整数。在这种情况下,它会把模板重复对应次数。
<div>
<span v-for="n in 10">{{ n }} </span>
</div>
结果:1 2 3 4 5 6 7 8 9 10
ul标签中使用组件
在ul里面使用模板,因为ul里面只有li标签会被当做有效内容,所以想要在ul标签里面使用模板组件可以
<ul>
<li
is="todo-item"
v-for="(todo, index) in todos"
v-bind:key="todo.id"
v-bind:title="todo.title"
v-on:remove="todos.splice(index, 1)"
></li>
</ul>
注意这里的 is="todo-item"
attribute。这种做法在使用 DOM 模板时是十分必要的,因为在 <ul>
元素内只有 <li>
元素会被看作有效内容。这样做实现的效果与 <todo-item>
相同,但是可以避开一些潜在的浏览器解析错误。
//todo-item组件
Vue.component('todo-item', {
template: `
<li>
{{ title }}
<button v-on:click="$emit('remove')">Remove</button>
</li>
`,
props: ['title']
})
Vue.set方法
操作对象:set(给那个对象加属性/替换,属性的名字,属性的值)
操作数组:set(给那个对象加属性/替换,索引,值)
set方法不能给data加数据,只能给data里面的属性加
可以Vue.set(),也可以vm.$set()
set()方法添加的数据是响应式的
注意: 目标对象不能是一个 Vue
实例或 Vue
实例的根数据对象。
Vue.delete
vm.$delete
vm.$delete( target, propertyName/index )
-
参数:
{Object | Array} target
{string | number} propertyName/index
仅在 2.2.0+ 版本中支持 Array + index 用法。
-
用法:
删除对象的属性。如果对象是响应式的,确保删除能触发更新视图。这个方法主要用于避开
Vue
不能检测到属性被删除的限制,但是你应该很少会使用它。在 2.2.0+ 中同样支持在数组上工作。
-
注意: 目标对象不能是一个
Vue
实例或Vue
实例的根数据对象。
事件处理
事件修饰符
Vue.js 为 v-on
提供了事件修饰符。之前提过,修饰符是由点开头的指令后缀来表示的。
.stop
- 阻止事件冒泡
.prevent
- 阻止默认事件
.once
- 事件只执行一次
.capture
- 使用事件的捕获模式
.self
- 只有event.target是当前操作的元素时才触发事件
.passive
- 事件的默认行为立即执行,无需等待事件回调执行完毕
nativa
- 如果想要监听组件就必须加native
<!-- 阻止单击事件继续传播 -->
<a v-on:click.stop="doThis"></a>
<!-- 提交事件不再重载页面 -->
<form v-on:submit.prevent="onSubmit"></form>
<!-- 修饰符可以串联 -->
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
<!-- 添加事件监听器时使用事件捕获模式 -->
<!-- 即内部元素触发的事件先在此处理,然后才交由内部元素进行处理 -->
<div v-on:click.capture="doThis">...</div>
<!-- 只当在 event.target 是当前元素自身时触发处理函数 -->
<!-- 即事件不是从内部元素触发的 -->
<div v-on:click.self="doThat">...</div>
<!-- 如果想要监听组件就必须加native -->
<cpn @click.nativa="btnClick()">组件</cpn>
使用修饰符时,顺序很重要;相应的代码会以同样的顺序产生。因此,用 v-on:click.prevent.self
会阻止所有的点击,而 v-on:click.self.prevent
只会阻止对元素自身的点击。
Vue 还对应 addEventListener
中的 passive
选项提供了 .passive
修饰符。
<!-- 滚动事件的默认行为 (即滚动行为) 将会立即触发 -->
<!-- 而不会等待 `onScroll` 完成 -->
<!-- 这其中包含 `event.preventDefault()` 的情况 -->
<div v-on:scroll.passive="onScroll">...</div>
这个 .passive
修饰符尤其能够提升移动端的性能。
不要把 .passive
和 .prevent
一起使用,因为 .prevent
将会被忽略,同时浏览器可能会向你展示一个警告。请记住,.passive
会告诉浏览器你不想阻止事件的默认行为。
按键修饰符:
在监听键盘事件时,我们经常需要检查详细的按键。Vue 允许为 v-on
在监听键盘事件时添加按键修饰符:
<!-- 只有在 `key` 是 `Enter` 时调用 `vm.submit()` -->
<input v-on:keyup.enter="submit">
使用 keyCode
attribute 也是允许的:
<input v-on:keyup.13="submit">
为了在必要的情况下支持旧浏览器,Vue 提供了绝大多数常用的按键码的别名:
.enter
.tab
.delete
(捕获“删除”和“退格”键).esc
.space
.up
.down
.left
.right
.exact
修饰符
2.5.0 新增
.exact
修饰符允许你控制由精确的系统修饰符组合触发的事件。
<!-- 即使 Alt 或 Shift 被一同按下时也会触发 -->
<button v-on:click.ctrl="onClick">A</button>
<!-- 有且只有 Ctrl 被按下的时候才触发 -->
<button v-on:click.ctrl.exact="onCtrlClick">A</button>
<!-- 没有任何系统修饰符被按下的时候才触发 -->
<button v-on:click.exact="onClick">A</button>
鼠标按钮修饰符
2.2.0 新增
.left
.right
.middle
这些修饰符会限制处理函数仅响应特定的鼠标按钮。
表单输入绑定
v-modle:
v-modle:默认是收集value值,像text,password,这些他们只要输入就能拿到value值,但是像radio这个,就必须设置value值,因为他只能点,不能输入。
如果是checkbox,不设置value的话,v-modle默认收集的是checked(也就是只要布尔值),设置了value就是收集value值
所以,如果表单是checkbox:那么要有value,而且v-modle绑定的要是个数组
收集表单数据:
若:,则v-model收集的是value值,用户输入的就是value值
若:,则v-model收集的是value值,且要给标签配置value值
若:
1. 没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值) 2. 配置input的value属性: 1. v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值) 2. v-model的初始值是数组,那么收集的就是value组成的数组 3. v-model的是三个修饰符: 1. lazy:失去焦点再收集数据 2. number:输入字符串转为有效的数字 3. trim:过滤首尾空格
<input type='radio' value='男' name='sex' v-modle='sex'/>
<input type='radio' value='女' name='sex' v-modle='sex'/>
data:{
sex:''
}
<input v-model="searchText">
等价于:
<input
v-bind:value="searchText"
v-on:input="searchText = $event.target.value"
>
当用在组件上时,v-model
则会这样:
<custom-input
v-bind:value="searchText"
v-on:input="searchText = $event"
></custom-input>
为了让它正常工作,这个组件内的 <input>
必须:
- 将其
value
attribute 绑定到一个名叫value
的 prop 上 - 在其
input
事件被触发时,将新的值通过自定义的input
事件抛出
写成代码之后是这样的:
Vue.component('custom-input', {
props: ['value'],
template: `
<input
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
`
})
-
你可以用
v-model
指令在表单<input>
、<textarea>
及<select>
元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但v-model
本质上不过是语法糖。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。 -
v-model
会忽略所有表单元素的value
、checked
、selected
attribute 的初始值而总是将 Vue 实例的数据作为数据来源。你应该通过 JavaScript 在组件的data
选项中声明初始值。 -
对于需要使用输入法 (如中文、日文、韩文等) 的语言,你会发现
v-model
不会在输入法组合文字过程中得到更新。如果你也想处理这个过程,请使用input
事件。 -
对于单选按钮,复选框及选择框的选项,
v-model
绑定的值通常是静态字符串 (对于复选框也可以是布尔值): -
<!-- 当选中时,`picked` 为字符串 "a" --> <input type="radio" v-model="picked" value="a"> <!-- `toggle` 为 true 或 false --> <!-- 有多个复选框时,`toggle` 为 里面的value的值 --> <input type="checkbox" v-model="toggle"> <!-- 当选中第一个选项时,`selected` 为字符串 "abc" --> <select v-model="selected"> <option value="abc">ABC</option> </select>
修饰符
.lazy
在默认情况下,v-model
在每次 input
事件触发后将输入框的值与数据进行同步 (除了上述输入法组合文字时)。你可以添加 lazy
修饰符,从而转为在 change
事件_之后_进行同步:
<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg">
.number
如果想自动将用户的输入值转为数值类型,可以给 v-model
添加 number
修饰符:
<input v-model.number="age" type="number">
这通常很有用,因为即使在 type="number"
时,HTML 输入元素的值也总会返回字符串。如果这个值无法被 parseFloat()
解析,则会返回原始的值。
.trim
如果要自动过滤用户输入的首尾空白字符,可以给 v-model
添加 trim
修饰符:
<input v-model.trim="msg">
组件
组件是可复用的 Vue 实例,且带有一个名字
组件名大小写
定义组件名的方式有两种:横杆和驼峰
使用 kebab-case:横杆
Vue.component('my-component-name', { /* ... */ })
当使用 kebab-case (短横线分隔命名) 定义一个组件时,你也必须在引用这个自定义元素时使用 kebab-case,例如 <my-component-name>
。
使用 PascalCase:驼峰
Vue.component('MyComponentName', { /* ... */ })
当使用 PascalCase (首字母大写命名) 定义一个组件时,你在引用这个自定义元素时两种命名法都可以使用。也就是说 <my-component-name>
和 <MyComponentName>
都是可接受的。注意,尽管如此,直接在 DOM (即非字符串的模板) 中使用时只有 kebab-case 是有效的。
父组件传递数据给子组件
- 传什么都可以,数组、对象、函数、data中的数据都行
- 父组件可以给子组件传一个函数(带参数),子组件调用(传入参数),父组件就收到(参数)
- 还可以自定义事件
Prop 的大小写
HTML 中的 attribute 名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 名需要使用其等价的 kebab-case (短横线分隔命名) 命名:
Vue.component('blog-post', {
// 在 JavaScript 中是 camelCase 的
props: ['postTitle'],
template: '<h3>{{ postTitle }}</h3>'
})
<!-- 在 HTML 中是 kebab-case 的 -->
<blog-post post-title="hello!"></blog-post>
重申一次,如果你使用字符串模板,那么这个限制就不存在了。
Vue中的字符串模板
1、HTML模板和字符串模板
HTML模板(dom模板):直接在HTML页面挂载的模板,就是原先写在页面上的,能被浏览器识别的HTML结构,会在一加载就被浏览器渲染,然后js获取dom节点的内容, 形成dom模板。(即非字符串模板)
字符串模板:可能原先放在服务器上的,script标签或者js的字符串里,原先不参与页面渲染的一串字符。
2、Props属性:HTML 特性是不区分大小写的。所以,当使用的不是字符串模板时,camelCase (驼峰式命名) 的 props属性需要转换为相对应的 kebab-case (短横线分隔式命名):
(1)、HTML模板:
Vue.component('child', {
// 在 JavaScript 中使用 camelCase
props: ['myMessage'],
template: '<span>{{ myMessage }}</span>'
})
(2)、字符串模板:
<!-- 在 HTML 中使用kebab-case -->
<child my-message="hello!"></child>
3、组件名大小写:
注意:当直接在 DOM 中使用一个组件 (而不是在字符串模板或单文件组件) 的时候,我们强烈推荐遵循 W3C 规范中的自定义组件名 (字母全小写且必须包含一个连字符)。这会帮助你避免和当前以及未来的 HTML 元素相冲突。
(1)、使用 kebab-case:
Vue.component('my-component-name', { /* ... */ });
当使用 kebab-case (短横线分隔命名) 定义一个组件时,你也必须在引用这个自定义元素时使用 kebab-case,例如 。
(2)、使用 PascalCase:
Vue.component('MyComponentName', { /* ... */ })
当使用 PascalCase (驼峰式命名) 定义一个组件时,你在引用这个自定义元素时两种命名法都可以使用。也就是说 和 都是可接受的。注意,尽管如此,直接在 DOM (即非字符串的模板,如:在单个组件的<template></template>中 或者 index.html中直接CDN引入vue.js的<div id="app"></div>中) 使用时只有 kebab-case 是有效的,使用驼峰式,是不会渲染的。
Prop 类型
到这里,我们只看到了以字符串数组形式列出的 prop:
props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
但是,通常你希望每个 prop 都有指定的值类型。这时,你可以以对象形式列出 prop,这些 property 的名称和值分别是 prop 各自的名称和类型:
props: {
title: String,
likes: Number,
isPublished: Boolean,
commentIds: Array,
author: Object,
callback: Function,
contactsPromise: Promise // or any other constructor
}
//还可以
props: {
title:{
type:String,
default:''
},
likes:{
type:Number,
default:0,
required:true,//必传
}
//......等等
}
传递静态或动态 Prop
不加冒号传递过去的就是字符串,加了冒号才能写表达式(或者变量)
像这样,你已经知道了可以像这样给 prop 传入一个静态的值:
<blog-post title="My journey with Vue"></blog-post>
你也知道 prop 可以通过 v-bind
动态赋值,例如:
<!-- 动态赋予一个变量的值 -->
<blog-post v-bind:title="post.title"></blog-post>
<!-- 动态赋予一个复杂表达式的值 -->
<blog-post
v-bind:title="post.title + ' by ' + post.author.name"
></blog-post>
在上述两个示例中,我们传入的值都是字符串类型的,但实际上任何类型的值都可以传给一个 prop。
传入一个数字
<!-- 即便 `42` 是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
<blog-post v-bind:likes="42"></blog-post>
<!-- 用一个变量进行动态赋值。-->
<blog-post v-bind:likes="post.likes"></blog-post>
传入一个布尔值
<!-- 包含该 prop 没有值的情况在内,都意味着 `true`。-->
<blog-post is-published></blog-post>
<!-- 即便 `false` 是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
<blog-post v-bind:is-published="false"></blog-post>
<!-- 用一个变量进行动态赋值。-->
<blog-post v-bind:is-published="post.isPublished"></blog-post>
传入一个数组
<!-- 即便数组是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
<blog-post v-bind:comment-ids="[234, 266, 273]"></blog-post>
<!-- 用一个变量进行动态赋值。-->
<blog-post v-bind:comment-ids="post.commentIds"></blog-post>
传入一个对象
<!-- 即便对象是静态的,我们仍然需要 `v-bind` 来告诉 Vue -->
<!-- 这是一个 JavaScript 表达式而不是一个字符串。-->
<blog-post
v-bind:author="{
name: 'Veronica',
company: 'Veridian Dynamics'
}"
></blog-post>
<!-- 用一个变量进行动态赋值。-->
<blog-post v-bind:author="post.author"></blog-post>
传入一个对象的所有 property
如果你想要将一个对象的所有 property 都作为 prop 传入,你可以使用不带参数的 v-bind
(取代 v-bind:prop-name
)。例如,对于一个给定的对象 post
:
post: {
id: 1,
title: 'My Journey with Vue'
}
下面的模板:
<blog-post v-bind="post"></blog-post>
等价于:
<blog-post
v-bind:id="post.id"
v-bind:title="post.title"
></blog-post>
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。
注意在 JavaScript 中对象和数组是通过引用传入的,所以对于一个数组或对象类型的 prop 来说,在子组件中改变变更这个对象或数组本身将会影响到父组件的状态。
所以不要改变父组件传递过来的prop,如果要改变,则可以在data中定义一个变量来改变
props:['sun'],
data(){
return {
result:this.sun
}
}
Prop 验证
我们可以为组件的 prop 指定验证要求,例如你知道的这些类型。如果有一个需求没有被满足,则 Vue 会在浏览器控制台中警告你。这在开发一个会被别人用到的组件时尤其有帮助。
为了定制 prop 的验证方式,你可以为 props
中的值提供一个带有验证需求的对象,而不是一个字符串数组。例如:
Vue.component('my-component', {
props: {
// 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
propA: Number,
// 多个可能的类型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 带有默认值的数字
propD: {
type: Number,
default: 100
},
// 带有默认值的对象
propE: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
})
当 prop 验证失败的时候,(开发环境构建版本的) Vue 将会产生一个控制台的警告。
注意那些 prop 会在一个组件实例创建之前进行验证,所以实例的 property (如 data
、computed
等) 在 default
或 validator
函数中是不可用的。
在生命周期钩子函数 created中,就可以访问到props中的数据了
是先准备好通过prop传进来的数据在初始化组件的data的,所以data中可以使用props中数据
类型检查
type
可以是下列原生构造函数中的一个:
String
Number
Boolean
Array
Object
Date
Function
Symbol
额外的,type
还可以是一个自定义的构造函数,并且通过 instanceof
来进行检查确认。例如,给定下列现成的构造函数:
function Person (firstName, lastName) {
this.firstName = firstName
this.lastName = lastName
}
你可以使用:
Vue.component('blog-post', {
props: {
author: Person
}
})
来验证 author
prop 的值是否是通过 new Person
创建的。
子组件传递数据给父组件
推荐始终使用 kebab-case 的事件名。(btn-click)
自定义事件的流程
在子组件中,通过$emit()来触发事件
在父组件中,通过V-on来监听子组件事件
methods:{
bthClick(item){
// console.log(item)
//发射自定义事件,第一个参数是自定义事件名称,第二个是传递出去的数据
this.$emit('zi-din-yi-shi-jian',item);
}
}
第一种:通过prop先传递方法
可以给在父组件先定义一个方法show(a),传递给子组件,子组件接收后调用方this.show(this.shuju),往方法传参数,子组件一调用,父组件就可以接收到。
第二种:自定义事件
使用$emit()自定义一个事件,发射给父组件,父组件监听该事件@自定义事件名字=“回调函数”。(如果需要只触发一次,可以使用@自定义事件名字.once)
第三中:也是自定义事件
使用KaTeX parse error: Expected '}', got 'EOF' at end of input: …mounted(){this.refs.xxx.KaTeX parse error: Expected 'EOF', got '}' at position 19: …'自定义事件名字',回调函数)}̲,注意:这里的回调函数是在me…once)
解绑自定义事件:
解绑一个自定义事件:通过this.$off(‘自定义事件名字’);
解绑多个自定义事件:this.$off([‘第一个’,‘第二个’]);
解绑所以自定义事件:this.$off();
销毁当前组件实例,所以自定义事件也就不能用了
组件通信------全局事件总线
可以实现任意两个组件的通信
安装事件总线
main.js
...
new Vue({
.....
beforeCreate(){
//安装全局事件总线
Vue.prototype.$bus = this
},
......
})
使用事件总线
//组件1
methods:{
show(){
//触发|发射事件
this.$bus.$emit('hellp',111)
}
}
//组件2
mounted(){
//监听|绑定事件
this.$bus.$on('hello',(data)=>{
console.log(data);//111
})
},
//用了事件总线最好要写这句,要不然事件总线身上太多东西了
//因为如果有一天,组件被销毁了,但是事件总线上绑定的不会被自动销毁,所以我们要自己销毁
beforeDestroy(){//组件销毁前解绑自定义事件
this.$bus.off('hello');
}
组件通信------消息订阅与发布
可以实现任意两个组件的通信
消息订阅与发布:
- 订阅消息(需要拿数据的组件):消息名
- 发布消息(被拿数据的组件):消息内容
例子:生活中报纸订阅与发布:
- 订阅报纸:住址(关键)
- 邮递员送报纸:报纸(关键)
https://github.com/mroderick/PubSubJS
安装pubsub-js库
npm install pubsub-js
引入pubsub
import PubSub from ‘pubsub-js’
先订阅消息:
组件1: this.pubId = PubSub .subscribe(‘hello’,(a,b)=>{
//回调函数中的形参一般第一个写msgName,第二个写data,规范一点
console.log(‘有人发布了’);回调函数中有两个参数,第一个是发布的名字,第二个是携带过来的数据
})
后发布消息:消息一发布,订阅中的回调函数就会执行
组件2: PubSub.publish(‘hello’, ‘携带数据’);//异步发布
组件2: PubSub.publishSync(‘hello’, ‘携带数据’);//同步发布
为了写的更好一点,可以加上取消订阅,如果组件都没了,那么订阅消息还有必要存在吗
beforDestroy(){
PubSub.unsubscribe(this.pubId)
}
组件通信----依赖注入(provide / inject)
这种方式就是Vue中的依赖注入,该方法用于父子组件之间的通信。当然这里所说的父子不一定是真正的父子,也可以是祖孙组件,在层数很深的情况下,可以使用这种方法来进行传值。就不用一层一层的传递了。
provide / inject
是Vue提供的两个钩子,和data
、methods
是同级的。并且provide
的书写形式和data
一样。
provide
钩子用来发送数据或方法inject
钩子用来接收数据或方法
在父组件中:
provide() {
return {
num: this.num
};
}
复制代码
在子组件中:
inject: ['num']
复制代码
还可以这样写,这样写就可以访问父组件中的所有属性:
provide() {
return {
app: this
};
}
data() {
return {
num: 1
};
}
inject: ['app']
console.log(this.app.num)
复制代码
注意: 依赖注入所提供的属性是非响应式的。
非 Prop 的 Attribute
一个非 prop 的 attribute 是指传向一个组件,但是该组件并没有相应 prop 定义的 attribute。
因为显式定义的 prop 适用于向一个子组件传入信息,然而组件库的作者并不总能预见组件会被用于怎样的场景。这也是为什么组件可以接受任意的 attribute,而这些 attribute 会被添加到这个组件的根元素上。
例如,想象一下你通过一个 Bootstrap 插件使用了一个第三方的 <bootstrap-date-input>
组件,这个插件需要在其 <input>
上用到一个 data-date-picker
attribute。我们可以将这个 attribute 添加到你的组件实例上:
<bootstrap-date-input data-date-picker="activated"></bootstrap-date-input>
然后这个 data-date-picker="activated"
attribute 就会自动添加到 <bootstrap-date-input>
的根元素上。
替换/合并已有的 Attribute
想象一下 <bootstrap-date-input>
的模板是这样的:
<input type="date" class="form-control">
为了给我们的日期选择器插件定制一个主题,我们可能需要像这样添加一个特别的类名:
<bootstrap-date-input
data-date-picker="activated"
class="date-picker-theme-dark"
></bootstrap-date-input>
在这种情况下,我们定义了两个不同的 class
的值:
form-control
,这是在组件的模板内设置好的date-picker-theme-dark
,这是从组件的父级传入的
对于绝大多数 attribute 来说,从外部提供给组件的值会替换掉组件内部设置好的值。所以如果传入 type="text"
就会替换掉 type="date"
并把它破坏!庆幸的是,class
和 style
attribute 会稍微智能一些,即两边的值会被合并起来,从而得到最终的值:form-control date-picker-theme-dark
。
禁用 Attribute 继承
如果你不希望组件的根元素继承 attribute,你可以在组件的选项中设置 inheritAttrs: false
。例如:
Vue.component('my-component', {
inheritAttrs: false,
// ...
})
这尤其适合配合实例的 $attrs
property 使用,该 property 包含了传递给一个组件的 attribute 名和 attribute 值,例如:
{
required: true,
placeholder: 'Enter your username'
}
有了 inheritAttrs: false
和 $attrs
,你就可以手动决定这些 attribute 会被赋予哪个元素。在撰写基础组件的时候是常会用到的:
Vue.component('base-input', {
inheritAttrs: false,
props: ['label', 'value'],
template: `
<label>
{{ label }}
<input
v-bind="$attrs"
v-bind:value="value"
v-on:input="$emit('input', $event.target.value)"
>
</label>
`
})
注意 inheritAttrs: false
选项不会影响 style
和 class
的绑定。
将原生事件绑定到组件
组件使用元素事件。组件上写的事件不加.native,都会被当成自定义事件
你可能有很多次想要在一个组件的根元素上直接监听一个原生事件。这时,你可以使用 v-on
的 .native
修饰符:
<base-input v-on:focus.native="onFocus"></base-input>
<base-input v-on:click.native="onFocus"></base-input>
全局配置
Vue.config.productionTip = false
设置为 false
以阻止 vue 在启动时生成生产提示。(控制台)
自定义指令
定义一个指令big,使用时:v-big
定义一个指令big2,使用:v-big2
<div id='app'>
<h2 v-big='n'></h2>
</div>
new Vue({
el:'#app',
data:{
n:1
},
//定义指令
directives:{
//这里面的指令都是局部的指令
//这里面所有的函数的this都是window
//"big":function(element,binding){}//函数写法,还有对象写法
//big:function(element,binding){}//函数写法,还有对象写法
//函数写法简写,big函数何时会被调用?1.指令与元素成功绑定时(一上来),2.指令所在的模板被重新解析时
big(element,binding){
//第一个参数是绑定指令的dom元素:<h2></h2>
//第二个是绑定的数据:n,binding.value就是n的值
console.log('big')
console.log(this)//window
.....
},
//对象写法
big2:{
//里面的方法名字是固定的,vue会自动调用
bind(element,binding){//指令与元素成功绑定时(一上来)
},
inserted(element,binding){//指令所在元素被插入页面时
},
update(element,binding){//指令所在的模板被从新解析时
}
}
}
})
//全局指令对象写法
Vue.directives('big2',{
//里面的方法名字是固定的,vue会自动调用
bind(element,binding){//指令与元素成功绑定时(一上来)
},
inserted(element,binding){//指令所在元素被插入页面时
},
update(element,binding){//指令所在的模板被从新解析时
}
})
//全局指令函数写法
Vue.directives('big',function(element,binding){
//第一个参数是绑定指令的dom元素:<h2></h2>
//第二个是绑定的数据:n,binding.value就是n的值
console.log('big')
console.log(this)//window
.....
})
- 普通DOM元素进行底层操作的时候,可以使用自定义指令
- 自定义指令是用来操作DOM的。尽管Vue推崇数据驱动视图的理念,但并非所有情况都适合数据驱动。自定义指令就是一种有效的补充和扩展,不仅可用于定义任何的DOM操作,并且是可复用的。
ref属性
在JavaScript中需要通过document.querySelector("#demo")来获取dom节点,
然后再获取这个节点的值。在Vue中,我们不用获取dom节点,元素绑定ref之后,
直接通过this.$refs即可调用,这样可以减少获取dom节点的消耗。
也就是说在自己组件中可以获取自己的。
ref被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs对象上。
如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用
就指向该子组件实例
<h2 ref='title'>标题</h2>
获取:
this.$refs.title
注意: $refs只有在组件渲染完成后才填充,在初始渲染的时候不能访问它们,并且它
是非响应式的,因此不能用它在模板中做数据绑定
有时候我们需要父组件直接访问子组件,子组件直接访问父组件,或者子组件访问跟组件。
父组件访问子组件:使用$children或者$refs(开发时用这个比较多)
先看看$children的访问
this.$children是一个数组类型,它包含所有子组件对象
1.$children
console.log(this.$children);//子组件可能有多个,所以这是个数组
this.$children[0].showMessage();//可以拿到子组件中的方法
console.log(this.$children[0].a);
在真实开发中不用$children去哪东西
为什么不用$children呢,因为如果在这里中间再来个子组件,那么可能就需要改$children[1]
这里的中括号中的数值了,下标值可能需要改变
2.$refs
console.log(this.$refs);//默认是个空对象
//那怎么用呢?必须在组件上面加属性(ref),<cpn ref="随便写"></cpn>
console.log(this.$refs.suibian);
console.log(this.$refs.suibian.a);
this.$refs.suibian.showMessage();
总结:ref属性
- 被用来给元素或子组件注册引用信息(id的替代者)
- 应用在html标签上获取的是真实dom元素,应用在组件标签上是组件实例对象(vc)
- 使用方式:
- 打标识:
…
或者 - 获取:this.$refs.xxx
- 打标识:
r o o t 和 root和 root和parent
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="../js/vue.js" type="text/javascript" charset="utf-8"></script>
</head>
<body>
<div id="app">
<cpn></cpn>
</div>
<!-- 子组件模板 -->
<template id="cpn">
<div>
<h2>我是子组件</h2>
<button @click="bthClick()">按钮</button>
</div>
</template>
<script type="text/javascript">
const app = new Vue({
el: "#app",
data: {
msg: "helloWorld"
},
components:{
cpn:{
template:"#cpn",
methods:{
bthClick(){
//1.访问父组件$parent
//开发时不建议使用
//我们开发时,这些组件都是需要复用的
//因为,你去别的父组件拿东西可能那到,去另一个别的的父组件拿可能拿不到
//console.log(this.$parent.msg);
//2.访问跟组件$root,也很少用到
console.log(this.$root.msg)
}
}
}
}
})
</script>
</body>
</html>
mixin:混入
mixin(混入):
类似于继承
哪些可以抽哪些不可以抽取?
可以抽:生命周期的代码。如果是生命周期函数,那么继承mixin的组件,两个生命周期会合并。
如果混合中存在,本身组件也存在的data数据或者methods中的方法,都以为本身为主
mixin是共享代码
当组件和mixin同时定义生命周期选项,两个都会触发,而且mixin会先触发.
如果组件和mixin同时定义相同方法,组件的方法会覆盖mixin.
如果组件和mixin同时定义相同计算属性,组件的计算属性会覆盖mixin.
也就是说,处理生命周期钩子,优先用自己本身的属性,方法,数据
//创建mixin.js文件,混合中可以写什么呢?
//只要是组件中可以的都可以
export const hunhe = {
data(){
return {
//如果混合中有,组件本身也有,那么默认使用组件本身的
x:200
}
},
methods:{
showName(){
alert(this.name)
}
},
mounted(){
console.log('你好1')
}
}
//创建组件1,Student.vue
<template>
.....
</template>
<script>
import {hunhe,hunhe2} from './mixin'
export default {
name:'Student',
data(){
return{
//如果混合中有,组件本身也有,那么默认使用组件本身的
name:'河职院',
address:'河源',
x:300
}
},
mounted(){
console.log('你好2')
}
//使用混合
mixins:[hunhe,hunhe2]
}
</script>
以上的都是局部混合
全局混合,在main.js 中写:
-
import {hunhe} from ‘…’
-
Vue.mixins(hunhe),这个时候vm和vc身上都有混合
vue使用或自定义插件
使用:
- 在main.js中引入插件 import … from ‘…’
- 应用创建:Vue.use(插件,参数1,参数2)
自定义插件:
-
创建一个js文件,可以起名为plugins.js
-
插件必须要有install()方法
-
install(Vue,参数1,参数2)接收的第一个参数,参数是Vue实例
-
后的参数是使用插件时传入如:Vue.use(插件,参数1,参数2)
-
export default { //vue会自动帮我们调用 install(Vue){ //console.log("@@@",Vue) //可以在这里写全局过滤器、自定义全局指令、全局混入等等 //给Vue原型添加属性、方法等,vm和vc就都可以使用属性和方法了 Vue.prototype.hello = ()=>{ ..... } } }
-
this.$nextTick()方法
nextTick:下一轮的意思
//这个方法中的回调函数会在dom节点更新完毕之后在执行
this.$nextTick(function(){
})
组件内使用 vm.$nextTick()
实例方法只需要通过this.$nextTick()
,并且回调函数中的 this
将自动绑定到当前的 Vue
实例上
$nextTick()
会返回一个 Promise
对象,可以是用async/await
完成相同作用的事情
await this.$nextTick()
在什么地方用呢?当改变数据后,要基于更新后的新DOM进行某些操作,要在nextTick所指定的回调函数中执行。
比如,现在methods中有一个方法show,
<input type="text" v-if="flag"/>
data(){
return{
flag:false
}
}
show(){
this.flag = true;//虽然这一句可以让标签渲染出来,但是也要等该方法执行完毕,vue发现数据变化,才重新渲染模板,而在标签渲染出来之前,就已经调用了focus()方法,所以没有作用。
this.$refs.某个输入框.focus();//这句是获取焦点会发现,并没有起作用,没有作用是因为,上面的标签还没有渲染出来,调用这个方法无效。
//那么这个时候就可以用nextTick方法来。
}
//------------------改成
show(){
this.flag = true;
this.$nextTick(function(){//会在dom节点更新完毕后执行
this.$refs.某个输入框.focus();
})
}
$arrts:通信的一种手段
他可以接收到父组件传递的属性,跟props一样,但是要注意,如果props接收了,那arrts上就获取不到被接收了的属性
父组件:
<XIAOHA title='title' zdy="zdy"/>
子组件
props:['title']
console.log(this.$arrts)//{zdy:zdy}
//如果不使用props接收
console.log(this.$arrts)//{zdy:zdy,title:title}
$listeners:通信的一种手段
可以获取到父组件给子组件传递的事件
父组件:
<XIAOHA @clicka='clicka'/>
子组件
console.log(this.$listeners)//f
vue的过渡与动画
动画效果:
只使用v-enter-active和v-leave-active就好了
创建组件Test.vue
<template>
<div>
<button @click="isShow = !isShow">显示/隐藏</button>
<!-- 在vue中,想让谁想有过渡和动画效果,就使用transition标签把谁包裹起来 -->
<!-- 会自动调用下面写好的样式,在没有使用name属性的时候,类样式的名字也是固定的 -->
<!-- 如果使用了name属性,把样式名字的v改成name属性的属性值 -->
<!-- name属性,指定要使用的样式 -->
<!-- appear属性,使一上来就用动画过渡效果 -->
<transition name="hello" appear>
<h1 v-show="isShow">你好啊!</h1>
</transition>
<!-- 可以发现,transition与template一样最终是不会加到dom中的 -->
</div>
</template>
<script>
export default {
name: "Test",
data() {
return {
isShow: true
}
}
}
</script>
<style scoped>
h1 {
background-color: orange;
}
/* 使用动画,vue使用动画,名字固定,自动调用*/
/* 如果上面的transition标签没有给name属性,那么这两个名字就是固定的 */
/* 如果有使用name属性,那么久把这里的v改成name的属性值 */
/* .v-enter-active{ */
.hello-enter-active{
/* 进来时激活的动画 */
animation: atguigu 1s;
}
/* .v-leave-active{ */
.hello-leave-active{
/* 离开时激活的动画 */
/* 使用动画reverses是使动画倒着放 */
animation: atguigu 1s reverse;
}
/* 定义一个关键帧 */
@keyframes atguigu{
from{
transform: translateX(-100%);
}
to{
transform: translateX(0px);
}
}
</style>
在组件App.vue中测试
<template>
<div>
<Test/>
<!-- 在脚手架中下面这两种都可以使用 -->
<Test2/>
<test-2/>
</div>
</template>
<script>
import Test from './components/Test.vue'
import Test2 from './components/Test2.vue'
export default{
name:"App",
components:{Test,Test2}
}
</script>
过渡效果:
复制Test,创建Test2,样式稍微不同
vue在做动画的时候,自动添加的样式不止一个,比如:
.hello-enter,.hello-leave-to
.hello-enter-to,.hello-leave
最后实现效果与Test一样,Test是使用动画的,Test2是使用过渡的
使用动画时不需要写.hello-enter,.hello-leave-to,.hello-enter-to,.hello-leave
<template>
<div>
<button @click="isShow = !isShow">显示/隐藏</button>
<transition name="hello" appear>
<h1 v-show="isShow">你好啊!</h1>
</transition>
</div>
</template>
<script>
export default {
name: "Test",
data() {
return {
isShow: true
}
}
}
</script>
<style scoped>
h1 {
background-color: orange;
/* transition: 0.5s linear; */
}
/* 进入的起点,离开的终点 */
.hello-enter,
.hello-leave-to {
/* 使用过渡 */
transform: translateX(-100%);
}
/* 可以在这加过渡 */
.hello-enter-active,
.hello-leave-active{
transition: 0.5s linear;
}
/* 进入的终点,离开的起点 */
.hello-enter-to,
.hello-leave {
transform: translateX(0);
}
</style>
多个元素过渡:
<!-- transition标签中只能放一个元素,如果想让多个元素使用过渡,可以使用<transition-group>标签 -->
<!-- <transition-group>标签中的每一个元素都应该有唯一的key值 -->
默认情况下,它不会渲染一个包裹元素,但是你可以通过 tag attribute 指定渲染一个元素。
过渡模式不可用,因为我们不再相互切换特有的元素。
<transition-group name="hello" appear>
<h1 v-show="isShow" key='1'>你好啊!</h1>
<h1 v-show="isShow" key='2'>小哈!</h1>
</transition-group>
<transition-group tag='ul'>
<li style="margin: 10px;" :key="item" v-for="item in list">{{ item }</li>
</transition-group>
使用第三方动画库animate.css
https://animate.style/
使用 npm 安装:
npm install animate.css --save
引入
<script>
import 'animate.css';
</script>
使用
<template>
<div>
<button @click="isShow = !isShow">显示/隐藏</button>
<!-- name必须这样写 -->
<!-- 再写两个属性,属性值就使用第三方定义好的 -->
<transition-group
name="animate__animated animate__bounce"
appear
enter-active-class="animate__backInUp"
leave-active-class="animate__backOutUp"
>
<h1 v-show="isShow" key="1">你好啊!</h1>
<h1 v-show="isShow" key="2">小哈!</h1>
</transition-group>
</div>
</template>
<script>
import 'animate.css';
export default {
name: "Test",
data() {
return {
isShow: true
}
}
}
</script>
<style scoped>
h1 {
background-color: orange;
/* transition: 0.5s linear; */
}
</style>
该库中,标题带有entrances的就是进来的动画,exits就是出去的动画
transitions生命周期
@before-enter="beforeEnter" //对应enter-from
@enter="enter"//对应enter-active
@after-enter="afterEnter"//对应enter-to
@enter-cancelled="enterCancelled"//显示过度打断
@before-leave="beforeLeave"//对应leave-from
@leave="leave"//对应enter-active
@after-leave="afterLeave"//对应leave-to
@leave-cancelled="leaveCancelled"//离开过度打断
当只用 JavaScript 过渡的时候,在 enter
和 leave
钩子中必须使用 done
进行回调
const beforeEnter = (el: Element) => {
console.log('进入之前from', el);
}
const Enter = (el: Element,done:Function) => {
console.log('过度曲线');
setTimeout(()=>{
done()
},3000)
}
const AfterEnter = (el: Element) => {
console.log('to');
}
appear
通过这个属性可以设置初始节点过度 就是页面加载完成就开始动画 对应三个状态
appear-active-class=""
appear-from-class=""
appear-to-class=""
appear
slot插槽
默认插槽
定义一个组件Test.vue
<template>
<div>
<h1>标题</h1>
<slot>我是默认值,当使用者没有传递具体结构时,我会出现</slot>
</div>
</template>
<script>
....
</script>
<style scoped>
h1 {
background-color: orange;
/* transition: 0.5s linear; */
}
</style>
使用
<template>
<Test>
这里写的所有标签都会替换到上面插槽的位置如:
<p> </p>
<span></span>
</Test>
</template>
<script>
import Test from '../Test.vue'
export default {
name:'',
components:{Test}
}
....
</script>
具名插槽
<template>
<div>
<h1>标题</h1>
<slot name='hello'>我是默认值,当使用者没有传递具体结构时,我会出现</slot>
<slot name='word'>我是默认值,当使用者没有传递具体结构时,我会出现</slot>
</div>
</template>
使用具名插槽
<template>
<Test>
<!--这里写的所有标签都会替换到上面插槽的位置如:-->
<div slot="hello">
<p>hello</p>
</div>
<div slot="word">
<span>word</span>
</div>
<!--这样写不会覆盖,是会追加的-->
<div slot="word">
<p>word</p>
</div>
<!--这样写不合适,写了两遍slot="word",可以使用下面的新写法-->
</Test>
</template>
vue2.6.0新出的
<template>
<Test>
这里写的所有标签都会替换到上面插槽的位置如:
<div slot="hello">
<p>hello</p>
</div>
<!-- template标签是不会被渲染到dom中的,v-slot只能在template上使用,后面是冒号,冒号后面不用跟引号 -->
<template v-slot:word>
<div>
<span>word</span>
</div>
<div>
<p>word</p>
</div>
</template>
<!--简写 -->
<template #word>
<div>
<span>word</span>
</div>
<div>
<p>word</p>
</div>
</template>
</Test>
</template>
作用域插槽
理解:数据在组件的自身(子组件),但是根据数据生成的结构需要组件的使用者(父组件)来决定。
就是说,现在子组件有数据,也定义了插槽,父组件要使用子组件的时候,要在插槽的位置使用数据。
作用域插槽也可以有name,与具名插槽一样。
使用:假设子组件为Category.vue,父组件为App.vue
子组件:
<template>
<div>
这里这样写,父组件在使用的时候就会接收到数据
<slot :games="games"></slot>
</div>
</template>
<script>
export default {
name:"Category",
data(){
return{
games:['火影忍者','海贼王','七龙珠']
}
}
}
</script>
父组件:
<template>
<Category>
必须要包在template标签中,必须有scope属性
<template scope="scopeData">
插槽里面要写什么自定义
<ul>
<li v-for="g in scopeData.games" :key="g">{{g}}</li>
</ul>
</template>
</Category>
<Category>
必须要包在template标签中,必须有scope属性
<template slot-scope="scopeData">
插槽里面要写什么自定义
<ol>
<li v-for="g in scopeData.games" :key="g">{{g}}</li>
</ol>
</template>
</Category>
</template>
另一种子组件定义了插槽,子组件有数据,父组件要是使用
子组件:<slot name='items' :data="data"></slot>
父组件:<template #items="{data}" ></template>
语法是 #name的属性值={定义的数据}
Vuex
什么时候使用
- 多个组件依赖于同一状态
- 来自不同组件的行为需要变更同一状态
- vuex就是用来共享数据的
安装:
npm i vuex
引入:
import Vuex from ‘vuex’
注册:
Vue.use(Vuex)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-smusDv58-1668501814119)(…/…Vuevuex.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MPi5eZz4-1668501814121)(…Vuevuex原理.png)]
使用:搭建vuex环境
创建文件:src/store/index.js
//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用
Vue.use(Vuex)
//准备actions对象--响应组件中用户的动作
const actions = {
//如果有ajax请求,在这里发
//这是就是组件中调用了dispatch()的第一个参数
jia(conten,data){
conten.commit('JIA',data)
}
}
//准备mutations对象--修改state中的数据
const mutations = {
JIA(state,data){
//在这里修改数据
state.sum = data;
}
}
//准备state对象--保存具体的数据
const state = {
sum:2
}
//准备getters--用于将state中的数据进行加工
const getters = {
//不一定非要使用
//定义一个方法,如果操作state对象在的数据的过程过于复复杂,可以在这定义方法
bigSun(state){//如果有模块化开发,那么state就是当前仓库的state,不是大仓库的state
return state.sum += 2;
}
}
//创建并暴露store
export default new Vuex.Store({
//这里面actions,mutations,state名字是固定的
actions,
mutations,
state,
getters
})
在main.js中创建vm时传入store配置项
.....
//引入store
import store from './store/index.js'
......
//创建vm
new Vue({
el:'..',
render:h => h(App),
store
})
然后vm和vc就都有了$store属性了
访问
this.$store.dispatch('jia',2)
//模块化开发user是模块
this.$store.dispatch('user/jia',2)
四个map方法的使用
- mapState方法:用于帮助我们映射state中的数据为计算属性
- mapGetters方法:用于帮助我们映射getter中的数据为计算属性
- mapActions方法:用于帮助我们生产与actions对话的方法,即:包含$store.dispatch(xxx)的函数
- mapMutations方法:用于帮助我们生成与mutations对话的方法,即:包含$store.commit(xxx)的函数
-
import {mapState,mapGetters,mapActions,mapMutations} from vuex;
-
mapState的作用是用来简写 计算属性中this.$store.state 这一句的,
-
mapGetters的作用是用来简写 计算属性中this. s t o r e . s t a t e 这 一 句 的 , 如 果 是 模 块 化 开 发 t h i s . store.state 这一句的,如果是模块化开发this. store.state这一句的,如果是模块化开发this.store.state.模块
-
mapMutations的作用是用来简写 方法(methods)中this.$store.commit这一句的,
-
mapActions的作用是用来简写 方法(methods)中this.$store.dispatch这一句的,
-
使用、mapState({suibian:‘sum’,suibian2:‘xxx’,suibian3:''xxx})
- 注意了,配置对象中的key是随便定义的,但是value的话需要是state{}这个对象中定义好的
- 在计算属性中要这样写:…mapState({suibian:‘sum’,suibian2:‘xxx’,suibian3:‘xxx2’}),
- 因为mapState本身就是个对象—>let x = mapState({suibian:‘sum’,suibian2:‘xxx’,suibian3:''xxx})
-
computed:{ //suibian(){ //return this.$store.state.sum //}, //suibian2(){ //return this.$store.state.xxx //}, //suibian3(){ //return this.$store.state.xxx2 //} //------- //suibian4(){ // return this.$store.getters.xxx; //} //改写成 // ...mapState({suibian:'sum',suibian2:'xxx',suibian3:'xxx2'}), //如果,写成这种,拿就可以简写成数组的格式 // ...mapState({sum:'sum',xxx:'xxx',xxx2:'xxx2'}), ...mapState(['sum','xxx','xxx2']), //访问,this.sum ...mapGetters(['xxx']) }, methods:{ increment(){ this.$store.commit('JIA',this.xxx) } //借助mapMutations生成对应的方法,方法中会调用commit联系Mutations //可以简写成 ...mapMutations({increment:"JIA"}),//但是这样写要注意,他没有携带参数this.xxx,所以在模板中调用方法的时候需要括号,括号中传参数,没传参数,就是事件对象 //数组写法 ...mapMutations(["JIA"]), //---------- jiaOdd(){ this.$store.dispatch('jiaWait',this.n) } //简写成 ...mapActions({jiaOdd:'jiaWait'})//但是这样写要注意,他没有携带参数this.xxx,所以在模板中调用方法的时候需要括号,括号中传参数,没传参数,就是事件对象 //当然也可以写成数组形式 jiaWait(){ this.$store.dispatch('jiaWait',this.n) } //方法名两个相同可以简写成下面这种的数组形式 ...mapActions(['jiaWait']) }
VueX的模块化
-
就是每一个模块都有那三个或四个属性,一个模块一个js文件
-
比如有关购物车的vuex模块
-
//购物车模块 const cart = { actions:{}, mutations:{}, state:{a:0}, getters:{} } //支付模块 const pay = { actions:{}, mutations:{}, state:{b:0}, getters:{} } //然后使用模块 //创建并暴露store export default new Vuex.Store({ //modules:{ // a:cart, // b:pay //} modules:{ cart,pay } })
-
使用
-
//suibian2(){ //return this.$store.state.cart.xxx //}, computed:{ // ...mapState({cart:'cart',pay:"pay"}), //...mapState(['cart'],["pay"]), ...mapState({ cart:(state)=>{ //这里的state是大仓库中的数据,里面包含其它模块(//支付模块,//购物车模块) return state.cart } }) }, 模板上使用是 {{cart.a}}
-
第二种使用
-
computed:{ //都需要指定‘cart',因为我得找到是谁的a ...mapState('cart',['a']),//这种使用有前提,需要给什么定义的模块(支付模块,购物车模块)配置namespaced为true ...mapMutations('cart',{jia:'JIA'}) //或 ...mapMutations('cart',['JIA']) ...mapActions('cart',['xx']) ...mapGetters('cart',['xx']) }, /*如: const cart = { namespaced:true actions:{}, mutations:{}, state:{a:0}, getters:{} }*/ 模板上使用是 {{a}}
vue路由router
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZOc83mNS-1668501814124)(…URL的hash.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2LSLBKAF-1668501814126)(…HTML5的history模式:pushState.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DMH0Cnga-1668501814128)(…HTML5的history模式:replaceState.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xoGPqrjb-1668501814130)(…HTML5的history模式:go.png)]
前端路由与后端路由
-
路由:
- 一个路由就是一组映射关系(key-value)
- key为路径,value可能是function或component
-
后端路由:
- 理解:value是function,用于处理客户端提交的请求。
- 工作过程:服务器接收到一个请求时,根据请求路径找到匹配的函数来处理请求,返回响应数据。
-
前端路由:
- 理解:value是component,用于展示页面内容
- 工作过程:当浏览器的路径改变时,对应的组件就会显示
认识vue-router
-
路由用于设定访问路径, 将路径和组件映射起来.
-
在vue-router的单页面应用中, 页面的路径的改变就是组件的切换.
安装和使用vue-router
安装:
npm install vue-router --save
引入:最好单独创建一个文件router/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
//引入组件
//import Home from '../views/home/Home.vue'
//另一种写法:路由懒加载模式
const Home = () => import("../views/home/Home.vue");
Vue.use(VueRouter)
创建路由器,配置一级路由:
const routes = [
//一个对象就是一个路由
{
//路径,
path: '/',
//根目录时重定向到/home
redirect: '/home'
},
{
path: '/home',
//路上是/home时显示组件Home页面
component: Home
}
]
// 2.创建路由器router
export default new VueRouter({
routes,
//默认情况下, 路径的改变使用的URL的hash.有#出现
//如果希望使用HTML5的history模式, 非常简单, 进行如下配置即可:
mode: 'history'
})
//main.js引入文件
import router from './router/index'
new Vue({
router,//vm和vc上就可以使用$router了
render: h => h(App)
}).$mount('#app')
使用路由:
- : 该标签是一个vue-router中已经内置的组件, 它会被渲染成一个标签。
- 的to属性是让路由跳转,比如原来的地址是localhost:8080,使用to后跳转到localhost:8080/#/home。后面我们会讲使用代码跳转
- 的replace属性,设置后不会留下history记录,所以指定replace的情况下,后退键返回不能返回到上一个页面中。比如说我们现在在home页面,我们点击进入abc页面,那么我们将不能返回到上一个home页面。
- 浏览器的历史记录有两种写入方式:分别为push和replace,push是追加历史记录,replace是替换当前记录,路由跳转默认是push
- tag属性:可以替换为其他元素
- active-class:哪个路由处于活跃,就有这个属性,会自动添加一个默认class=“router-link-active”
- 发现路径中有#,不好看,可以在 new VueRouter的中配置mode: ‘history’
- [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jrT8jIBh-1668501814132)(D:MDfilestudy-notesVuerouter-link.png)]
- : 该标签会根据当前的路径, 动态渲染出不同的组件。网页的其他内容, 比如顶部的标题/导航, 或者底部的一些版权信息等会和处于同一个等级。在路由切换时, 切换的是挂载的组件, 其他内容不会发生改变.
几个注意点:
- 路由组件通常放在pages文件夹,一般组件通常放在components文件夹
- 通过切换,‘隐藏’了的路由组件,默认是被销毁了,需要的时候再去挂载
- 不销毁的办法:使用这个标签包裹不想销毁的就好了
- 每个组件都有自己的$route属性,里面存储着自己的路由信息
- 整个应用只有一个router,可以通过组件的$router属性获取到
嵌套路由:
嵌套路由是一个很常见的功能
-
比如在home页面中, 我们希望通过/home/news和/home/message访问一些内容.
-
一个路径映射一个组件, 访问这两个路径也会分别渲染两个组件.
实现嵌套路由有两个步骤:
-
创建对应的子组件, 并且在路由映射中配置对应的子路由.
-
在组件内部使用标签.
配置子路由:在一级路由中写children数组
const routes = [
{
path: '/home',
//路上是/home时显示组件Home页面
component: Home,
//配置子路由,在一级路由中写children数组
children:[
{
path:'news',//注意这里是不用加/
component:News
}
]
}
]
// 2.创建路由器router
export default new VueRouter({
routes,
//默认情况下, 路径的改变使用的URL的hash.有#出现
//如果希望使用HTML5的history模式, 非常简单, 进行如下配置即可:
mode: 'history'
})
路由传参:
- 传递query参数:
<ul>
<li v-for="m in messageList" :key="m.id">
<!-- 跳转路由并携带query参数,to的字符串写法 -->
<router-link :to="`/home?id=${m.id}&title=${m.title}`">{{m.title}}</router-link>
<!-- 跳转路由并携带query参数,to的对象写法 -->
<router-link :to="{
path:'/home',
query:{
id:m.id,
title:m.title
}
}">
{{m.title}}
</router-link>
</li>
</ul>
data(){
return{
messageList:[
{id:001,title:'zs'},
{id:002,title:'ls'},
{id:003,title:'ww'}
]
}
}
- 接收参数: r o u t e . q u e r y . i d 、 route.query.id、 route.query.id、route.query.title
传递参数主要有两种类型:
-
params的类型:
-
配置路由格式: /router/:id
-
传递的方式: 在path后面跟上对应的值
-
传递后形成的路径: /router/123, /router/abc
-
-
query的类型:
- 配置路由格式: /router, 也就是普通配置
-
-
传递的方式: 对象中使用query的key作为传递方式
-
传递后形成的路径: /router?id=123, /router?id=abc
-
-
vue让跳转路由参数不在地址栏显示(name;param)
- **name方式跳转:**push绑定的不再是path而是使用了你要发送的页面的name值
this.$router.push({name:'taskCenter', params:{id: ids, savePath: savePath}})
- param获取传参:
- this.$route.params.id;
- this.$route.params.savePath;
-
解决路由传递的参数跳转页面后刷新导致数据没了
- 使用query方式传参,可是路径参数就会显示
this.$router.push({ name: 'NewsDetail', query: { newsUrl: url } })
- 使用query方式传参,可是路径参数就会显示
-
如何使用它们呢? 也有两种方式: 的方式和JavaScript代码方式
<!-- 1.<router-link> --> <router-link :to="{ path:'/home', query:{ name:'zs', age:18 } }"> <router-link :to="{ path:'/home', params:{ name:'zs', age:18 } }"> {{m.title}} </router-link>
<script> methods:{ show(){ this.$router.push({ path:'/home', query:{ name:'zs', age:18 } }) } } </script>
-
获取参数:
-
获取参数通过$route对象获取的.
-
在使用了 vue-router 的应用中,路由对象会被注入每个组件中,赋值为 this.$route ,并且当路由切换时,路由对象会被更新。
-
通过$route获取传递的信息如下:
- this. r o u t e . p a r a m s . n a m e 、 t h i s . route.params.name、this. route.params.name、this.route.params.age
- this. r o u t e . q u e r y . n a m e 、 t h i s . route.query.name、this. route.query.name、this.route.query.age
-
-
路由在传递参数的时候,如果传递的是params格式的,且是通过对象进行传递的,只能通过给路由起名字,通过name的形式传递。
this.$router.push({name:'home',params:{id:xxx}})
-
如何指定params参数可传可不传,
-
在设置路由的时候后面加个括号,在路由跳转的时候就可以不传,也可以传递
-
{ path: '/home/:id?', component: Home, }
-
如果传参数的时候,传递了空字符串,那么路劲会错误
this.$router.push({name:'home',params:{id:''}})
-
那么这么解决什么的问题呢?
- 可以用undefined解决
this.$router.push({name:'home',params:{id:'' || undefined}})
-
命名路由:
-
作用:可以简化路由的跳转(最好是用在多级路由身上)
-
如何使用
-
给路由命名:
const routes = [ { path: '/home', component: Home, children:[ { path:'news', component:News, children:[ { name:'abc'//给路由命名 path:'abc', component:Abc } ] } ] } ] export default new VueRouter({ routes, mode: 'history' })
-
简化跳转
<!-- 简化前,需要写完整路径 --> <router-link to="/home/news/abc">跳转<router-link> <!-- 简化后,直接通过name跳转 --> <router-link :to="{name:'abc'}">跳转<router-link> <!--简化写法配合传递参数 --> <router-link :to="{ name:'abc', query:{ 姓名:'zs', age:18 } }" >跳转<router-link>
-
路由的props配置
用来解决传过来参数后,页面频繁出现 r o u t e . q u e r y . x x x 、 route.query.xxx、 route.query.xxx、route.params.xxx
//第一种写法对应props第一种,一一对应
const routes = [
{
path: '/home',
component: Home,
children:[
{
path:'news',
component:News,
children:[
{
name:'abc'//给路由命名
//path:'abc',//第一种写法
//path:'abc/:id/:title',//第二种写法
path:'abc',//第三种写法
component:Abc,//参数都会注入该组件
//props的第一种写法,值为对象,该对象中所有的key-value都会以props的形式传给Abc组件,这种写法用的扫,传进去的是死数据
// props:{a:1,b:'hello'}
//props的第二种写法,值为布尔值,若布尔值为真,就会把该路由组件收到的所有params参数,以props的形式传给Abc组件
//props:true
//props的第三中写法,值为函数,函数接收一个参数,参数是$route
props($route){
return {id:$route.query.id,title:$route.query.title}
//return {id:$route.query.id,title:$route.params.title}这里面也可以接受params参数
}
}
]
}
]
}
]
export default new VueRouter({
routes,
mode: 'history'
})
Abc组件接收:然后页面就可以直接{{id}}、{{title}}了,不需要
{{KaTeX parse error: Expected 'EOF', got '}' at position 15: route.query.id}̲}、{{route.params.id}}
//第一种接收
//props:['a','b']
//第二种接收
//props:['id','title']
//第三种接收
props:['id','title']
data(){
return{
}
}
路由跳转:
第一种是使用标签的to属性跳转。
- 这个会转为a标签,当然也可以用tag属性转为其他
第二种是使用JavaScript代码跳转
-
这种比较灵活,常用,比如要实现点击按钮3秒后在跳转。
-
使用this. r o u t e r . p u s h ( 这 里 面 写 的 代 码 跟 t o 属 性 中 的 一 样 ) 、 t h i s . router.push({这里面写的代码跟to属性中的一样})、this. router.push(这里面写的代码跟to属性中的一样)、this.router.replace({这里面写的代码跟to属性中的一样})
-
methods:{ toHome(){ this.$router.push({ path:'/home', query:{ 带参数过去 } }) } }
-
this.$router.push({}):跳转到某个路由,地址栏可以回退
-
this.$router.replace({}):跳转到某个路由,地址栏不能回退
-
this.$router.back();:地址栏回退
-
this.$router.forward():地址栏前进
-
this.$router.go():参数为-1与back()类似,参数为1与forward()类似
- 参数为-2代表回退两步
- …
路由的缓存
这个标签可以实现缓存。
使用:把要缓存的放在标签内即可
<keep-alive>
<router-view />
</keep-alive>
上面这样写默认都缓存
标签有include属性:表示哪个需要缓存
标签有exclude属性:表示除了xxx,其他都缓存
这两个属性的属性值是组件的name名字,可以写成数组
:include=“[‘Detail’,‘Home’]”
export default {
name:'Detail',
data(){
return{
}
}
}
<keep-alive exclude="Detail">
<router-view />
</keep-alive>
:是要显示的路由组件(我不知道我这么理解对吗)
路由的生命周期函数:
如果组件中使用了定时器,但是组件是缓存的,那么在beforeDestroy(){}函数就没用了。
这时可以使用deactivated(){},在这里面关闭定时器
activated(){
//激活的
}
deactivated(){
//失活的
}
路由守卫:
- 作用:对路由进行权限控制,比如某一个组件只能在用户登录后才到查看或点击什么的
- 分类:全局守卫、独享守卫、组件内守卫
全局守卫:
import Vue from 'vue'
import VueRouter from 'vue-router'
const Home = () => import("../views/home/Home.vue");
const Cart = () => import("../views/cart/Cart.vue");
const Category = () => import("../views/category/Category.vue");
const Profile = () => import("../views/profile/Profile.vue");
const Detail = () => import("../views/detail/Detail.vue");
// 1.安装插件
Vue.use(VueRouter)
// 2.创建router
const routes = [
{
path: '/home',
component: Home,
/
meta:{title:'程序员可以在这配置一些自己想要的信息'}
},
]
const router = new VueRouter({
routes,
mode: 'history'
})
//
//全局前置路由守卫----初始化的时候被调用,每次路由切换之前被调用
//beforeEach(),
router.beforeEach((to, from, next)=>{//每一次路由切换之前调用回调函数
//to: 即将要进入的目标 路由对象
//from: 当前导航正要离开的路由
//next():接着走
//必须调用next()函数,否则路由切换不过去
//这就可以在过去之前动态判断一些条件什么的
})
//全局后置路由守卫-----初始化的时候被调用,每次路由切换之后被调用
router.afterEach((to, from)=>{
//to: 即将要进入的目标 路由对象
//from: 当前导航正要离开的路由
})
export default router
独享守卫:
import Vue from 'vue'
import VueRouter from 'vue-router'
const Home = () => import("../views/home/Home.vue");
const Cart = () => import("../views/cart/Cart.vue");
const Category = () => import("../views/category/Category.vue");
const Profile = () => import("../views/profile/Profile.vue");
const Detail = () => import("../views/detail/Detail.vue");
// 1.安装插件
Vue.use(VueRouter)
// 2.创建router
const routes = [
{
path: '/home',
component: Home,
/
meta:{title:'程序员可以在这配置一些自己想要的信息'},
/独享守卫
beforeEnter:(to, from, next)=>{
//home这个路由自己的守卫,功能类似beforeEach
//进入这个组件(路由)之前,会自动调用
}
},
]
const router = new VueRouter({
routes,
mode: 'history'
})
export default router
组件内守卫:
在组件中写
<template>
</template>
<script>
export default {
name:'xx',
//当路由进入之前
//通过路由规则,进入该组件时被调用
beforeRouteEnter(to, from, next){
....
next();
},
//当路由离开之前
//通过路由规则,离开该组件时被调用
beforeRouteLeave(to, from, next){
....
next();
}
}
</script>
<style>
</style>
路由器的两种工作模式:
history模式和hash模式
- 对于一个url来说,什么是hash值?----#及其后面的内容就是hash值
- hash值不会包含在HTTP请求中,即:hash值不会带给服务器。
- hash模式:
- 地址中永远带着#号,不美观
- 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法
- 兼容性较好
- history模式:
- 地址干净,美观
- 兼容性和hash模式相比略差
- 应用部署上限时需要后端人员支持,解决刷新页面服务的404的问题。
vue路由跳转页面滚动到顶部
vue 2
import VueRouter from 'vue-router'
Vue.use(VueRouter)
//vue2.0 new VueRouter({}) 创建路由实例
const router= new VueRouter({
routes,
//配置滚动行为,跳转到新的路由界面滚动条的位置
scrollBehavior () {
return { x: 0, y: 0 }
}
})
vue 3
import { createRouter, createWebHashHistory } from 'vue-router'
// vue3.0 creatRouter({}) 创建路由实例
const router = createRouter({
// 使用hash的路由模式
history: createWebHashHistory(),
routes,
// 每次切换路由的时候滚动到页面顶部
scrollBehavior () {
return { left: 0, top: 0 }
}
})
最后
以上就是高大毛巾为你收集整理的Vue2学习笔记Vue 2…的全部内容,希望文章能够帮你解决Vue2学习笔记Vue 2…所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复