MENU

Vue2学习笔寄

2022-10-30 • 笔记编辑

基础内容

通过 data()提供数据

vue中可以在 export default{}里通过 data()提供数据,data必须是一个函数,return一个对象

export default {
  data () {
    return {
      uname: 'JuziYou',
      age: 18
    }
  }  
}

使用插值表达式显示数据

插值表达式使用两对大括号包裹,使用的数据需要在 data()methodscomputed等地方存在,可以使用表达式,但是不能使用在标签属性

{{ uname }}
{{ obj.uname }}
{{ obj.age > 18 ? '成年' : '未成年' }}

v-bind

插值表达式不能使用在标签属性,需要使用 v-bind需要设置动态html属性上,简写为 :

举例:

<a :href="url">戳戳</a>
<a v-bind:href="url">戳戳</a>


v-on

v-on语法为 v-on:事件名='需要执行的代码/函数名/函数名(实参)'需要在 methods中提供事件处理函数,简写 @

举例:

<button @click='num = bum + 1'>Click</button>
<button @click='functionA'>Click</button>
<button @click='functionB('JuziYou')'>Click</button>
<button v-on:click='num = bum + 1'>Click</button>
<button v-on:click='functionA'>Click</button>
<button v-on:click='functionB('JuziYou')'>Click</button>

事件修饰符

.prevent阻止默认行为
.stop阻止冒泡
.once程序运行期间只触发一次事件处理函数
.native在组件上调用事件


v-model

v-model是一个语法糖 @input:value组合到了一起,它吧属性和数据双向绑定到一起。双向绑定即数据变化视图同步变化,视图变化数据同步变化。

语法:v-model="数据变量"

<button v-model="数据变量"> 戳戳 </button>

在父子组件通信时,如果 :value传参给子组件 $emit('input', 值)可以使用 v-model代替

v-model 修饰符

.number.parseFloat转换为数字类型
.trim去除首尾空白(空格)
.lazy使用 change事件改变数据(默认为 imput事件改变数据)


v-textv-html

v-textv-html会更新DOM对象的innerText或者innerHTML,并且会覆盖差值表达式 v-text不会识别HTML标签,v-html会识别HTML标签

语法:

<p v-text="数据变量"></p>
<p v-html="数据变量"></p>

v-showv-ifv-else

v-showv-if控制标签的显示或隐藏,truefalse
v-show使用CSS的 display:none来隐藏
v-if将会直接从DOM树上移除
频繁切换显示的情况下使用 v-show因为使用 display:none来切换显示隐藏不会频繁创建元素节省性能,v-if是惰性的在 false时不会创建元素节省初期渲染开销

语法:

<p v-show="true"></p>
<p v-if="false"></p>

v-ifv-elsev-else-if同时使用,方便通过变量控制一套标签出现或者隐藏

<template>
  <div>
    <h1 v-if="yukari>= 60">紫老ffhfhewufuiefefrwgfuktyr</h1>
    <h1 v-else-if="yukari>= 30">紫妈</h1>
    <h1 v-else>紫</h1>
  </div>
</template>

<script>
export default {
  data(){
    return {
      yukari: 16
    }
  }
}
</script>

v-for

v-for 常用于列表渲染,按照数据循环生成,可以遍历数组、对象、数字、可遍历解构的字符串
每一项唯一标识符作为 :key="索引",可以最大限度的复用你的DOM,:key="索引"的索引只能是数字或者字符串

语法:
v-for="(值, 索引) in 目标" :key="索引"
v-for="值 in 目标" :key="值下的可用于索引的值"

<template>
  <div>
    <ul>
      <li v-for="(item,index) in list" :key="index">
        {{ item }} > {{ index }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data(){
    return {
      list:['JuziYou','MikanpaperYuzu','橘纸柚']
    }
  }
}
</script>
<template>
  <div>
    <ul>
      <li v-for="(value, key) in preson" :key="key">
        {{ value }} · {{ key }}
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data(){
    return {
      preson:{
        uname: '八云紫',
        skill: '操纵界线的能力',
        age: 18
      }
    }
  }
}
</script>
<template>

<div>
    <ul>
      <li v-for="(item,index) in personList" :key="index">
        >>>{{item.uname}}
        <p>{{item.skill}}</p>
      </li>
    </ul>
  </div>
</template>

<script>
export default {
  data(){
    return {
      personList:[
        {uname:'博丽灵梦',home:'博丽神社'},
        {uname:'琪露诺',home:'雾之胡'},
        {uname:'蕾米莉亚',home:'红魔馆'},
        {uname:'帕秋莉',home:'红魔馆'}
      ]
    }
  }
}
</script>
<template>
  <div>
    <ul>
      <li v-for="(item,i) in 5" :key="i">
        {{item}} · {{i}}
      </li>
    </ul>
  </div>
</template>


数组的数据更新监测

