欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

荐 Vue高级

程序员文章站 2022-03-03 19:45:19
vue核心1.计算属性 computedcomputed计算属性:Vue本身支持模板中使用复杂表达式表现业务数据,但是这会使得模板内容过于杂乱,如果确有需求,可以通过computed计算属性实现,该computed可以对其他data做复杂合成处理语法:new Vue({ computed:{ // 属性名称:function(){} 属性名称(){ // 业务表达式实现,可以通过this操作data成员 return 返回结果 } }})...

vue核心

1.计算属性 computed

computed计算属性

Vue本身支持模板中使用复杂表达式表现业务数据,但是这会使得模板内容过于杂乱,如果确有需求,可以通过computed计算属性实现,该computed可以对其他data做复杂合成处理

语法

new Vue({
  computed:{
    // 属性名称:function(){}
    属性名称(){
      // 业务表达式实现,可以通过this操作data成员
      return  返回结果
    }
  }
})

计算属性(普通函数赋值)或(简易成员函数赋值) 都可以,不要使用箭头函数

使用

形式上,如何应用data成员,就如何应用计算属性,与使用data样子一致

{{ computed计算属性名称 }}       <!--模板中-->
this.computed计算属性名称	       <!-- Vue实例内部-->

应用场景

如果页面需要访问一个数据,这个数据比较复杂,是需要通过其他data数据经过复杂逻辑制作出来的,就可以使用“计算属性”

特点

  1. 计算属性关联的data如果发生变化,会重新编译执行,获得并使用对应新结果,即响应式(入口)
  2. 计算属性的返回信息有变化,使用的地方也会重新编译执行,存在出口响应式
  3. 计算属性内部可以使用this关键字,与Vue对象等效
  4. 每个计算属性都需要通过return关键字返回处理结果

computed计算属性与methods方法的区别

  1. computed计算属性本身有“缓存”,在关联的data没有变化的情况下,后续会使用缓存结果,节省资源

    methods方法没有缓存,每次访问方法体都需要重新加载执行,耗费资源

  2. methods应用逻辑较复杂,例如内部可以嵌入ajax,或互相调用,而computed比较纯粹,只是操作data的

在Vue实例内部创建计算属性与el、data、methods并列位置处

2.过滤器 filters

过滤器

在项目应用中,同样一份数据信息,表现形式却有千差万别,例如时间信息可以是对象、时间戳、格式化等,字符串可以是大写的、小写的、首字母大写的等等,如果提供方给我们提供的信息是其中一种形式,而我们需要的是另一种,在Vue中,可以通过 “过滤器” 转换处理。

过滤器是Vue中实现数据格式转换的一种机制。本质就是函数

如下时间信息通过 对象形式 或 时间戳方式显示都不合适,但是变为格式化时间就比较友好

Thu Mar 21 2019 17:48:17 GMT+0800     =>   2019-03-21 17:48:17

1553161717	     					  =>   2019-03-21 17:48:17

过滤器关键字:filterfilters

2.1私有过滤器

私有过滤器声明语法

Vue实例化过程中,与el、data平行的位置声明filters成员并在其中制作过滤器,这个过滤器只能被当前Vue实例使用,称为 “私有过滤器”

new Vue({
  filters:{
    // 如下方法格式是es6简易设置方式,完整写法: 过滤器名称:function(被处理数据){}
    过滤器名称(被处理的数据){
      // 对数据进行加工处理
      return 结果
    },
  }
})

使用

{{ 应用数据 | 过滤器名称 }}

过滤器被设置到应用数据的尾部,通过 “|竖线” 连接

注意

  1. 过滤器只可以用在两个地方: 插值表达式:冒号 属性绑定表达式
  1. 插值表达式: {{ 数据 | 过滤器 }}

  2. v-bind属性绑定中使用: <标签 :属性=“数据 | 过滤器">

  1. 过滤器不让使用this关键字,或者this关键字不是“Vue实例”
  2. 过滤器需要return返回数据处理后的结果

案例应用

给时间信息做格式化处理,利用过滤器实现对象时间转换为格式化时间

<td>{{ item.time | timeFMT }}</td>

过滤器:

// 注册过滤器【私有的】
filters:{
  // timeFMT:function(){}
  timeFMT(origin){
    var tm = new Date(origin)   // 根据origin重新实例化一个时间对象
    var yyyy = tm.getFullYear()
    var mm = (tm.getMonth()+1).toString().padStart(2,0)
    var dd = tm.getDate().toString().padStart(2,0)

    var hh = tm.getHours().toString().padStart(2,0)
    var ii = tm.getMinutes().toString().padStart(2,0)
    var ss = tm.getSeconds().toString().padStart(2,0)

    return `${yyyy}-${mm}-${dd} ${hh}:${ii}:${ss}`
  }
},

设置字符串以指定的位数输出,不够就在字符串前边补位

// 字符串.padStart(位数,补位信息)
'hello'.padStart(8,0)      // 000hello

2.2全局过滤器

全局过滤器

​ 在new Vue()前边,直接给Vue调用filter声明的过滤器称为“全局过滤器”

​ 全局的意思是过滤器可以供所有Vue实例使用

Vue.filter(名称, function(被处理的数据){return xx})
var vm = new Vue()
var vm2 = new Vue()

全局和私有取舍

理论上,多个Vue实例都需要使用的过滤器声明为全局的,只是当前Vue实例使用的过滤器声明为私有的

实际情况:私有的用的更多

注意

  1. 全局过滤器需要在new Vue()之前声明
  2. 多个过滤器可以被同时使用, {{ 信息 | 过滤器 | 过滤器 | 过滤器 … }},形成一个信息被多次处理效果

3.axios

axios是对ajax封装的一个产品,向服务器发送请求,获取数据

获取

访问npm官网:https://www.npmjs.com/ 搜索axios即可

axios获取3种方式:

  1. 直接下载源文件 (推荐)
  2. 通过script标签引入,需要上网环境
  3. npm install axios

使用

axios可以发送各种请求

axios.get('请求地址', {params:{name:value,name:value...}})

axios.post('请求地址', {name:value,name:value...})

axios({
  method:'get/post',
  url:请求地址,
  params:{},     // 传递get参数信息
  data:{}        // 传递post参数信息
})

注意

  1. get()方法如果传递参数需要额外设置params,post()方法则不用
  2. axios调用任何方法返回结果都是Promise对象

给axios配置公共根地址

给axios把各个请求都需要使用的相同的根地址做统一配置,使得相同代码只维护一份,提升开发速度

axios.defaults.baseURL = 公共根地址

把axios配置成为Vue成员

在Vue的大环境中不要直接使用axios,要把axios配置成为Vue的成员,通过Vue对象调用

把axios配置为 Vue构造器原型继承的成员,这样 vue实例对象就可以调用了

// 原型继承成员名称为 $http ,也可以配置为其他名称
Vue.prototype.$http = axios


// vue实例中使用axios
this.$http({url:xx, method:xx})

Vue中所有的内容都通过自身调用,开发、维护比较方便

3.1拦截器-interceptors

拦截器

​ 拦截器是axios向服务器端发送请求响应回来所经历的两道关口

axios本身有两种拦截器:请求拦截响应拦截

  • 请求拦截器:

    axios每次开始请求的时候先执行此处逻辑,在这个地方可以给axios做出发前的配置,也可以做出发前的检查工作,检查ok的情况下就开始向服务器端发请求

  • 响应拦截器:

    axios完成与服务器端交互回到客户端后就执行此处逻辑,在这个地方可以做一些后续收尾事宜,例如判断axios请求是否成功,或相关数据过滤操作

拦截器关键字:interceptors

请求拦截器

// 请求拦截器
axios.interceptors.request.use(function (config) {
  // 放置业务逻辑代码
  return config;
}, function (error) {
  // axios发生错误的处理
  return Promise.reject(error);
});

响应拦截器

// 响应拦截器
axios.interceptors.response.use(function (response) {
  // 放置业务逻辑代码
  // response是服务器端返回来的数据信息,与Promise获得数据一致
  return response;
}, function (error) {
  // axios请求服务器端发生错误的处理
  return Promise.reject(error);
});

把以上拦截器代码设置好,那么axios"所有"的请求就都会执行了

拦截器细节

​ 知道config参数 和 Promise.reject(error) 分别代表的意思

axios.interceptors.request.use(function (config) {
  return config;
}, function (error) {
  return Promise.reject(error);
});

axios.interceptors.response.use(function (response) {
  return response;
}, function (error) {
  return Promise.reject(error);
});
  1. config参数

    config是一个对象 与 axios.defaults 相当(不等于)

    config可以给axios配置例如baseURL的信息的

  2. response参数

    服务器端给返回的具体数据信息,与业务axios接收的数据一致

  3. Promise.reject()

    Promise.reject(data) 是 语法糖的用法,本质与下述一致,即返回一个Promise对象

    Promise.reject(data)
    上下效果一致
    new Promise(function(resolve,reject){
      reject(data)
    })
    
    Promise.resolve(data)
    上下效果一致
    new Promise(function(resolve){
      resolve(data)
    })
    

4.组件component

组件

​ 组件是拥有一定功能许多html标签的集合体,是对html标签的封装

好处

模板中为了实现一个(例如)分页效果,需要绘制20个html标签,如果使用组件,就设置一个标签就可以了,明显提升开发效率

框架

Vue:电脑端、移动端

react:电脑端、移动端

angular:电脑端、移动端

组件库

组件库针对框架、平台都有针对开发

很有名的第3方组件库(饿了么element-ui):Vue电脑端组件库 https://element.eleme.cn/#/zh-CN>

组件关键字:components、component

4.1组件内部成员

可以认为组件是一个特殊的Vue实例,拥有着与Vue实例大致相同的成员

例如 datamethodsfiltersdirectives(自定义组件)、created等等成员在组件内部都可以设置

注意

​ 组件data成员 与 Vue实例的 不一样,需要通过 function/return 设置,具体要返回一个{}对象

data(){
  return { }
}

function声明data

组件中声明的data成员,值需要是一个function,内部通过return返回{}对象供使用,这个特性必须遵守

组件的data必须是一个function

组件根据业务需要,可以被使用多次,function会使得每次组件使用的时候都亲自执行并给当前应用分配一个独立的数据对象,这样多个组件的data数据是独立的,互相没有关联、牵扯,互相不会覆盖

​ 相反,如果直接通过{}对象 给data赋值,多次使用组件会造成大家的data都是共享的,就是一份数据,一个组件修改data后,其他组件都受到影响,这与业务逻辑是相违背的

组件与Vue实例异同

  1. 组件中的 data 必须是一个 function 并 return 一个 字面量对象
    (Vue 实例的 data 可以是 字面量对象,也可以是 function/return形式,前者推荐使用)
  2. 组件中直接通过 template 属性来指定组件的html结构
    Vue 实例中,一般通过 el 属性来指定渲染的容器,当然也可以使用template
  3. 组件和Vue实例拥有类似的成员,都有自己的生命周期函数,过滤器,methods、data等成员

4.2私有组件

声明私有组件语法

new Vue({
  components:{
    '组件的名称': { 配置对象成员 }, 
    '组件的名称': { 配置对象成员 }...
  },
})

使用组件语法

<组件名称></组件名称>

组件形式上 就是html标签

案例应用

制作一个分页组件并使用

  <div id="app">
    <h2>组件应用</h2>
    <!-- 组件的名字被当做html标签使用 -->
    <com-page></com-page>
  </div>

  <script src="./vue.js"></script>
  <script>
    var vm = new Vue({
      components:{
        'com-page':{
          // template: 设定当前组件拥有的html标签
          template:`
            <ul>
              <li>1</li>
              <li>2</li>
              <li>3</li>
            </ul>
          `
        }
      },
      el:'#app',
     });
  </script>

注意

  1. template设置的各个html标签需要有唯一的根元素节点,上例为ul
  2. 组件名称建议是 xx-yy 的格式
  3. template都必须有一个根元素节点

4.3全局组件

全局组件语法

Vue.component(名称,{配置对象成员})

new Vue()

注意

​ 1. 全局组件需要在new Vue之前设置

5.组件传值

5.1父给子传值

父组件可以 引入、使用子组件,从业务上看,该父组件有可能对子组件有个性化需求,为了体现组件的灵活多变,可以通过传值实现

语法

父组件要在子组件标签上通过属性值方式传值

<子组件标签 xx=value yy=value zz=value></子组件标签>

子组件通过props接收属性值并应用值

<!--在模板中应用传递来的数据-->
<input :style="{color:xx}">

<script>
  export default {
    // 通过props接收父传递过来的数据,注意各个名称需要使用单引号圈选
    // 具体有两种方式:
    props:['xx','yy','zz'],
    props:{
      xx:{
        type:类型限制
        default:默认值
      }
    }
  }
</script>

案例应用

​ 父组件多次使用按钮组件,每次要求按钮的文字显示不同颜色,就可以通过传值实现

父组件App.vue的代码:

<template>
    <div id="app">
      <h2>App根基组件</h2>
      <!-- 给子组件传值:通过“属性值”方式实现修饰子组件button按钮文字的颜色 -->
      <!-- 属性值来源:直接声明、组件实例data成员 -->
      <com-button yan="green"></com-button>
      <com-button yan="orange"></com-button>
      <com-button :yan="co"></com-button>
    </div>
</template>

<script>
// 对ComButton子组件到导入、注册、使用
import ComButton from '@/components/ComButton.vue'
export default {
  name: 'App',
  components: {
    ComButton
  },
  data () {
    return {
      co: 'gray'
    }
  }
}
</script>

子组件 components/ComButton.vue代码:

<template>
    <div id="btn">
      <button :style="{color:yan}">我是按钮</button>
    </div>
</template>

<script>
export default {
  name: 'Button',
  // 对父组件传递过来的数据进行接收
  // 两种方式:简单的、复杂的
  props: ['yan']
  // props: {
  //   yan: {
  //     type: String, // Boolean  Number  Object  Array
  //     default: 'pink'
  //   }
  // }
}
</script>

5.1.1子组件修改父组件传递来的数据

sync 应用(扩展)

子组件修改父组件传递来的数据

方法1:

父组件:
<com-button :yan="co"></com-button>
子组件
<button @click="yan='yellow'">修改</button>  
			// 子组件接收的yan可以被修改,但是firebug报错,说明不推荐、不允许
			虽然子组件可以修改信息,但是不推荐
      理性分析是:父组件还可以修改
      两头都修改,没有秩序了

方法2:最传统的实现子组件修改父组件传递数据的

父组件:
// 箭头函数,data就一个参数[data是自定义的],()是否设置都可以,后边语句需要设置{}
<com-button :yan="co" @xiugai="data=>{co=data}"></com-button>
子组件:
<button @click="$emit('xiugai','purple')">修改</button>

父组件声明事件,子组件调用事件修改co

父组件通过事件实现co变化,yan就变化,子组件由于响应式,yan自然发生变化

方法3:通过update:xxx的方式给子组件声明事件

父组件:
// 事件名称为 update:xxx 的格式
// xxx 就是传递给子组件的数据的名称
<com-button :yan="co" @update:yan="data=>{co=data}"></com-button>
子组件:
<button @click="$emit('update:yan','green')">修改</button>

方法4:终极版,通过.sync优化父组件的相关操作

该方法实现 子组件修改父组件传递过来的数据,最终方法

父组件:
<!-- 通过 【:yan.sync="co"】 就是对 如下内容-->
<!-- 【:yan="co" @update:yan="data=>{co=data}"】-->
<!-- 的封装-->
<com-button :yan.sync="co"  :se.sync="abc"></com-button>
子组件:
<button @click="$emit('update:yan','blue')">修改</button>

以后我们可以通过.sync设置,子组件可以修改父组件传递过来的具体数据信息

update是固定标志

.sync官网详情: https://cn.vuejs.org/v2/guide/components-custom-events.html#sync-%E4%BF%AE%E9%A5%B0%E7%AC%A6

5.2子给父传值

子组件给父组件传递数据

语法

  1. 父组件向子组件通过**@符号定义一个事件**,在本身内部methods中声明事件方法
  2. 子组件使用this.$emit()调用父组件传递过来的事件,并传递相关的数据
  3. 父组件通过事件方法参数获得子组件传递过来的数据并使用

父组件操作

父组件通过**@符号**在子组件上定义一个事件,在父组件内部methods中声明事件方法

<子组件 @func1="show"></子组件>
...
methods:{
	show(arg1,arg2){xxxx}
}

​ func1为事件的名称,给子组件触发使用

​ show为该事件的执行函数,在父组件内部的methods中定义好

​ 在事件中可以通过形参(arg1、arg2)接收子组件传递过来的数据 并做进一步处理

子组件操作

子组件中,使用this.$emit()调用父组件中的事件方法

this.$emit('func1', 数据, 数据)

// this.$emit(事件名称, 传递的数据,数据,数据……)
// 使用this.$emit调用父组件给声明的事件
// $emit可以使得组件实例“触发”本身的事件执行
// ($emit也可以触发鼠标或键盘事件执行)

第二个参数开始传递实参数据,其可以被父组件methods方法的形参所接受

$emit(名称,数据,数据……) 是组件调用自己方法的固定方式,第一个参数是被调用方法的名称,后续参数都是给方法传递的实参信息

案例应用

父组件(app.vue)代码:

<template>
  <div id="app">
    <h2>我是父组件app----{{dt}}</h2>
    <!-- 使用son子组件 -->
    <!-- 通过@符号给子组件声明一个(自定义)事件,receive事件方法在methods中设置 -->
    <com-son @jieshou="receive"></com-son>
  </div>
</template>

<script>
// 导入、注册、使用子组件
import ComSon from './components/Son.vue'
export default {
  components: {
    'com-son': ComSon
  },
  data () {
    return {
      dt: ''
    }
  },
  methods: {
    // msg可以接收到当前事件传递过来的数据
    receive (msg) {
      this.dt = msg
    }
  }
}
</script>

子组件(components/son.vue)代码:

<template>
    <div id="son">
      我是子组件son
      <button @click="huibao()">汇报学习情况</button>
    </div>
</template>

<script>
export default {
  methods: {
    huibao () {
      this.$emit('jieshou', '我们学习vue很好')
    }
  }
}
</script>

5.3兄弟组件传值

兄弟组件之间彼此没有联系,它们需要通过中间件Vue实例对象bus(快递员)进行数据传递

给组件实例(或Vue实例) 声明事件有两种方式:

  1. 直接声明
  2. 通过$on实现

给组件实例声明事件:

<组件 @事件名称="事件驱动方法"></组件>

通过**$on**进行声明:

// 组件实例.$on(事件名称,事件驱动方法(形参,形参){})

vm.$on('hello',function(traffic,city){console.log(`我坐着{$traffic}到达${city}城市`)})

注意:组件实例 和 vue实例都可以调用$on

实现步骤

  1. 定义模块src/bus.js,导入Vue模块并导出一个Vue实例对象

    import Vue from 'vue'
    export default new Vue() 
    
  2. 在各个兄弟组件中,导入 bus.js 模块

    import bus from '@/bus.js'
    

    虽然bus.js被各个组件都导入,但是系统中只有一个bus对象

  3. 接收数据的兄弟组件的 created 生命周期方法里(使得事件及时响应),

    使用 bus.$on(‘事件名称’, (接收的数据) => {}) 定义事件成员方法

    created(){
      // 定义事件,注意箭头函数应用
      bus.$on('xxx', data=>{
        console.log(data)
      })
    }
    

    xxx是事件方法的名称

    data是形参,待接收数据,并且可以定义多个

    注意:如果$on内部要使用this,通过"箭头函数"声明方法

  4. 发送数据的兄弟组件中,使用 bus.$emit(‘事件名称’, 要发送的数据) 向外发送数据

    <button @click="sendMsg">给兄弟说话</button>
    export default {
      methods: {
        sendMsg(){
          // 触发 绑定的 事件,并向外传递参数
          bus.$emit('xxx', '1000元保护费')
        }
      }
    }
    

    xxx 是接收数据组件给bus声明的方法

    第二个参数是传递的实参数据

说明

  1. Vue实例可以调用$on()方法进行事件方法创建

    实例.$on(名称,(形参,形参,形参……){})
    

    参数根据需要,可以是一个或多个

  2. Vue实例可以调用$emit()方法进行事件方法执行

    实例.$emit(名称,实参,实参,实参……)
    

    参数与$on的形参是一一对应的

注意

虽然各个兄弟组件针对bus.js都有做引入,系统在运行的时候只有一个bus对象,所以一个组件给bus绑定的事件方法,其他组件可以通过bus调用

案例应用

src/bus.js代码:

// 快递员(中间组件),负责兄弟组件之间传递数据
import Vue from 'vue'
// 导出一个Vue对象
// 注意:这是一个新的对象,与main.js里边的没有关系
export default new Vue()

First.vue代码:

<template>
    <div id="first">
      <h3>我是大哥--{{msg}}</h3>
    </div>
</template>

<script>
import bus from '@/bus.js'
export default {
  name: 'First',
  data () {
    return {
      msg: '' // 接收小弟传递过来的数据
    }
  },
  created () {
    bus.$on('receive', (data) => {
      console.log(data)
      this.msg = data
    })
  }
}
</script>

Second.vue代码:

<template>
    <div id="second">
      <h3>我是小弟</h3>
      <button @click="back()">给大哥回话</button>
    </div>
</template>

<script>
import bus from '@/bus.js'
export default {
  name: 'Second',
  methods: {
    back () {
      bus.$emit('receive', '1000元保护费')
    }
  }
}
</script>

App.vue代码(引入、注册、使用各个兄弟组件):

<template>
    <div id="app">
      <h2>App根基组件</h2>
      <first></first>
      <second></second>
    </div>
</template>

<script>
// 对两个兄弟子组件 做 导入、注册、使用
import First from '@/components/First.vue'
import Second from '@/components/Second.vue'
export default {
  name: 'App',
  components: {
    First,
    Second
  }
}
</script>

6.路由router

路由

路由是一个js功能模块,用于解决SPA项目组件切换显示问题的,本身对组件切换的各个底层技术有做封装,是更成熟组件切换解决方案,使用起来更高级、方便。

路由是开发SPA项目必备技能之一

安装路由:

在项目中安装路由有两种方式(两种方式本质完全一样):

  1. vuecli(脚手架)创建项目的时候(勾选Router项目即可,这时会增加一个步骤,选择n即可)
  2. 单独安装:
npm i vue-router

注意:以上安装依赖包的指令需要在项目根目录执行

路由相关组件

  1. router-link 设置#锚点超链接按钮

  2. router-view 设置组件显示占位符

案例应用:

​ 应用 路由 升级SPA案例的组件切换效果

在src/main.js中给路由做如下配置:

  1. import引入 路由模块
  2. import引入 各个业务组件
  3. Vue.use(路由模块) 注册路由组件
  4. 创建路由对象,通过path、component设置#锚点 与 组件的联系
  5. 在Vue实例内部 挂载 router路由对象

具体代码:

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

// 1. 引入路由模块
import VueRouter from 'vue-router'

// 2. 导入各个业务组件
import Home from './components/Home.vue'
import Movie from './components/Movie.vue'
import Music from './components/Music.vue'

// 3. 注册路由中的相关组件
// 路由中有两个组件( <router-link>  <router-view> )被进场使用
// A. 单独注册
// Vue.component('router-link',XXX)
// Vue.component('router-view',XXX)
// B. 一并注册,一次性把所有的组件都注册好,更高效
Vue.use(VueRouter)    // 插件

// 4. 创建一个路由对象
const router = new VueRouter({
  routes:[
    // path和component都是固定名称
    // {path:路由地址, component:被显示的组件模块}
    {path:'/home', component:Home},
    {path:'/movie', component:Movie},
    {path:'/music', component:Music},
  ]
})

Vue.config.productionTip = false

new Vue({
  // 5. 挂载路由对象
  router, // 全写:router:router,简易成员赋值
  render: h => h(App)
}).$mount('#app')

设置切换按钮和占位符

​ 在App.vue中设置按钮 和 占位符

  1. 按钮: 通过router-link设置 按钮和#锚点信息
<router-link to="/home">首页</router-link>
<router-link to="/user">会员</router-link>
<router-link to="/movie">电影</router-link>
  1. 占位符:通过 router-view 设置组件显示占位符
<router-view></router-view>

App.vue具体代码:

<template>
    <div>
      <h2>App根组件-路由实现spa</h2>
      <p>
        <router-link to="/home">首页</router-link>
        <router-link to="/movie">电影</router-link>
        <router-link to="/music">音乐</router-link>
      </p>
      <p id="cont">
        <!-- 设置业务组件显示-路由组件实现代表占位符 -->
        <router-view></router-view>
      </p>
    </div>
</template>

路由执行过程分析:

  1. 用户点击 页面的 路由链接router-link,点击的一瞬间,就会修改 浏览器 地址栏 中的 #号 锚点地址信息,

  2. #锚点变化了 会立即被 路由 监听到 (路由有封装window.onhashchange事件)

  3. 之后 路由 会获取变化后的#锚点信息 (路由有封装window.location.hash)

  4. 再之后 路由 根据#锚点信息找到对应 的组件 (在main.js中可知)

  5. 最后组件是通过路由占位符router-view显示的

6.1.重定向redirect

重定向

一个路由执行时可以跳转到另一个路由去执行,使得一个路由地址A与另一个路由地址B联系起来,执行A的时候会跳转执行B

关键字:redirect

语法

var router = new VueRouter({
  routes:[
    // {path:'/', redirect:'跳转到的路由地址'}
    {path:'/', redirect:'/home'},
    {path:'/home', component:Home},
  ]
})

执行 /根目录路由地址 时,就跳转执行 /home路由地址 ,进而把对应的组件给显示出来了

注意

  1. 不仅 “/” 可以被重定向,其他普通路由地址互相也可以重定向
  2. 重定向会使得路由再次发生调用请求

案例应用

​ 在没有任何#锚点信息时,就显示首页组件效果

const router = new VueRouter({
  routes:[
    // {path:'路由地址A', redirect:'路由地址B'}      // A 重定向执行 B
    {path:'/', redirect:'/home'},
    {path:'/home', component:Home}
  ]
})

6.2.子路由children

子路由

一般项目开发中,App.vue是根基组件(第1级),内部可以有具体业务组件Home.vue Movie.vue(第2级),根据业务需要,业务组件内部还要做内容分级显示(第3级)组件

第3级组件做应用的时候需要设置路由,并且与第2级组件路由有形成父子关系,故称为 子路由

通过children关键字路由设置子路由

案例应用

// 导入第三层级业务组件
import Hongkong from './components/yinyue/Hongkong.vue'

// 3. 注册路由中的相关组件
Vue.use(VueRouter) // 插件

// 4. 创建一个路由对象
const router = new VueRouter({
  routes:[
    {path:'/', redirect:'/home'},
    {
      // 给当前路由 配置子路由,关键字children
      path:'/music', 
      component:Music,
      children:[
        {path:'/music/hongkong',component:Hongkong},
      ]
    },

注意

  1. 要通过 **children **关键字设置子路由
  2. 第三级组件对应的 切换按钮(router-link) 和 显示占位符(router-view) 需要在第二级组件中设置
  3. 第二级组件对应的 切换按钮(router-link) 和 显示占位符(router-view) 需要在App.vue组件中设置

给子路由设置重定向:

在main.js中给子路由配置重定向:

    {
      path:'/music', 
      redirect:'/music/dalu',      // A. 子路由重定向配置  推荐
      component:Music,
      children:[
        // {path:'/music', redirect:'/music/dalu'}, // B.子路由重定向配置
        {path:'/music/hongkong',component:Hongkong},
        {path:'/music/*',component:*},
        {path:'/music/dalu',component:Dalu}
      ]
    },

注意

  1. 子路由设置重定向有两种方式:父路由中 或 子路由中
  2. 父级路由的component:Music 成员不能去除

6.3.路由传参

路由传参

项目中有应用场景是这样的:

商品列表页面中,每个商品项目都有 详情页面,为了知道哪个商品被展示查看,需要在路由地址中额外设置商品的数字id信息,以便据此查询商品,这个商品id就是“路由传参

声明路由参数

{ path: '/dt/:xx/:yy/:zz', component: Detail }

通过 :xx 的方式声明参数,一个或多个都可以,彼此通过 /斜杠 分隔

接收路由参数

<标签>{{$route.params.xx}}</标签>

<script>
new Vue({
  created(){
    this.$route.params.xx
  }
})
</script>

模板 和 Vue实例 内部都可以接收

案例应用:

​ 单击电影列表项目,进入详情页面,并对当前电影项目的id信息传递接收

  1. 创建业务组件 src/components/Movie.vue,展示电影列表

    <template>
        <div>
          <h3>电影列表展示</h3>
          <ul>
            <!-- 给router-link设置属性,使得生成其他标签(默认生成a标签) 
              tag="标签名称" ,变为其他标签,不影响单击效果
              <li data-v-358f1330="" class=""> 第一滴血 </li>
            -->
            <router-link  tag="li"   v-for="item in movieList"  :key="item.id"
              :to=" '/detail/'+item.id  "   >
              {{item.name}}
              </router-link>
          </ul>
        </div>
    </template>
    
    <script>
    export default {
      data(){
        return {
          movieList:[
            {id:101, name:'第一滴血'},
            {id:102, name:'我不是药神'},
            {id:103, name:'我不是码神'},
          ]
        }
      }
    }
    </script>
    
  2. 创建业务组件 src/components/Detail.vue 展示电影详情,同时接收电影参数

    <template>
        <div>电影详情展示-----{{$route.params.mid}}</div>
    </template>
    
    <script>
    export default {
      // 组件实例内部获得"路由参数",进而可以通过axios获得指定信息的详情内容
      created(){
        console.log(this.$route.params.mid) // 获得名称为mid的路由参数
      }
    }
    </script>
    
  3. 在main.js中 给 Movie.vue 和 Detail.vue 两个组件创建路由,Detail的路由要设置参数

    // 2. 导入各个业务组件
    import Movie from './components/Movie.vue'
    import Detail from './components/Detail.vue'
    
    // 3. 注册路由中的相关组件
    Vue.use(VueRouter) // 插件
    
    // 4. 创建一个路由对象
    const router = new VueRouter({
      routes:[
        {path:'/', redirect:'/movie'},
        {path:'/movie', component:Movie}, // 电影列表路由
        // 给当前路由设置参数
        // 通过:冒号方式 表达有参数,a/b/c 是参数的名称,可以自定义为其他
        {path:'/detail/:mid', component:Detail}, // 电影详情路由
      ]
    })
    

注意

  1. 路由有参数,那么应用中要传递该参数
  2. router-link标签默认被编译为超链接a标签,可以设置tag属性,使其变为其他标签

6.4.编程式导航

导航

​ 一个路由被执行一次,就是一次导航

导航种类

  1. 声明式导航:router-link可以编译生成超链接按钮,单击按钮就切换路由并显示对应的组件,这个过程称为“声明式导航(静态)”
  2. 编程式导航:有时由于业务需要,一个路由被切换执行并不方便通过声明式导航实现,相反是要通过程序代码的方式给实现出来,就是“编程式导航(动态)”

编程式导航的实现

路由对象.push(路由地址)    // 根据路由地址执行导航  最经常使用********
路由对象.back()  	      // 后退************
路由对象.forward()        // 前进
路由对象.go(数字整数)     // 根据“整型数字”参数做路由的 前进(大于0)、刷新(等于0)、后退(小于0) 操作

路由对象

  1. main.js中,就是router
  2. 在组件实例中 就是 this.$router

案例应用

​ 在电影详情页面通过“编程式导航”实现单击“返回”按钮回到列表页面效果

src/components/Detail.vue具体实现:

<template>
    <div>
      <p><button @click="$router.back()">返回back</button></p>
      <p><button @click="$router.go(-1)">返回go</button></p>
      <p><button @click="$router.push('/movie')">返回push</button></p>
      <p>电影详情展示-----{{$route.params.mid}}</p>
    </div>
</template>

6.5.路由守卫

守卫

​ 每个路由在执行的时候都会经历一些"关口",关口可以做决定是否 继续前进 或 执行其他路由 或 停止当前路由执行 ,关口就是守卫。

作用

​ 每个项目都要使用守卫,很多组件页面要求只有处于登录状态的用户才可以访问,判断是否登录就是通过守卫做的。

部署守卫语法

router.beforeEach((to, from, next) => { /* 导航守卫 处理逻辑 */ })

router是 new VueRouter() 得到的 路由对象

  1. to:是一个对象,保存着将要访问的路由相关参数,to.path:被访问的路由地址信息

  2. from:是一个对象,保存着离开的那个路由的相关参数,from.path: 从哪来的路由地址

  3. next:是一个回调函数,对后续的执行起着 拦截 或 放行 的作用

如果没有问题请一定执行next()方法,以进行后续操作,

next()方法使用示例:

​ next(’/login’) 执行其他路由,例如登录

​ next(false) 停止当前路由执行

​ next() 执行后续动作

注意

​ 守卫种类有很多,我们要学习使用的是 “全局前置守卫” ,特点是所有的路由在执行之前都会经过该守卫

案例应用:

实现非登录用户访问后台首页就 强制去登录的效果

// 路由守卫简单使用【全局前置守卫,所有路由都生效】
router.beforeEach(function(to,from,next){
    // "非登录"用户禁止访问后台页面,相反可以访问login登录页面
    let tk = window.sessionStorage.getItem('token')
    // "没有token" 并且 还要访问 "home页面[非login登录页面]" 就强制登录
    if(!tk && to.path!=='/login'){
        // return会停止后续代码执行
        return next('/login')
    }
    next() // 放行
})

7.监听器watch

watch监听器

监听器就是监测机制,可以监测vue中data数据的变化,并做相关处理

关键字:watch

语法

data(){
  return {
    name:'',
    user:{
      addr:'',
    }
  }  
},
watch:{
  // data成员名称:函数(新值,旧值){}
   name:function(newv,oldv){},
  'user.addr':function(newv,oldv){},  // 对象成员监听
   user: { // 深度监听,内部任意成员变化都会感知到
    handler: function (newv, oldv) { },
    deep: true
  },
}

注意

  1. 监听器既可以监听普通成员、也可以监听对象成员,还可以深度监听
  2. 一般this可以调用的成员属性都可以监听,例如computed计算属性,但是主要针对data做应用
  3. 深度监听,使用handler+deep关键字达成

8.脚手架VueCLI

VueCLI

脚手架,其可以把许多项目通用的依赖包(vue、webpack、路由、vuex、less编译器等等) 和 通用的配置都给做好安装好,使得开发者全部的注意力都集中在业务层面,明显提升开发效率的,真实项目都要使用脚手架开发。

依赖包:axios、vue等等都是依赖包,一个依赖包中有许多 模块

安装vuecli

npm i -g @vue/cli   // 使用全局方式安装

上述依赖包通过全局方式安装,完毕后在系统任何目录都会执行名称为"vue"的一个指令

依赖包安装完毕,会形成 在 C:\Users\ssh\AppData\Roaming\npm\node_modules@vue\cli 目录

vue --version 查看脚手架版本,现在默认是4.0.5版本(如果是2.9.6就是错误的,需要卸载重新安装)

npm un -g @vue/cli 卸载

vuecli创建项目

vue  create  项目名称(01-pro)

注意

  1. vuecli创建新项目时,项目名称必须是一个新目录,完毕后会自动生产之,并在其中生成项目需要的文件
  2. 项目上级各个目录名字最好为英文数字中横线 不要使用 中文的或其他特殊符号定义上级目录名字

本文地址:https://blog.csdn.net/jyn15159/article/details/107312105