我是靠谱客的博主 高大毛巾,最近开发中收集的这篇文章主要介绍Vue2学习笔记Vue 2…,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

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之间的区别:

  1. computed能完成的功能,watch都可以完成

两个重要的小原则:

  1. 所有被Vue管理的函数,最好写成普通函数,这样this的指向才是vm(vue实例)或组件实例对象
  2. 所有不被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-ifv-for可以在<template> 元素上使用

永远不要把 v-ifv-for 同时用在同一个元素上。

(所以这里有个小技巧,可以外层嵌套template标签,然后将v-for放到标签上)但是这样:key怎么办

当 Vue 处理指令时,v-forv-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-forkey。请用字符串或数值类型的值。

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 会忽略所有表单元素的 valuecheckedselected 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 (如 datacomputed 等) 在 defaultvalidator 函数中是不可用的。

在生命周期钩子函数 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');
}

组件通信------消息订阅与发布

可以实现任意两个组件的通信

消息订阅与发布:

  1. 订阅消息(需要拿数据的组件):消息名
  2. 发布消息(被拿数据的组件):消息内容

例子:生活中报纸订阅与发布:

  1. 订阅报纸:住址(关键)
  2. 邮递员送报纸:报纸(关键)

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提供的两个钩子,和datamethods是同级的。并且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" 并把它破坏!庆幸的是,classstyle 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 选项不会影响 styleclass 的绑定。

将原生事件绑定到组件

组件使用元素事件。组件上写的事件不加.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属性

  1. 被用来给元素或子组件注册引用信息(id的替代者)
  2. 应用在html标签上获取的是真实dom元素,应用在组件标签上是组件实例对象(vc)
  3. 使用方式:
    • 打标识:

      或者
    • 获取:this.$refs.xxx

r o o t 和 root和 rootparent

<!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使用或自定义插件

使用:

  1. 在main.js中引入插件 import … from ‘…’
  2. 应用创建:Vue.use(插件,参数1,参数2)

自定义插件:

  1. 创建一个js文件,可以起名为plugins.js

  2. 插件必须要有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 过渡的时候,在 enterleave 钩子中必须使用 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

什么时候使用

  1. 多个组件依赖于同一状态
  2. 来自不同组件的行为需要变更同一状态
  3. 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)的函数
  1. import {mapState,mapGetters,mapActions,mapMutations} from vuex;

  2. mapState的作用是用来简写 计算属性中this.$store.state 这一句的,

  3. mapGetters的作用是用来简写 计算属性中this. s t o r e . s t a t e 这 一 句 的 , 如 果 是 模 块 化 开 发 t h i s . store.state 这一句的,如果是模块化开发this. store.statethis.store.state.模块

  4. mapMutations的作用是用来简写 方法(methods)中this.$store.commit这一句的,

  5. mapActions的作用是用来简写 方法(methods)中this.$store.dispatch这一句的,

  6. 使用、mapState({suibian:‘sum’,suibian2:‘xxx’,suibian3:''xxx})

    1. 注意了,配置对象中的key是随便定义的,但是value的话需要是state{}这个对象中定义好的
    2. 在计算属性中要这样写:…mapState({suibian:‘sum’,suibian2:‘xxx’,suibian3:‘xxx2’}),
      • 因为mapState本身就是个对象—>let x = mapState({suibian:‘sum’,suibian2:‘xxx’,suibian3:''xxx})
  7. 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')
使用路由:
  1. : 该标签是一个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)]
  1. : 该标签会根据当前的路径, 动态渲染出不同的组件。网页的其他内容, 比如顶部的标题/导航, 或者底部的一些版权信息等会和处于同一个等级。在路由切换时, 切换的是挂载的组件, 其他内容不会发生改变.

几个注意点:

  1. 路由组件通常放在pages文件夹,一般组件通常放在components文件夹
  2. 通过切换,‘隐藏’了的路由组件,默认是被销毁了,需要的时候再去挂载
    1. 不销毁的办法:使用这个标签包裹不想销毁的就好了
  3. 每个组件都有自己的$route属性,里面存储着自己的路由信息
  4. 整个应用只有一个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'

})

路由传参:

  1. 传递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'}
		]
	}
}
  1. 接收参数: r o u t e . q u e r y . i d 、 route.query.id、 route.query.idroute.query.title

传递参数主要有两种类型:

  1. params的类型:

    • 配置路由格式: /router/:id

    • 传递的方式: 在path后面跟上对应的值

    • 传递后形成的路径: /router/123, /router/abc

  2. query的类型:

    • 配置路由格式: /router, 也就是普通配置
    • 传递的方式: 对象中使用query的key作为传递方式

    • 传递后形成的路径: /router?id=123, /router?id=abc

  1. 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;
  2. 解决路由传递的参数跳转页面后刷新导致数据没了

    1. 使用query方式传参,可是路径参数就会显示
      1. this.$router.push({ name: 'NewsDetail', query: { newsUrl: url } }) 
  3. 如何使用它们呢? 也有两种方式: 的方式和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>
    
  4. 获取参数:

    • 获取参数通过$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.namethis.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.namethis.route.query.age
  5. 路由在传递参数的时候,如果传递的是params格式的,且是通过对象进行传递的,只能通过给路由起名字,通过name的形式传递。

    1. this.$router.push({name:'home',params:{id:xxx}})
  6. 如何指定params参数可传可不传,

    1. 在设置路由的时候后面加个括号,在路由跳转的时候就可以不传,也可以传递

    2. {
        path: '/home/:id?',
        component: Home,
      }
      
    3. 如果传参数的时候,传递了空字符串,那么路劲会错误this.$router.push({name:'home',params:{id:''}})

    4. 那么这么解决什么的问题呢?

      1. 可以用undefined解决
      2. this.$router.push({name:'home',params:{id:'' || undefined}})

命名路由:

  1. 作用:可以简化路由的跳转(最好是用在多级路由身上)

  2. 如何使用

    1. 给路由命名:

      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'
      })
      
    2. 简化跳转

      <!-- 简化前,需要写完整路径 -->
      <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.xxxroute.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(){
	//失活的
}

路由守卫:

  1. 作用:对路由进行权限控制,比如某一个组件只能在用户登录后才到查看或点击什么的
  2. 分类:全局守卫、独享守卫、组件内守卫
全局守卫:
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模式
  1. 对于一个url来说,什么是hash值?----#及其后面的内容就是hash值
  2. hash值不会包含在HTTP请求中,即:hash值不会带给服务器。
  3. hash模式:
    1. 地址中永远带着#号,不美观
    2. 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法
    3. 兼容性较好
  4. history模式:
    1. 地址干净,美观
    2. 兼容性和hash模式相比略差
    3. 应用部署上限时需要后端人员支持,解决刷新页面服务的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…所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(30)

评论列表共有 0 条评论

立即
投稿
返回
顶部