数组方法中能引起页面更新的方法有:
pushpopshiftunshiftsplicesortreverse
其他无法引起页面更新的方法可以通过赋值来完成更新
通过下标来更新值不会触发页面更新需要使用 $set来更新数组
语法:this.$ste(要改变的对象, 要改变的位置, 要改变的值)

<template>
  <div>
    <ul>
      <li v-for="(item,index) in list" :key="index">{{item}}</li>
    </ul>
    <button @click="changeFn">changeFn</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      list: ['博丽灵梦', '琪露诺', '八云紫']
    }
  },
  methods: 
    changeFn(){
      this.$set(this.list, 1, "魔理沙")
    }
  }
}
</script>

动态绑定 class

使用 v-bind:class设置动态属性一般使用简写 :class允许使用对象或者数组
:class不会影响到原有的class属性
使用对象动态绑定 :class="{类名:布尔值}"如果布尔值为 true就有这个类名,false则没有
使用数组动态绑定 :class="数组"标签会有数组里面的所有类名

<template>
  <div>
    <div :class="str">Nya</div>
  </div>
</template>

<script>
export default {
  data(){
    return {
      str: 'green'
    }
  }
}
</script>
<template>
  <div>
    <div :class="isRed ? 'red' : ''"></div>
  </div>
</template>

<script>
export default {
  data(){
    return {
      isRed: true
    }
  }
}
</script>
<template>
  <div>
    <div :class="{yukari: isRed, suka: !isRed}"></div>
  </div>
</template>

<script>
export default {
  data(){
    return {
      isRed: true
    }
  }
}
</script>
<template>
  <div>
    <div :class="arr"></div>
  </div>
</template>

<script>
export default {
  data(){
    return {
      arr: ['show', 'mask', 'red', 'paper']
    }
  }
}
</script>


动态绑定 style

使用 v-bind:style设置动态属性一般使用简写 :style
语法 :style="{样式名:样式值}"样式名为CSS属性的驼峰命名法

<template>
  <div>
    <h1 :style="{ fontSize: '50px', color: fontColor}">黄色的</h1>
  </div>
</template>

<script>
export default {
  data(){
    return{
      fontColor: 'yellow'
    }
  }
}
</script>

computed计算属性

计算属性必须在 computed节点中,多用于多个数据影响一个数据的场景,根据现有的数据区计算出新的数据并且有缓存,在数据不发生变化的情况下只会执行一次,数据有变化时会重新计算并缓存,写法是一个函数,一定需要返回值是最终值

示例翻转字符串:

<template>
  <div>
    <h1>{{reverseStr}}</h1>
  </div>
</template>

<script>
export default {
  data(){
    return{
      uname: 'MikanpaperYuzu'
    }
  },
  computed: {
    reverseStr(){
      return this.uname.split('').reverse().join('')
    }
  }
}
</script>

计算属性默认情况下只能获取不能修改,如果需要修改需要用到完整写法

完整写法示例:

<template>
  <div>
    <h1>计算属性的完整写法</h1>
    <h1>{{fullName}}</h1>
    <button @click="clickFn">点我</button>
  </div>
</template>

<script>
export default {
  data(){
    return{
      firstName:'Juzi',
      lastName:'You'
    }
  },
  computed: {
    fullName: {
      get(){
        return this.firstName + '-' + this.lastName
      },
      set(val){
        this.firstName = val.split('-')[0]
        this.lastName = val.split('-')[1]
      }
    }
  },
  methods: {
    clickFn(){
      this.fullName = 'MikanPaper-Yuzu'
    }
  }
}
</script>

watch属性监听

属性监听必须写在 watch节点中,只要监听的属性值发生了变化就会执行,多用于一个属性影响多个属性的场景,没有缓存但是可以异步,简单写法无法监听复杂类型的写法,需要使用完整写法监听复杂数据类型

watch: {
  监听的属性 (变化后的值, 变化前的值) {
  }
}

示例:

<template>
  <div>
    <h2>{{ uname }}</h2>
    <button @click="uname = 'MikanpaperYuzu'">给我变</button>
  </div>
</template>

<script>
export default {
  data(){
    return{
      uname: 'JuziYou'
    }
  },
  watch:{
    uname(newVal, oldVal){
      console.log('魔法少女 ' + oldVal + ' 变 ' + newVal);
    }
  }
}
</script>
动态属性是一个对象的形式
immediate: true代表一进入页面立即执行
deep: true代表升读监听可以监听到复杂数据类型内部的变化
handler(){}每次变化时触发的函数

watch: {
  接听的属性:{
    immediate: true, //代表一进入页面立即执行
    deep: true,      // 代表升读监听可以监听到复杂数据类型内部的变化
    handler(){       // handler 是每次变化时触发的函数
    }
  }
}

示例:

<template>
  <div>
    <h2>{{ obj.uname }}</h2>
    <button @click="mya">给我变</button>
  </div>
</template>

<script>
export default {
  data(){
    return{
      obj: {
        uname : 'JuziYou'
      }
    }
  },
  watch: {
    obj:{
      immediate: true,
      deep: true,
      handler(){
        console.log("变了喵");
      }
    }
  },
  methods: {
    mya(){
      this.obj.uname = "MikanpaperYuzu"
    }
  }
}
</script>


组件基础

引入组件

组件分为全局引入和局部引入,一般使用大驼峰命名法,除了驼峰, 如果使用小写还可以使用 -转换链接不同的单词,如一个注册组件名为 <JuziYou />可以直接使用转换连接 <juzi-you />也能解析到父组件。如果标签没有内容可以直接使用自结束标签

局部引入

局部引入将组件注册在当前Vue文件,只可以用在这个Vue文件中。
使用 import 组件对象 from 'Vue文件路径'引入组件
然后 components: { 组件名: 组件对象 }注册组件
示例:

<template>
  <div id="app">
    <Pannel />
  </div>
</template>

<script>
import PannelLoc from './components/Pannel.vue'
export default {
  components: { Pannel: PannelLoc }
}
</script>
<template>
  <div>
    <h1>Nya</h1>
  </div>
</template>

全局引入

全局引入在 main.js引入组件并使用,注册在全局整个项目中都可以使用
使用 import 组件对象 from 'Vue文件路径'引入组件
然后 Vue.component("组件名", 组件对象)注册组件

示例:

import Vue from 'vue'
import App from './App.vue'

// 引入组件
import Pannel from "./components/Pannel";
// 全局注册
Vue.component('PannelGol', Pannel)

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
}).$mount('#app')
<template>
  <div>
    <h1>Nya</h1>
  </div>
</template>
<template>
  <div>
    <PannelGol></PannelGol>
  </div>
</template>


组件样式 scoped

吧样式只应用于当前组件,给组件的 <style>加上 scoped会给这个组件的所有元素添加自定义属性,以及当前组件的CSS添加交集选择器,只有这个自定义属性的标签才能被样式选中

示例:

<template>
  <div>
    <h1>MikanpaperYuzu</h1>
    <ChildOne />
  </div>
</template>

<script>
import ChildOne from './components/ChildOne.vue'
export default {
  components: {
    ChildOne
  }
}
</script>

<style>

</style>
<template>
  <div>
    <h1>JuziYou</h1>
  </div>
</template>

<script>
export default {

}
</script>
<style scoped>
h1{
  color: orange
}
</style>


组件 name属性

一般使用一些框架会用到,以保证框架的命名风格所以懒得写太清楚(((
示例:

<template>
  <div>
    <JuziYou />
  </div>
</template>

<script>
import ChildCom from './components/ChildCom.vue'
export default {
  components:{
    [ChildCom.name]: ChildCom
  }
}
</script>
<template>
  <div>
    <p>JuziYou</p>
  </div>
</template>

<script>
export default {
  name:'JuziYou'
}
</script>


父向子通讯

在父组件的子组件标签上添加自定义属性,然后在子组件使用 props接收
注: 子组件不能修改父组件传来的 props

示例:

<template>
  <div>
    <MyProduct title="勾勾果" price="200" intro="蒙德产勾勾果" />
    <MyProduct title="甜甜花" price="100" intro="蒙德产甜甜花" />
  </div>
</template>

<script>
// 定义局部变量
import MyProduct from './components/MyProduct.vue'
export default {
  components: {
    MyProduct,
  }
}
</script>
<template>
  <div>
    <h3>标题: {{ title }}</h3>
    <p>价格: {{ price }}元</p>
    <p>{{ intro }}</p>
  </div>
</template>

<script>
export default
  props: ['title','price','intro']
}
</script>


子向父通讯

在父组件的标签上设置自定义事件组件 @事件名="方法名",然后在子组件中使用 this.$emit(事件名, 传给父元素的值)触发自定义事件,$emit第二个值之后为返回给父元素的值,在父亲元素接收的方法中对应形参

示例:

<template>
  <div>
    <MyProduct
        :title="list.title"
        :price="list.price"
        :intro="list.intro"
        @upMora="upFn"
    />
  </div>
</template>

<script>
// 定义局部变量
import MyProduct from './components/MyProduct.vue'
export default {
  components: {
    MyProduct,
  }
  data() {
    return {
      list:{
        title: '勾勾果'
        price: '200'
        intro: '蒙德产勾勾果'
      }
    }
  },
  methods: {
    upFn(num){
      this.list.price = num
    }
  }
}
</script>
<template>
  <div>
    <h3>标题: {{ title }}</h3>
    <p>价格: {{ price }}元</p>
    <p>{{ intro }}</p>
    <button @click="$emit('upMora', 1000)">价格改为1000元</button>
  </div>
</template>

<script>
export default
  props: ['title','price','intro']
}
</script>

props校验

校验父模块向子模块传来的数据是否符合需求

key是接收值名称,value是接收的类型

export default {
    props:{
        user:String
    }
}
如果需要多个类型,key是接收者名称,value设置为接收的类型数组

export default {
    props:{
        age: [String, Number]
    }
}
如果设置为必传参数将使用完整写法写为对象的形式,type表示接收的类型,required: true来打开必传

export default {
    props:{
        gender:{
          type: String,
          required: true
        }
    }
}
如果设置默认值将使用完整写法写为对象的形式,type表示接收的类型,default: 值来设置默认值

export default {
    props:{
        salary:{
          type: String,
          default: 'JuziYou'
        }
    }
}
如果设置自定义校验规则将使用完整写法写为对象的形式,type表示接收的类型,使用 validator(传过来的值){}return出来的值 truefalse来校验通过或不通过,如果 returnfalse将会在控制台打印错误

export default {
    props:{
        // 检测传入 list 是否 length 大于 3
        list: {
          type: Array,
          validator(val){
            if(val.length >= 3){
              return true
            }
            return false
          }
        }
    }
}

.sync修饰符

可以让繁琐的父子通讯变得简单在使用.sync修饰符后在子组价使用 update:自定义变量 来更改父组件变量绑定的值就可以完成父子组件的通讯,相当于在父组件的标签上添加了@update:属性名=" 变量名 = $event"$event 是默认参数

<template>
  <div>
    <SyncUpdate :text.sync="name"/>
  </div>
</template>

<script>
import SyncUpdate from '@/components/sync-update.vue'
export default {
  components:{
    SyncUpdate
  },
  data () {
    return {
      name: 'Mikanpapre'
    }
  }
}
</script>
<template>
  <div>
    <div>{{ text }}</div>
    <!-- 使用 update:自定义变量 来更改父组件变量绑定的值 -->
    <button @click="$emit('update:text', 'Nya')">戳戳</button>
  </div>
</template>

<script>
export default {
  props: ['text']
}
</script>

$parent

$parent可以在子组件获取到父组件的实例


事件总线 EventBus

如果两个子组件通过父组件进行通讯会非常复杂,通过一个空的Vue对象当作事件总线常用于跨组件通讯的通用方案,在组件A使用 EventBus.$emit('事件名', 值)触发事件,在组件B使用 EventBus.$on('事件名', 函数体)监听事件

使用 import Vue from 'vue'引入Vue
使用 export default new Vue()对外暴露一个Vue实例

import Vue from 'vue'
export default new Vue()
组件A触发事件

<template>
  <div>我是A
  <button @click='clickfn'>戳</button>
  </div>
</template>

<script>
import EventBus from '../EventBus'
export default {
  methods:{
    clickfn(){
      EventBus.$emit('mikan')
    }
  } 
}
</script>
组件B监听事件,created()在事件创建时就执行

<template>
  <div>我是B</div>
</template>

<script>
import EventBus from '../EventBus'
export default {
    created(){
      EventBus.$on('mikan', ()=>{
        console.log('喵');
      })
    }
  
}
</script>
APP.vue导入两个组件并使用

<template>
  <div>
    <h1>EventBus</h1>
    <ChildA/>
    <ChildB/>
  </div>
</template>

<script>
import ChildA from './components/ChildA.vue'
import ChildB from './components/ChildB.vue'
export default {
  components: {
    ChildA,
    ChildB
  }
}
</script>


ref$refs

ref$refs通常用于获取元素DOM或组件示例,将会挂载到 $refs的组件对象内

获取DOM

在需要获取的DOM元素上 ref="值"然后在 $refs.值使用

<template>
  <div>
    <div ref="juziyou">JuziYou</div>
    <button @click="clickFn">Click</button>
  </div>
</template>

<script>
export default {
  methods:{
    clickFn(){
      console.log(this.$refs.juziyou)
    }
  }
}
</script>

获取组件实例

在需要获取的组件自定义标签上 ref="值"然后在 $refs.值使用

<template>
  <div>
    <ChildB ref="childRef"/>
    <button @click="childRefFn">Click</button>
  </div>
</template>

<script>
import ChildB from './components/ChildB.vue'
export default {
  components:{
    ChildB
  },
  methods:{
    childRefFn(){
      console.log(this.$refs.childRef.uname)
      this.$refs.childRef.logName()
    }
  }
}
</script>
<template>
  <div>
    ChildB
  </div>
</template>

<script>
export default {
  data(){
      return{
          uname: 'JuziYou',
      }
  },
  methods:{
      logName(){
          console.log(this.uname)
      }
  }
}
</script>


$nextTick

由于Vue更新DOM是异步的,会导致需要在DOM更新之后的代码会被先执行,所以需要使用 $nextTick
$nextTick接收一个函数作为参数,接收的函数将会在DOM更新后执行

如在点击按钮后显示输入框然后获取输入框的DOM:

<template>
  <div>
    <input type="text" ref="ipt" v-if="isShowInput">
    <button @click="fn" v-else>Click</button>
  </div>
 </template>

<script>
export default {
  data () {
    return {
      isShowInput: false
    }
  },
  methods: {
    fn () {
      this.isShowInput = true
      this.$nextTick(()=>{
        console.log(this.$refs.ipt);
      })
    }
  }
}
</script>

component动态渲染组件

component是Vue内置的一个组件用于动态的渲染组件,:is="值"的值是什么就会渲染哪个子组件

<template>
  <div>
    <button @click="comName = 'ChildA'">ChildA</button>
    <button @click="comName = 'ChildB'">ChildB</button>
    <component :is="comName"></component>
  </div>
</template>

<script>
import ChildA from './components/ChildA.vue'
import ChildB from './components/ChildB.vue'
export default {
  components:{
    ChildA,
    ChildB
  },
  data(){
    return{
      comName: 'ChildA'
    }
  }
}
</script>
<template>
  <div>
    <h1>ChildA</h1>
  </div>
</template>
<template>
  <div>
    <h1>ChildB</h1>
  </div>
</template>


自定义指令

自定义指令分为全局和局部注册,在标签上 v-自定义指令名进行使用

常用的:
inserted方法绑定此指令的元素插入到DOM时执行
语法为 inserted(形参){}
inserted(形参){}第一个形参是绑定此指令的元素,第二个形参为当前自定义指令传入的值

update方法绑定此指令的元素值发生变化时执行
语法为 update(形参){}
update(形参){}第一个形参是绑定此指令的元素,第二个形参为当前自定义指令传入的值

main.js内添加 Vue.directive进行全局注册
语法为 Vue.directive('指令名',{方法})

示例:在input标签创建时自动落焦

Vue.directive('focusglo', {
  inserted(el){
    el.focus()
  }
})
在组件的 export default内使用 directives{对象}进行局部注册,注册的自定义指令只能在当前组件使用

示例:如 color的值发生变化时重新设置使用了此自定义指令的元素的颜色

export default {
  data () {
    return {
      color: 'orange'
    }
  }
  directives: {
    zy:{
      inserted(el,binding){
        el.style.color = binding.value
      },
      update(el,binding){
        el.style.color = binding.value
      }
    }
  }
}


插槽

插槽插在父组件的两个起始标签和结束标签之间,默认会放到默认 <slot>插槽内
<template>中使用指令 v-slot:插槽名来使用指定的插槽,也可以用 #插槽名来简写,在子组件内的 <slot>通过 name="插槽名"变量的方式来设置插槽名
默认插槽可以使用 <template v-slot="变量名"></template >"来接收传过来的参数,具名插槽可以之间加上等号变量名来接收传过来的的参数 <template v-slot:插槽名="变量名"></template >",在子组件内的 <slot>通过添加自定义变量名的方式来传参

<template>
  <div>
    <!-- 使用組件時在父組件的兩個標簽之間插入 -->
    <MyDialog>
      <img src="https://lovemen.cc/usr/hotlink-ok/avatar.jpg" alt="">
    </MyDialog>
    <MyDialog>
      <!-- <template v-slot:footer> 指定插入footer插槽 v-slot:插槽name -->
      <!-- 在具名插槽下直接加上等號就可以接收,可以在等號内直接解構賦值 -->
      <template v-slot:footer="{yes:okay,no}">
        <button>{{ okay }}</button>
        <button>{{ no }}</button>
      </template>
        <!-- 可以使用#簡寫 -->
      <template #header>
        <h3>溫馨提示</h3>
      </template>
      <!-- 默認插槽透過v-slot="變量名"接收傳過來的,將以對象形式呈現,只能在template内使用 -->
      <template v-slot="obj">
        {{obj}}
        <p>你好,買?</p>
      </template>
    </MyDialog>
  </div>
</template>

<script>
import MyDialog from './components/MyDialog.vue'
export default {
  components:{
    MyDialog
  }
}
</script>
<template>
  <div class="my-dialog">
    <div class="header">
      <slot name="header"></slot>
    </div>
    <div class="content">
      <!-- slot表示此處有一個插槽 -->
      <!-- 作用域插槽:通過插槽設置自定義參數傳數據 -->
      <slot uname="MikanpapreYuzu" age="18"></slot>
    </div>
    <div class="footer">
      <!-- name給插槽起名 -->
      <slot name="footer" yes="好捏" no="打咩"></slot>
    </div>
  </div>
</template>

<script>
export default {

}
</script>

<style lang="less" scoped>
.my-dialog {
  width: 400px;
  padding: 10px 20px;
  border: 3px solid #000;
  border-radius: 5px;
  margin: 10px;
}
</style>


路由

npm默认获取的 vue-router版本为4,在Vue2中需要 vue-router版本为3时才可以使用,所以在Vue2中需要 @3指定 vue-router安装版本

npm i [email protected]

路由就是路径和组件间的关系,创建路由的方式有在 main.js创建路由和创建 router文件夹在 index.js中创建路由

main.js创建路由

先在 main.js内使用 import VueRouter from 'vue-router'引入 vue-router,然后使用 Vue.use(VueRouter)让Vue使用 vue-router插件 const router = new VueRouter(对象)创建一个路由实例,在对象内添加一个 routes数组,这个数组内每个对象都是一个匹配规则,import RouterPage from '@/views/RouterPage'引入组件,router内的对象 path为设置路由的路径 component为设置路由指向的组件,最后在 new Vue内添加const出来的变量名关联到Vue实例,匹配到的组件会在 <router-view></router-view>渲染

import Vue from 'vue'
import App from './App.vue'
import My from '@/views/My'
import Part from '@/views/Part'

// 5 引入组件
import RouterPage from '@/views/RouterPage'
// 1引入vue-router
import VueRouter from 'vue-router'
// 2让Vue使用vue-router插件
Vue.use(VueRouter)
// 3创建路由实例
const router = new VueRouter({
  // 6 routes 是一个数组,此数组里面的每一个对象都是一个匹配规则
  routes:[
    {
      // 7设置路由路径
      path:'/RouterPage',
      // 8 给路径指向组件
      component: RouterPage
    }
  ]
})

Vue.config.productionTip = false

//4 吧路由实例关联router到vue实例
new Vue({
  router,
  render: h => h(App),
}).$mount('#app')
<template>
  <div>
    <h1>RouterPage</h1>
  </div>
</template>
<template>
  <div>
    <a href="#/RouterPage"></a>
    <div>
      <router-view></router-view>
    </div>
  </div>
</template>

router文件夹中的 index.js创建路由

main.js中创建路由不太好,应该每个模块干每个模块的事情
src中创建 router文件夹然后在文件夹中创建 index.js,首先在 index.js中使用 import Vue from 'vue'引入Vue,然后使用 import VueRouter from 'vue-router'引入 vue-router,接着使用 Vue.use(VueRouter)让Vue使用 vue-router插件,使用 const router = new VueRouter(对象)创建一个路由实例,在对象内添加一个 routes数组,这个数组内每个对象都是一个匹配规则,import RouterPage from '@/views/RouterPage'引入组件,router内的对象 path为设置路由的路径 component为设置路由指向的组件,export default routerindex.js对外暴露 router实例,最后在 main.js中使用 import router from '@/router/index.js'引入路由实例再在 new Vue中关联引入的实例 router到Vue实例,匹配到的组件会在 <router-view></router-view>渲染

// 1 引入Vue
import Vue from 'vue'
// 5 引入组件
import RouterPage from '@/views/RouterPage'
// 2 引入vue-router
import VueRouter from 'vue-router'
// 3 让Vue使用vue-router插件
Vue.use(VueRouter)
// 4 创建路由实例
const router = new VueRouter({
  // 6 routes 是一个数组,此数组里面的每一个对象都是一个匹配规则
  routes:[
    {
      // 7设置路由路径
      path:'/RouterPage',
      // 8 给路径指向组件
      component: RouterPage,
    }
  ]
})

// 对外暴露路由实例对象
export default router
import Vue from 'vue'
import App from './App.vue'

// 引入路由实例
import router from '@/router/index.js'

Vue.config.productionTip = false

//4 吧路由实例关联router到vue实例
new Vue({
  router,
  render: h => h(App),
}).$mount('#app')
<template>
  <div>
    <h1>RouterPage</h1>
  </div>
</template>
<template>
  <div>
    <a href="#/RouterPage"></a>
    <div>
      <router-view></router-view>
    </div>
  </div>
</template>

查询字符串传参

to="path"的path后面加 ?查询字符串的方式传参,然后在组件内使用 $route.query接收参数会以一个对象的形式接收

比如 <router-link to="/part?uname=JuziYou&ocname=MikanpaperYuzi">橘纸柚</router-link>,在组件内 $route.query将会收到一个对象 {uname:'JuziYou', ocname'MikanpaperYuzi'}

动态路由传参

首先在对应的路径复制一份然后在path中的路由加上 /:参数名,然后在组件内使用 $route.params接收参数会以一个对象的形式接收

比如:
一个路由为 /user需要接收一个参数名为 uname(.....省略后面或者前面代码)

..... = new VueRouter({
  routes:[
  .....
  .....
    {
      path:'/user',
      redirect: 'User' 
    },
    {
      path:'/user/:uname',
      redirect: 'User' 
    },
  .....

然后访问比如 localhost:8080/#/user/juziyou,在组件内使用 $route.params将会获取到一个对象 {uname:'juziyou'}

路由重定向以及默认页(404)

在路由实例的 routes中起始位子添加一个匹配规则,匹配规则中 redirect为重定向的路径

如从 /重定向到 /juziyou(.....省略后面或者前面代码)

..... = new VueRouter({
  routes:[
    {
      path:'/',
      redirect: '/juziyou' 
    },
  .....

默认页则在路由实例的 routes中的末尾添加一个 path为通配符 *的一个规则

如前面一个规则也没匹配上返回一个 NotFund页面(.....省略后面或者前面代码)

..... = new VueRouter({
  routes:[
  .....
  .....
    {
      path:'*',
      redirect: 'NotFund' 
    },
  .....

mode 与 base

mode写在路由的实例中有个常用的参数 hashhistoryhash会在URL中添加#号,history则不会但是需要后端配合因为会向服务器发送真实路径。
以及可以通过 base 设置基础地址,比如要访问 /user 页面在 hash 模式下是 /#/user 如果在 history 模式下设置了 base/juzi/ 地址就是 /juzi/user

如修改 modehistory(.....省略后面或者前面代码)

..... = new VueRouter({
  mode: 'history',
  base: '/juzi/'
  .....

router-link声明式导航

声明式导航 router-linkvue-router提供的一个全局组件,使用 to="path"来跳转路由路径
会给选中的路由自动的加上class类名,其分为模糊匹配类名和精确匹配类名,可以在路由实例内通过 linkActiveClas修改模糊匹配类名以及通过 linkExactActiveClass修改精确匹配类名

如通过 router-link转到path /routerpage

<router-link to="/routerpage"></router-link>

如需要修改精确匹配类名为:juzi,模糊匹配类名为:you在路由实例内设置的方式(.....省略后面或者前面代码)

...... = new VueRouter({
  linkActiveClass:'you',
  linkExactActiveClass:'juzi',
  ......

编程式传参

通过调用函数的方式使用方法 $router.push,使用 path无法使用 params传参所以推荐使用 name来进行跳转

name

在路由配置中添加 name属性,在编程式导航中如果需要使用 params就得用 name来跳转

全局守卫

所有的路由一旦匹配到规则在真正渲染解析前都会经过全局守卫,只有在全局守卫放行后才能真正渲染页面
在创建实例前先声明一个白名单变量或常量,吧路由(path)以字符串的形式储存在数组中,然后使用router.beforeEach(回调函数)创建路由守卫,在路由解析访问之前都会经过回调函数,回调函数中有三个形参from从哪里来的路由信息对象、to要到那里去的路由信息对象、next是否放行这是一个方法,如果next()表示放行去的页面、next(路径)则表示拦截到的页面,使用whiteList.includes来匹配是否处于白名单

如验证用户是否登录

// 设置白名单
const whiteList = ['/login', '/regisrer']
router.beforeEach((to, from, next) => {
  // 如果有token就放行
  if (this.token) {
    next()
  } else {
    // 如果没有token检查是不是去白名单页面
    if (whiteList.includes(to.path)) {
      // 如果是去白名单直接放行
      next()
    } else {
      // 如果不是去白名单跳转到登录
      next('/login')
    }
  }
})

生命周期

生命周期是Vue组件创建到销毁的过程
在特定的时间点执行特定的操作
分四大阶段,八个方法
官方文档

初始化

beforeCreate在组件创建之前会被调用,此状态下无法获取自定义的数据,比如 data中的数据
created会在初始化数据并当前实例代理了数据后执行,一般会在此生命周期钩子中请求服务器数据

挂载

beforeMount无法获取到DOM元素因为这个时候还是虚拟DOM
mounted中就可以获取到真实DOM了

更新

beforeUpdate在页面使用中的数据发生变时虚拟DOM更新之前运行
updated在使用中的数据发生变化时虚拟DOM更新到页面后运行

销毁

beforeDestroy在销毁前运行,一般用来解绑一些事件,比如说定时器
destroyed咋子销毁后运行

keep-alive缓存

<keep-alive>是Vue内置的全局组件可以吧组件缓存到内存中,使用<keep-alive>被缓存的组件有两个生命周期activated组件被激活deactivated组件被隐藏


vuex

vuex是vue的一个状态(数据)管理工具(也是插件),方便的解决多组件的共享状态,拥有响应式、操作简洁的优势
一般情况下多组件的数据共享会存在vuex中

创建仓库

一般为了维护项目的目录整洁会在src目录下新建store目录放置index.js
首先在创建Vuex实例然后再在main.js中导入挂载到Vue实例上
Vuex.Store()括号内是一个对象

// 引入Vue
import Vue from 'vue'
// 引入Vuex
import Vuex from 'vuex'
// 注册vuex插件
Vue.use(Vuex)
// 创建仓库实例
const store = new Vuex.Store()
// 导出仓库
export default store
import Vue from 'vue'
import App from './App.vue'
// 引入store
import store from '@/store'

Vue.config.productionTip = false

new Vue({
  // 挂载到 Vue 实例
  store,
  render: h => h(App)
}).$mount('#app')

state

state提供唯一的公共数据源,所有的共享数据需要放到state中储存,可以在任何组件中使用$store.state.键来获取state中的数据也可以通过mapState()映射到computed

import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)

const store = new Vuex.Store({
  // 设置 State
  state:{
    uname: 'JuziYou',
    age: 18
  }
})
export default store
<template>
  <div>
    <!-- 直接使用 $store.state.uname 获取 uname 的值 -->
    <p>{{ $store.state.uname }}</p>
    <!-- 直接使用映射计算属性得到的值 -->
    <p>{{ age }}</p>
  </div>
</template>

<script>
// 引入 mapState 
import { mapState } from 'vuex'
export default {
  computed:{
    // mapState() 得到的是一个数组中对应的对象可以使用 ... 展开运算符展开到计算属性中
    ...mapState(['age'])
  }
}
</script>

mutation

state中的数据只能通过mutation修改,用于父组件需要修改仓库中的数据
在vuex实例中定义mutation,它是一个对象里面存储修改state的方法,每个方法的第一个形参是当前仓库的state,第二个是传入的参数
可以通过$store.commit('方法', 传参)来调用mutation中的方法,传参只能传一个参数如果需要传多个使用复杂数据类型来完成,比如说对象
还可以通过辅助函数mapMutations(数组)的方式使用展开运算符映射到methods中,需要使用this.方法来调用,使用起来和mapState()很像

actions

actions负责仓库内的异步操作,mutation只能用于同步更新数据
在vuex实例中定义actions,它是一个对象里面存储异步的方法,每个方法的第一个形参拥有仓库实例的所有属性和方法,第二个是传入的参数传参只能传一个参数如果需要传多个使用复杂数据类型来完成,比如说对象
可以通过$store.dispatch('方法', 传参)来调用
也可以通过辅助函数mapActions(数组)来调用使用展开运算符映射到methods

getters

getters使用仓库state中现有的数据计算出新的数据
在vuex实例中定义getters,每个方法的第一个形参是当前仓库的state,必须要有返回值
可以通过$store.getters.方法来调用
也可以通过辅助函数mapGetters(数组)的方式使用展开运算符映射到computed

module 模块

如果使用单一的index.js项目大后应用会变得非常复杂相对臃肿
store文件夹中创建一个用于存放模块的文件夹,export default向外暴露键statemutationsactionsgetters值就是它们所需要的值,访问模块中的数据可以直接通过$store.state.模块名.数据键来访问mutationsactionsgetters默认情况下全局可以调用,然后在index.js中引入模块并在modules中注册,组件的state以对象的形式挂载到state`下

export default {
  state: {},
  mutations: {},
  actions: {},
  getters: {}
}
import Vue from 'vue'
import Vuex from 'vuex'
// 引入子模块
import data from '@/store/data'
Vue.use(Vuex)
const store = new Vuex.Store({
  // 使用modules来引入子模块
  // 会将挂载组件的state以对象的形式挂载到state下
  modules:{
    data
  },
})

namespaced 命名空间

开启命名空间后子模块的mutations、actions、getters就不会注册在仓库全局,在子模块的export default中添加namespaced: true,开启后$store访问模块内的方法需要模块名/函数名
辅助函数需要在数组前增加模块名如mapState(模块名, 数组),然后通过this.方法来调用
辅助函数还可以通过加/的方式来使用(如mapState(['模块名/方法名']),在调用方法时得this[模块名/方法名]()来调用

export default {
  namespaced: true,
}

createNamespacedHelpers

createNamespacedHelpers辅助函数会返回一个对象里有mapActionsmapGettersmapMutationsmapState通过解构赋值和重命名的方式来提取映射

export default {
  namespaced: true,
  state: {
    uname: 'JuziYou'
  },
  mutations: {
    updateName (state, payload) {
      state.uname = payload
    }
  }
}
import Vue from 'vue'
import Vuex from 'vuex'
import datas from '@/store/modules/datas'
Vue.use(Vuex)
const store = new Vuex.Store({
  state: {
  },
  mutations: {
  },
  actions: {
  },
  getters: {
  },
  modules: {
    datas
  }
})

export default store
<template>
  <div>
    <div>{{ $store.state.datas.uname }}</div>
    <button @click="updateUname">Mikanpapre</button>
  </div>
</template>

<script>
import { createNamespacedHelpers } from 'vuex'
const { mapMutations: userMapMutations } = createNamespacedHelpers('datas')
export default {
  methods: {
    ...userMapMutations(['updateName']),
    updateUname () {
      this.updateName('Mikanpapre')
    }
  }
}


归档 文章二维码
本页链接的二维码
打赏二维码

博客环境损坏新增评论暂不可用