Vue脚手架学习笔记

视频

Vue脚手架学习笔记

  • 1. 脚手架设置相关内容
    • 1.1 各文件的作用
    • 1.2 关闭语法检查
  • 2. 组件的使用
    • 2.1 单文件组件的使用(组件使用的三个步骤)
    • 2.2 prop配置项:父向子传数据
      • 2.2.1 数组方式
      • 2.2.2 类型限制
      • 2.2.3 默认值、必要性
    • 2.3 ref :给标签添加名字
    • 2.4 mixin:混入,将共有的方法提取
    • 2.5 scoped:局部样式
    • 2.6 $emit :在组件中自定义事件,子向父传数据
      • 2.6.1 通过代码给组件绑定事件
      • 2.6.3 自定义事件只执行一次once
      • 2.6.4 传递的参数不确定时
    • 2.7 $bus 数据总线:任意组件数据传递
    • 2.8 pubsub:消息订阅,任意组件传递消息
  • 3. axios:Vue中的Ajax
  • 4 VueX
    • 4.1 安装VueX
    • 4.2 store 三大核心的作用:
      • 4.2.1 actions
      • 4.2.2 mutations
      • 4.2.3 state
      • 4.2.4 getter 第四个配置项
    • 4.3 调用三大核心时的简写形式:映射
      • 4.3.1 mapState:在计算属性computed中使用
        • 4.3.1.1 v-modle 中不能使用mapState中定义的对象
      • 4.3.2 mapGetter:在计算属性computed中使用
      • 4.3.1 mapActions:在methods中使用
      • 4.3.1 mapMutations:在methods中使用
  • 5 Vuex的模块化
    • 5.1 export default 和 export const导出的不同
    • 5.2 给每个模块创建对应的js文件
    • 5.3 在组件中调用
      • 5.3.1 state
      • 5.3.2 getters
      • 5.3.3 actions
      • 5.3.4 mutations
      • 5.3.5 Vue_a.vue代码
  • 6 路由
    • 6.1 新建目录和文件
    • 6.2 在main.js中导入路由组件
    • 6.3 在App.vue中使用路由
    • 6.4 多级路由
      • 6.4.1query的对象形式在路由传递数据
        • 6.4.1.1 完整代码
      • 6.4.2 query的字符形式传递数据
      • 6.4.3 路由配置中的`name` 属性
    • 6.5 编程式导航(浏览器的前进\后退)
    • 6.6 $router中的前进\后退
    • 6.6 `push` 到达指定路由
    • 6.7 keep-alive:页面跳转时组件销毁
    • 6.8 路由的两个生命周期
    • 6.9 $route中的meta
    • 6.10 全局路由守卫
      • 6.10.1 全局前置路由守卫
      • 6.10.2 全局后置路由守卫 title的设置
    • 6.11 局部路由守卫
      • 6.11.1 path守卫
      • 6.11.2 组件守卫
  • 7 发布到服务器

1. 脚手架设置相关内容

安装node版本管理工具nvm

  • nvm常用命令
    1. 下载指定版本的node:nvm install 16.18.1
    2. 切换指定版本的node:nvm use16.18.1
    3. 卸载指定版本的node:nvm uninstall 16.18.1
    4. 显示已安装的node版本:nvm ls 或 nvm list
    5. 显示nvm版本:nvm v
      安装和卸载node

1.1 各文件的作用

在这里插入图片描述

1.2 关闭语法检查

在这里插入图片描述

lintOnSave : false

2. 组件的使用

2.1 单文件组件的使用(组件使用的三个步骤)

创建组件–>注册组件–>使用组件

  1. 在Componets文件中创建文件Car.vue

组件:(html(结构),javascript(交互),css(样式))
<template>
  <div>
    <h3>{{brand}}</h3>
    <h3>{{price}}</h3>
    <h3>{{color}}</h3>
  </div>
</template>

<script>
export default {
  // 在浏览器的VueDevTool中显示的名字
    name : 'CarInfo',
    data(){
        return {
            brand : '宝马520',
            price : '10',
            color : '黑色',
        }
    }
}
</script>
  1. 在App.vue中注册
<script>
import Car from './components/Car.vue'
  // 将组件暴露在外,方便别的组件调用:export default
  export default{
    name : 'app',
    data() {
      return {
        msg: '汽车信息',
      };
    },
    // 2. 下一级组件在这里注册
    components : {Car}
  }
</script>
  1. 使用组件
<template>
    <div>
      <h1>{{msg}}</h1>
      <!-- 3. 使用组件 -->
      <car></car>
      <car></car>
      <car></car>
    </div>
</template>
  1. 最终显示效果
    在这里插入图片描述
  2. 在 浏览器插件中显示
    在这里插入图片描述

2.2 prop配置项:父向子传数据

  1. 如果传递是data中定义的响应式数据,需要标签的属性使用v-bind,:属性名='插值'
  2. 在子组件中:配置项props :['属性名'],来接收
  3. 如果传递的是一个对象,则需要使用属性名.key
  4. prop接收后的数据不能修改,因为数据的源在父组件,在子组件修改不会传递到父组件

2.2.1 数组方式

Car.vue
<template>
  <div>
    <h3>{{brand}}</h3>
    <h3>{{price}}</h3>
    <h3>{{color}}</h3>
  </div>
</template>

<script>
export default {
    name : 'CarInfo',
    // 1. 数组方式
    props:['brand','price','color']
}
</script>
App.vue
<template>
    <div>
      <!-- * 数据通过标签的属性来传递,示例中传递的是常量所以属性不用加v-bind -->
      <car brand='宝马520' price=10 color="黑色"></car>
    </div>
</template>

2.2.2 类型限制

  1. carprice限制为数字类型,而传递过来的数据还是string的情况下,程序可以运行,控制台报错:price的类型错误。应该是数字类型10,而传送来的是字符串‘10’

Invalid prop: type check failed for prop “price”. Expected Number with value 10, got String with value “10”.

  1. 解决办法:传送数据时将标签price=‘10’改为:v-bind:price='10'简写:price='10'
  2. 这里有一个问题要注意,除数字类的字符串,其他字符类的不能使用v-bind,会将字符串当成data中的对象去查找。
Car.vue
<script>
export default {
    name : 'CarInfo',
    //2. 添加类型限制
    props : {
      brand : String,
      price : Number,
      color : String,
    }
}
</script>
App.vue
<template>
    <div>
      <h1>{{msg}}</h1>
      <!-- * 数据通过标签的属性来传递 -->
      <car brand='宝马520' :price='10' color="黑色"></car>
      <car brand="比亚迪" :price='20' color="红色"></car>
    </div>
</template>

2.2.3 默认值、必要性

  1. 默认值:当传递的属性不存在时,会使用默认值(必须是属性都不存在,等于空串也不会使用默认值)
  2. 必要性:传递的属性必须存在,否则控制台报错:Missing required prop
App.vue
      <!-- * 数据通过标签的属性来传递 -->
      <car brand='宝马520' :price='10' ></car>
      <car brand="比亚迪" :price='20' color="红色"></car>
Car.vue
<script>
export default {
    name : 'CarInfo',
    //3. 添加配型限制、默认值、必要性)
    props : {
      brand : {
        type:String,
        required : true // 必要性
      },      
      price : {
        type:Number,
        required : true // 必要性
      },      
      color : {
        type:String,
        default : '红色' // 默认值
      },
    }
}
</script>

2.3 ref :给标签添加名字

  1. 在任意的标签内添加属性ref,并赋值
  2. ref的属性值,必须唯一,否则报错
  3. 通过this.$refs.ref的属性值.属性来访问标签内任意属性的属性值
App.vue
<template>
    <div>
      <h1 ref='title'>{{msg}}</h1>
		// 添加ref属性并赋值
      <car brand='宝马520' :price='10' color='黑色' ref="car1"></car>
      <car brand="比亚迪" :price='20' color="红色" ref='car2'></car>

      <button @click='printCarInfo'>ref属性访问子组件的属性</button>
    </div>
</template>

<script>
import Car from './components/Car.vue'

  export default{
    name : 'app',
    data() {
      return {
        msg: '汽车信息',
      };
    },
    methods: {
      printCarInfo() {
        // $refs来访问标签的属性
        console.log(this.$refs.car1);
        console.log(this.$refs.car2.color);
        console.log(this.$refs.title.innerHTML);
      },
    },
    components : { Car }
  }
</script>


2.4 mixin:混入,将共有的方法提取

  1. 作用:不同的vue中有相同的方法时,可以提取到mixins.js文件中(文件名随意),在vue中引入就可以使用
  2. vuemixins中有同名的方法时,只执行vue中的方法
  3. main.js中引入mixins中的方法,该方法为全局的方法,所有的vue中都会有此方法Vue.mixin(mix2)
  4. 声明周期函数:mixinsvue中有相同的声明周期函数时,两个都会执行

目录结构
在这里插入图片描述

// mixins.js
export const mix1 = {
    methods: {
        printUserInfo() {
            console.log('mixin中的方法,打印客户信息',this.username); 
        },
    },
}

export const mix2 = {
    // 生命周期:挂载后
    mounted(){
        console.log('mixins中的mounted执行',this); 
    }
}
// main.js
import Vue from 'vue'
import App from './App.vue'
// 全局的混入,在所有的vue中都会引入mix2的方法
import { mix2 } from './mixins'
Vue.mixin(mix2)

Vue.config.productionTip = false
new Vue({
  render(h) {
    return h(App)
  }
  // render: h => h(App),
}).$mount('#app')

VipInfo.vue
<template>
    <div>
        <div>{{ username }}</div>
        <button @click="printUserInfo">打印vip信息</button>
    </div>
</template>

<script>
import {mix1, mix2} from '../mixins'
export default {
    name : 'VipInfo',
    data() {
        return {
            username: '李四',
        };
    },
    mixins : [mix1,mix2],
    // 生命周期:mixins和vue中都有同一个生命周期函数时,两个都执行
    mounted(){
        console.log('VipInfo中的mounted执行',this); 
    }
/*     methods:{
      printUserInfo(){
        console.log('vip .....method');
      }
    } */
}
</script>

User.vue
<template>
  <div>
      <div>{{username}}</div>
      <button @click='printUserInfo'>打印用户信息</button>
  </div>
</template>

<script>
// 从文件中引入
import { mix1 } from '@/mixins';
export default {
    name : 'UserInfo',
    data() {
      return {
        username: '张三',
      };
    },
// mixin使用时,用数组的方式
    mixins : [mix1],
    methods:{
      // 当mixins和当前vue中都有同一个方法时,执行当前vue中的方法
      printUserInfo(){
        console.log('user.vue中的方法,打印客户信息',this.username); 
      }
    }
}
</script>

结果
在这里插入图片描述
从结果中可以看到生命周期函数mounted函数执行了5次,分别是(先后顺序)

  1. main.js中的vue,也就时Root的
  2. App中的Component
  3. VipInfo中自己定义的mounted函数
  4. VipInfo中的Component又执行了一次
  5. User中的Component

2.5 scoped:局部样式

很多的style最后都会汇集到App这个vue中,为了方式样式重名,在style标签内增加scoped属性

<style scoped>
  
</style>

2.6 $emit :在组件中自定义事件,子向父传数据

  1. 作用:
    1.1 子组件可直接执行父组件中的函数,
    1.2 子组件可以向父组件传递数据
  2. 使用:
    2.1 在父组件文件中,在子组件的标签上绑定事件 v-on:事件名='函数名'
    2.2 在父组件中写好执行的函数体
    2.3 在子组件文件中,绑定正常的触发事件,在事件的执行函数中 this.$emit('父组件中的事件名',参数1,参数2,....)
    2.4 当事件触发后,执行父组件中的函数体
  3. 事件触发后的执行过程,如图:
    在这里插入图片描述

2.6.1 通过代码给组件绑定事件

  1. 在父组件中,给子组件的标签ref赋值
  2. 在生命周期执行到挂载完成后,this.$refs.ref的值.$on('子组件中调用的事件名',事件发生后的执行函数)
    在这里插入图片描述

2.6.3 自定义事件只执行一次once

  1. 在标签中绑定事件时
<User v-on:event1.once='doSome1'></User>
  1. 通过代码绑定事件
this.$refs.printUser.$once('event2',this.doSome2)

2.6.4 传递的参数不确定时

  1. 子组件中正常传递
  2. 父组件中接收时使用...parameters,以数组的形式接收
doSome2(name,...parameters){
   console.log(name,parameters);            
}
//结果
张三  [20, '男']

2.7 $bus 数据总线:任意组件数据传递

原理在视频的P91

  1. 在main.js中添加代码
main.js
new Vue({
  el : '#app',
  render: h => h(App),
  // 生命周期:创建前
  beforeCreate(){
    // 创建bus总线,用于传递数据
    Vue.prototype.$bus = this
  }
})
  1. 在接收方添加代码
// 生命周期:挂载完成
mounted () {
	this.$bus.$on('事件名',执行的函数(参数1,参数2))
}
  1. 在发送方添加代码
this.$emit('事件名',参数1,参数2...)    
  1. 销毁
beforeDestroy(){
	this.$bus.off(‘事件名’)
}

2.8 pubsub:消息订阅,任意组件传递消息

  1. 安装pubsub:npm i pubsub.js
  2. 在订阅消息和发布消息的组件中引入pubsub:import PubSub from 'pubsub-js''
  3. 在挂载后订阅消息
        mounted (){
          // 返回值是此订阅消息的ID
          // 参数1:订阅消息的名字,参数2:(订阅消息的名字,返回消息发布数据)
          this.pubsubId = PubSub.subscribe("订阅的消息的名字",(messageName,msg) => {
            console.log(this.pubsubId,messageName,msg);
          })
        },
  1. 发布消息:PubSub.publish("订阅的消息的名字","发布的消息")
  2. 销毁订阅
        beforeDestroy(){
          // 销毁时使用ID
          pubsub.unsubscribe(this.pubsubId)
        },

3. axios:Vue中的Ajax

详细教程

  1. 安装
npm install axios
  1. 在组件中引入
import axios from 'axios'
Vue.prototype.$axios = axios
  1. 使用
axios.get('URL').then(
     response => {
          console.log(response .data);          
    },
    error => {
          console.log(error.message);
   }
)                

4 VueX

4.1 安装VueX

终端中执行命令:

npm i vuex@3
  • 在根目录下创建目录和文件(文件名随意)
    目录:vuex
    在vuex目录中创建文件:store.js

  • 文件store.js

import Vue from 'vue'
import Vuex from 'vuex'

// 使用vuex插件
Vue.use(Vuex)

// 创建vuex的三大核心

const actions = {}
const mutations = {}
const state = {}

// 创建Vuex的管理者,管理三大核心
const store = new Vuex.Store({action,mutation,state})

// 导出store
export default store
  • 在main.js中引入store
import Vue from 'vue'
import App from './App.vue'
// 引入store
import store from './vuex/store'

Vue.config.productionTip = false

new Vue({
  el : '#app',
  // 配置
  store,
   render: h => h(App),
})
  • 使用:
    在插值语法中{{$store.state.XXX}}
    在代码中:this.$stroe.state.XXX

4.2 store 三大核心的作用:

所有的方法和数据可以在所有的组件中使用

4.2.1 actions

  • 作用:
    1. 完成逻辑代码,异步操作,Ajax
    2. 调用mutations中的方法,传递处理过的数据
const actions = {
	方法名(context,参数){
		// todo
		// 
		context('mutations中的方法名',参数)
	},
}
  • 调用actions中的方法
    1. 使用$store.dispatch调用
this.$store.dispatch('actions中的方法名',参数)

4.2.2 mutations

  • 作用:维护state中的数据
  • mutations中的方法名:actions中的方法名为addUserName, 则mutations中的方法民为ADD_USER_NAME
const mutations = {
	// 此处的方法名,习惯定义为actions中方法名所有字母大写,并且在单词中间加入下划线_
    方法名(state, val){
        state.数据名 = val
    },
}
  • 调用mutations中的方法
    1. actions中调用
const actions = {
	方法名(context,参数){
		// todo
		context('mutations中的方法名',参数)
	},
}
  1. 在组件中使用$store.commit调用
    这种情况适用于业务逻辑非常简单的情况
this.$store.commit('mutations中的方法名',参数)

4.2.3 state

  • 作用:相当于组件中的data部分
const state = {
    key : 'value',
    key1 : ['数组'],
}

4.2.4 getter 第四个配置项

  • 作用:类似组件中的计算属性computed
const getters = {
    方法名(state){
    	// todo
        return 返回值
    }
}
  • 使用:
	$store.getters.getters中的方法名

4.3 调用三大核心时的简写形式:映射

【视频】原理的视频讲解
【视频】扩展运算符…

4.3.1 mapState:在计算属性computed中使用

  • 引入:import { mapState } from 'vuex';
  • 简化$store.state.xxxxx
  • 对象形式。key:组件中使用的名字,value:$store.state中定义的名字
    computed : {
        // 对象形式。key:组件中使用的名字,value:$store.state中定义的名字
         ...mapState({users:'users',vips:'vips',inString:'inString'})
    }
  • 数组形式:如果对象中的key和value是相同的,则可以使用数组形式的mapState
        // 数组形式。如果对象中的key和value是相同的,则可以使用数组形式的mapState
        ...mapState(['users','vips','inString'])
  • 在插值语法中可以直接使用:{{XXXXX}},在方法体中使用:this.XXXXX
  • 如果在组件的data{}配置项中定义了一个相同名字的对象,则会使用data{}中定义的对象。
4.3.1.1 v-modle 中不能使用mapState中定义的对象

[视频]讲解 21:35

  • 在双向数据绑定中,只能使用$store.state.XXXXX这种形式
  • 原因:使用...mapState这种方式简写,在底层实现时只生成了getter方法,没有setter方法
  • 使用简写形式会报错:
    Computed property “inString” was assigned to but it has no setter.

4.3.2 mapGetter:在计算属性computed中使用

  1. 引入:import { mapGetters, mapState } from 'vuex';
  2. 简化:$store.getters.XXXXX

对象形式。key:组件中使用的名字,value:$store.getters中定义的名字

    computed : {
        ...mapGetters({reverseStr:'reverseStr'})
    }
  • 数组形式:如果对象中的key和value是相同的,则可以使用数组形式
...mapGetters(['reverseStr'])

4.3.1 mapActions:在methods中使用

  1. 引入:import { mapActions } from 'vuex';
  2. 如果是某事件触发的方法,并且该事件需要传递参数,则将参数放在事件的表达式中:@click="addUser(userName)"
  3. 使用:
  • 对象形式
    在这里插入图片描述
  • 数组形式
    在这里插入图片描述

4.3.1 mapMutations:在methods中使用

  1. 引入:import { mapMutations } from 'vuex';
  2. 和mapActions的使用方法一样,要注意一点,如果要使用数组方式,则只能以mutations中定义的方法名为主,所以如果是事件导致的该方法发生,则需要修改事件中的方法名

5 Vuex的模块化

5.1 export default 和 export const导出的不同

export default 和 export const相关的文章

使用export defaultexport const定义的对象在导出时用法不同

  1. 使用export default定义,在一个文件中只能有一个export default定义的对象
// A 文件
export default {
	// 对象
}
// 导入
import 名字随意 from '../文件路径/a'
  1. 使用export const定义
// B 文件
export const name = {
	// 对象
}
export const email = {
	// 对象
}
// 导入
import { name, email } from '../文件路径/b'

5.2 给每个模块创建对应的js文件

  1. 在vuex目录中给每个模块创建对应的js文件
    在这里插入图片描述
  • 代码部分
    1. namespaced 命名空间,值为true确定开启,默认是false,不开启
    2. 如果在不同的文件中命名了相同的方法名或者数据名,在调用时会将所有的方法和数据都调用一次,开启命名空间后,在调用时需要指明方法或数据的所属的模块
    3. 每个模块都有自己的state,actions,mutations,getters
// modelA1文件
export default  {
    // 命名空间
    namespaced : true,
    state : {
         a : 'a'
    },
    getters : {
        getA(state){
            return state.a + '来自 getters'
        }
    },
    actions : {
        actionA(){
            console.log('action A');
            }
    },
    mutations : {
        MUTATION_A(){
            console.log('mutation A');            
        }
    }
}
  1. 在vuex的管理者store所在的文件中导入所有的模块
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

import moduleA from './moduleA1'
import moduleB from './moduleB'

export default new Vuex.Store({
    modules : {
        moduleA,moduleB
    }
})

在这里插入图片描述

5.3 在组件中调用

记得导入map:

import { mapActions, mapGetters, mapMutations, mapState } from 'vuex'

5.3.1 state

  1. 第一种方法
<div>{{$store.state.moduleA.a}}</div>
  1. 数据简写形式
<div>{{a}}</div>

computed : {
/*  a(){
      return this.$store.state.moduleA.a
    },*/
    // mapState就是将下面的语句翻译为上面的语句
    ...mapState('moduleA',['a']),
  },

5.3.2 getters

  1. 第一种方法
<div>{{$store.getters['moduleA/getA']}}</div>
  1. 数组简写形式
computed : {
	...mapGetters('moduleA',['getA'])
}

5.3.3 actions

html部分:

<button @click='actionA'>VueA click 1</button>

第一种方式:

  methods : {     
    actionA(){
      this.$store.dispatch('moduleA/actionA')
    }
  }
  1. 数组简写形式
  methods : {
    // 开启命名空间,数组形式的缩写
    ...mapActions('moduleA',['actionA']),
  }

5.3.4 mutations

  1. 第一种:对象简写形式
<button @click='mutationA'>VueB click 2</button>
  methods : {
	// 在module文件中,习惯mutation的文件名全部都是大写字母,这里只能使用对象简写形式
    ...mapMutations('moduleA',{mutationA : 'MUTATION_A'})
  }
  1. 第二种:数组简写形式

    • 修改click中的方法名与mutation的方法名相同
    <button @click='MUTATION_A'>VueB click 2</button>
  methods : {
    ...mapMutations('moduleA',['MUTATION_A'])
  }

5.3.5 Vue_a.vue代码

<template>
  <div>
    <button @click='actionA'>VueA click 1</button>
    <button @click='MUTATION_A'>VueB click 2</button>
    <!-- <div>{{$store.state.moduleA.a}}</div> -->
    <div>{{a}}</div>

    <!-- <div>{{$store.getters['moduleA/getA']}}</div> -->
    <div>{{getA}}</div>
  </div>
</template>

<script>
import { mapActions, mapGetters, mapMutations, mapState } from 'vuex'
export default {
  name : 'vueAAA',
  computed : {
    a(){
      return this.$store.state.moduleA.a
    },
    ...mapState('moduleA',['a']),
    ...mapGetters('moduleA',['getA'])
  },
  methods : {
/*     
    actionA(){
      this.$store.dispatch('moduleA/actionA')
    }, 
*/  
    // 开启命名空间,数组形式的缩写
    ...mapActions('moduleA',['actionA']),
/*     
    mutationA(){
      this.$store.commit('moduleA/mutationA')
    },
     */
    ...mapMutations('moduleA',['MUTATION_A'])
    // ...mapMutations('moduleA',{mutationA : 'MUTATION_A'})
  }
}
</script>

6 路由

  • 安装路由插件:
    Vue2 安装:npm i vue-router@3
    Vue3 安装: npm i vue-router@4

路由:route,路由器中的一条线路
路由器:router

6.1 新建目录和文件

  1. 新建目录:route
  2. 在目录中新建文件:index.js
// 导入路由
import VueRouter from 'vue-router'
// 导入组件
import 组件1 from '../XXXXX'
import 组件2 from '../XXXXX'

// 创建路由器对象
export default new VueRouter({
    routes : [
        {path:'/路径',component:组件1},
        {path:'/路径',component:组件2},
    ]
})

6.2 在main.js中导入路由组件

import Vue from 'vue'
import App from './App.vue'
Vue.config.productionTip = false

// 导入路由器
import VueRouter from 'vue-router'
// 使用路由器
Vue.use(VueRouter)
// 导入路由
import router from './route/index'

new Vue({
  el : '#app',
  // 配置项
  router,
  render: h => h(App),
})

6.3 在App.vue中使用路由

  1. 路由中的组件不需要在componets中包含
  2. <router-link>代替<a>标签
  3. 点击<router-link>标签后,将会在路由中寻找该路径指向的组件,将该组件放置到占位符<router-view的位置
// 需要点击的对象使用router-link标签
<router-link to="/路径">点我</router-link>

// 占位符,当点击标签后,该占位符被路由中上述路径指向的组件代替
<router-view></router-view>    

6.4 多级路由

  1. 在路由routes中创建子路由
  2. 在实例中,虽然两个路由指向了同一个组件Third,路径还是要分开,这样标签的active-class="selected"属性才能分辨出两个标签
    routes : [
        { 
            path:'/SecondOne',component:SecondOne,
            children : [
                // path中的路径相同,则active-class="selected"两个都会被显示选中
                {path:'Third',component:Third},
                {path:'Third_1',component:Third},
            ]
        },

6.4.1query的对象形式在路由传递数据

  1. 通过<router-link>标签的:to属性传递数据,path:路径,query:要传递的数据,query是对象形式
            <router-link active-class="selected" 

                :to="{
                  path : '/SecondOne/Third',
                  query : this.list1_1
                  }"
                
                >第二级目录:1.1</router-link>


  1. this.$route.query接收数据
        <li v-for="listThird,index in this.$route.query" 
        :key="index">{{listThird}}</li>
6.4.1.1 完整代码
index.js文件
// 导入路由
import VueRouter from 'vue-router'

// 导入组件
import SecondOne from '../paths/SecondOne.vue'
import SecondTwo from '../paths/SecondTwo.vue'

import Third from '../paths/Third.vue'
// 创建路由器对象
export default new VueRouter({
    routes : [
        { 
            path:'/SecondOne',component:SecondOne,
            children : [
                // path中的路径相同,则active-class="selected"两个都会被显示选中
                {path:'Third',component:Third},
                {path:'Third_1',component:Third},
            ]
        },
        {path:'/SecondTwo',component:SecondTwo},
    ]
})
SecondOne.vue 文件
<template>
  <div class='s1'>
      <div>
        <h3>2级目录</h3>
        <ul >
            <li><router-link active-class="selected" 

                :to="{
                  path : '/SecondOne/Third',
                  query : this.list1_1
                  }"
                
                >第二级目录:1.1</router-link></li>
        </ul>
      </div>
      <div>
        <router-view></router-view>
      </div>
  </div>
</template>

<script>
export default {
    name : 'SecondOne',
    data() {
      return {
        // 目录1.1下的数据
        list1_1 : [
            '第三级目录:1.1.1',
            '第三级目录:1.1.2',
            '第三级目录:1.1.3',
          ]
      }
    },
}
</script>
Third.vue 文件
<template>
  <div  class='s2'>
    <h3>3级目录</h3>
    <ul >
        <li v-for="listThird,index in this.$route.query" 
        :key="index">{{listThird}}</li>
    </ul>
  </div>
</template>

<script>
export default {
    name : 'ThirdLevel',
    mounted (){
        console.log(this.$route);
        console.log(this.$route.query);
    }
}
</script>

this.$route的结果
在这里插入图片描述

6.4.2 query的字符形式传递数据

以数据形式和对象形式传递参数,在 this.$route.query中接收到的对象是一样的

<-- router-link 标签里面的 to属性 -->
to="/SecondOne/Third?m1='第三级目录:1.1.1&m2='第三级目录:1.1.2'&m3='第三级目录:1.1.3'"

6.4.3 路由配置中的name 属性

  • 作用 : 给路径起一个名字,在使用到路径的地方就能用简单的值来代替
  1. 在路由中加入name属性
			children : [
                {path:'Third',component:Third},
                {
                    // 使用name属性代替该路径
                    name:'path1-2',
                    // path:'Third_1',
                    component:Third
                },
            ]
  1. <route-link>中使用
<router-link active-class="selected" 
            :to="{
            <-- 使用name代替path:'/SecondOne/Third_1' --> 
              name:'path1-2',                      
              query:this.list1_2}">
            第二级目录:1.2</router-link>

在这里插入图片描述

6.5 编程式导航(浏览器的前进\后退)

<router-link>标签在编译完成后是<a>标签,不能用于事件触发的网页跳转

  1. 事件引起的跳转
<button @click='goThirdPush'>跳转</button>
  1. 使用编程式导航时,push和replace方法会返回一个promise对象
    promise对象期望你能通过参数的方式返回成功和失败两个回调函数
    如果没有给这两个参数,连续点击两次按钮会报错
methods : {
      // 使用编程式导航时,push和replace方法会返回一个promise对象
      // promise对象期望你能通过参数的方式返回成功和失败两个回调函数
      // 如果没有给这两个参数,连续点击两次按钮会报错
        goThirdPush(){
          this.$router.push({
              path:'/SecondOne/Third',
              query:this.list1_1
          },()=>{},()=>{})
        },
        goThirdReplace(){
          this.$router.replace({
            name:'path1-2',            
            query:this.list1_2
          },()=>{},()=>{})
        }
    }
  1. push方法和replace方法的区别

浏览器会将点击的网址按栈的方式存储

  1. 点击新的网址,会将网址压入栈顶
  2. 点击后退按钮,会向栈底位置移动,读取下面地址的内容
  3. 无论后退还是前进,栈里面的内容不会清除,只有指针向栈顶或栈底移动

push方法:当前地址压入栈顶
replace方法:当前地址替换栈顶的地址

6.6 $router中的前进\后退

      <button @click='forward'>前进</button>
      <button @click='back'>后退</button>
      <button @click='forwardTwo'>前进2步</button>
      <button @click='backTwo'>后退2步</button>
        methods : {
          forward(){
            this.$router.forward()
          },
          back(){
            this.$router.back()
          },
          forwardTwo(){
            this.$router.go(2)
          },
          backTwo(){
            this.$router.go(-2)
          }
        }

6.6 push 到达指定路由

this.$router.push('/home')
this.$router.push({name: 'Home'})

6.7 keep-alive:页面跳转时组件销毁

  • 作用:当页面跳转时,旧的页面中的组件会被销毁,此标签阻止组件被销毁
  • 可在页面的生命周期:组件销毁前beforeDestroy()方法中证明

<keep-alive>的使用

  1. 路径下的所有组件不被销毁
      <keep-alive>
        <router-view></router-view>    
      </keep-alive>
  1. 路径下的单个组件不被销毁,include的值是组件的name配置项
      <keep-alive include="SecondOne">
        <router-view></router-view>    
      </keep-alive>

在这里插入图片描述
3. 路径下的多个组件不被销毁,数组形式,记得include加冒号

      <keep-alive :include="['SecondOne','SecondTwo']">
        <router-view></router-view>    
      </keep-alive>

6.8 路由的两个生命周期

  1. 有指向此组件的路由被点击后,路由的activated()执行
  2. 其他指向的路由被点击后 deactivated()执行
    activated() {
        console.log("路由激活");
    },
    deactivated() {
        console.log("路由切走");
    },

6.9 $route中的meta

可在meta中任意增加对象,对当前路由做标记

            children : [
                // path中的路径相同,则active-class="selected"两个都会被显示选中
                {path:'Third',component:Third},
                {
                    // 使用name属性代替该路径
                    name:'path1-2',
                    path:'Third_1',
                    component:Third,
                    // meta
                    meta : {
                        isAuth : true
                    }
                },

在这里插入图片描述

6.10 全局路由守卫

6.10.1 全局前置路由守卫

  • 作用:在任一路由被调用之前执行的函数,类似于生命周期的函数
  1. 位置:此方法必须写在,创建VueRouter对象之后与导出之间
// 全局前置路由守卫
router.beforeEach((to,from,next)=>{
    //todo
})

在这里插入图片描述

  1. 参数

    • tofrom都是route类型,里面有path,name,meta等属性
    • to是跳转之后的路由,from是跳转之前的路由
    • next():执行此方法表示放行,才可跳转到to的路由
  2. 使用
    在需要权限识别的路由上加上一个标志

meta : {
    isAuth : true
}
// 全局前置路由守卫
router.beforeEach((to,from,next)=>{
// 如果要访问的路由需要权限识别,并且该路由的name===path1-2,可以访问
    if(to.meta.isAuth){
        if(to.name==='path1-2'){
            next()
        }else{
            alert('您没有访问该地址的权限')
        }
    }else{
        next()
    }
})

6.10.2 全局后置路由守卫 title的设置

  • 只有tofrom两个参数
  • meta中给每个路由添加title属性,这样就可以在不同的路由展示不同的标题
router.afterEach((to,from)=>{
    document.title = to.meta.title || '欢迎使用'
})
  • 还需要修改另一个地方才能让标题完美
    在这里插入图片描述

6.11 局部路由守卫

6.11.1 path守卫

  1. 代码的位置:在路由文件的路由对象中
    在这里插入图片描述
beforeEnter(to,from,next){
  next()                        
}
  1. 调用时机:在本身路由执行之前
  2. 参数:to就是路由本身,from:跳转之前的路由

6.11.2 组件守卫

  1. 必须是路由中用到的组件才能使用组件守卫
  2. 代码的位置:在Vue文件的组件中
    在这里插入图片描述
  3. 执行时机
    // 路由组件执行之前
    beforeRouteEnter(to,from,next){
      next()
    },
    // 离开路由组件之前
    beforeRouteLeave(to,from,next){
      next()
    }

7 发布到服务器

  • 下载java,tomcat,并配置到环境变量
  • 在路由中增加属性mode设置为history模式或者hash模式,默认是hash模式
  • 在终端中打包:npm run build
  • 将生成的dist目录中的内容全部拷贝到tomcat的webapp/root目录中
  1. 路径中带有#的是hash模式,#后的的内容不会作为路径提交到服务器
    在这里插入图片描述
  2. 不带有#的模式是history模式,整个浏览器的内容作为路径提交到服务器,但是服务器中没有路径对应的资源,所以报404错误
  3. 解决history模式的的404问题
    在服务器发布网站的目录root中,新建WEB-INF文件夹,新建web.xml文件,将一下内容复制到文件中
<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
                      https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
  version="6.0"
  metadata-complete="true">

    <error-page>
        <error-code>404</error-code>
        <location>/index.html</location>
    </error-page>

</web-app>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/125901.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Hello Qt!

目录 1. 什么是Qt 2. Qt中的模块 3. 下载安装 4. QtCreator 4. Hello Qt 解释 .pro 解释 main.cpp 解释 mainwindow.ui 解释 mainwindow.h 解释 mainwindow.cpp 5. Qt 中的窗口类 5.1 基础窗口类 5.2 窗口的显示 6. Qt 的坐标体系 7. 内存回收 1. 什么是Qt 是一…

评估APP网页小程序代码UI开发H5估价师怎么评估开发精确研发价格?

作为一名应用程序开发评估师&#xff0c;可能涉及到的主要任务是为特定的应用程序提供估算开发成本和所需时间预测。为了为一个应用程序更准确地评估价格&#xff0c;须遵循以下几个步骤&#xff1a; 问: 如何让一个App更好、更精确地评估出价格&#xff1f; 答: 以下是一个可…

一款功能强大的web目录扫描器专业版

dirpro 简介 dirpro 是一款由 python 编写的目录扫描器&#xff0c;操作简单&#xff0c;功能强大&#xff0c;高度自动化。 自动根据返回状态码和返回长度&#xff0c;对扫描结果进行二次整理和判断&#xff0c;准确性非常高。 已实现功能 可自定义扫描线程 导入url文件进…

1. Collection,List, Map, Queue

1. java集合框架体系结构图 2. Collection派生的子接口 其中最重要的子接口是&#xff1a; 1&#xff09;List 表示有序可重复列表&#xff0c;重要的实现类有&#xff1a;ArrayList, LinkedList ArrayList特点&#xff1a;底层数组实现&#xff0c;随机查找快&#xff0c;增删…

centos 上redis以及远程连接工具rdm安装与使用

目录 一 安装包准备 二 安装 三 启动 redis 四 rdm 连接 redis 一 安装包准备 redis 6.2.4 网盘资源&#xff1a; 链接: https://pan.baidu.com/s/1R120Va9FEyraLdiPe9fBHg?pwdgq9i 提取码: gq9i rdm 网盘资源&#xff1a; 链接: https://pan.baidu.com/s/1GiYnfIuQdSUmM…

服装展示服务预约小程序的内容如何

互联网电商深入&#xff0c;很多服装商家开始线上卖货经营、会员管理及私域营销等&#xff0c;这也是当今商家们的一个优选项&#xff0c;当然除了直接卖货以外&#xff0c;展示和预约、客户交互也同样是不少商家需要的。 那么商家通过服装展示预约小程序能够实现什么效果呢&a…

19 数据中心详解

1、数据中心的概念 其实平时我们不管是看新闻&#xff0c;视频&#xff0c;下载文件等&#xff0c;最终访问的目的地都是在数据中心里面。数据中心存放的是服务器&#xff0c;区别于我们平时使用的笔记本或者台式机。 机架&#xff1a;数据中心的服务器被放在一个个叫作机架&…

【发布】DDD 工程脚手架 + 一键安装分布式技术栈环境!

作者&#xff1a;小傅哥 博客&#xff1a;https://bugstack.cn 沉淀、分享、成长&#xff0c;让自己和他人都能有所收获&#xff01;&#x1f604; 大家好&#xff0c;我是技术UP主小傅哥。 写了那么多案例工程&#xff0c;开发了那么多技术项目。那小傅哥做的这些案例和项目是…

第十八章总结

一.Swing概述 二.Swing常用窗体 1.JFrame窗体 创建一个不可见、具有标题的窗体&#xff0c;关键代码&#xff1a; JFrame jfnew JFrame("登陆系统"); Container containerjf.getContentPane(); 在创建窗体后&#xff0c;先调用getContentPane()方法将窗体转…

2023年Q3乳品行业数据分析(乳品市场未来发展趋势)

随着人们生活水平的不断提高以及对健康生活的追求不断增强&#xff0c;牛奶作为优质蛋白和钙的补充品&#xff0c;市场需求逐年增加。 今年Q3&#xff0c;牛奶乳品市场仍呈增长趋势。根据鲸参谋电商数据分析平台的相关数据显示&#xff0c;2023年7月-9月&#xff0c;牛奶乳品市…

C# OpenCvSharp 通过特征点匹配图片

SIFT匹配 SURF匹配 项目 代码 using OpenCvSharp; using OpenCvSharp.Extensions; using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text.RegularExpressions; using System.Windows.Forms; using static System.Net…

(C++17) variant的使用与union对比

文章目录 前言与需求union内存映射图C11的union 使用ref示例构造普通构造置空emplacemonostate 访问std::get<>std::holds_alternative<>获取指针std::get_if<>获取可选数量个数std::variant_size END 前言与需求 联合体&#xff0c;是在C语言时代就存在的概…

Global_Mapper_Pro_25.0安装教程大全

一. 下载&#xff1a; http://dt1.8tupian.net/2/29913a55b1000.pg3二. 介绍&#xff1a; Global Mapper Pro 25是领先的GIS数据处理解决方案&#xff01;提供了一整套符合标准的功能来提升您的操作和技能&#xff0c;您可以最合理的利用您的工具集来完成以前复杂的工作任务&a…

矢量图形编辑软件Boxy SVG mac中文版软件特点

Boxy SVG mac是一款基于Web的矢量图形编辑器&#xff0c;它提供了一系列强大的工具和功能&#xff0c;可帮助用户创建精美的矢量图形。Boxy SVG是一款好用的软件&#xff0c;并且可以在Windows、Mac和Linux系统上运行。 Boxy SVG mac软件特点 简单易用&#xff1a;Boxy SVG的用…

说说对React中类组件和函数组件的理解?有什么区别?

一、类组件 类组件&#xff0c;顾名思义&#xff0c;也就是通过使用ES6类的编写形式去编写组件&#xff0c;该类必须继承React.Component 如果想要访问父组件传递过来的参数&#xff0c;可通过this.props的方式去访问 在组件中必须实现render方法&#xff0c;在return中返回…

【LLMs】从大语言模型到表征再到知识图谱

从大语言模型到表征再到知识图谱 InstructGLMLLM如何学习拓扑&#xff1f;构建InstructGLM泛化InstructGLM补充参考资料 2023年8月14日&#xff0c;张永峰等人的论文《Natural Language is All a Graph Needs》登上arXiv街头&#xff0c;轰动一时&#xff01;本论文概述了一个名…

带头+双向+循环链表

前言&#xff1a; 前面我们已经学习了单链表的结构及其功能特点&#xff0c;也了解了单链表在实现一些功能时出现的一些缺点&#xff0c;比如在删除某个节点前面一个节点时就需要再开一个变量来存放前面一个节点的信息&#xff0c;这样就显得不灵活&#xff0c;为了使链表实现功…

“可一学院”新课程《区块链企业应用》正式上线

2023年8月&#xff0c;上海可一澈科技有限公司启动了一站式区块链学习平台“可一学院BitClass”。9月6日&#xff0c;可一学院正式推出一门新课程《区块链企业应用》&#xff0c;这门课程将帮助学习者了解企业需要什么样的区块链&#xff0c;以及应该如何运用这项技术来推动自身…

GIT的安装与常见命令

Git的介绍 Git是一个开源的分布式版本控制系统&#xff0c;最初由Linus Torvalds在2005年创建用于管理Linux内核的开发&#xff0c;现在已成为全球最流行的版本控制工具之一。 Git可以跟踪代码的修改&#xff0c;记录开发历程&#xff0c;保证多人合作开发时代码的一致性&…

5个写自定义函数小练习

计算列表平均值、素数判定、反转字符串&#xff0c;查找整数列表最大最小值、统计字符串中元音字母个数(大小写字不敏感)。 (笔记模板由python脚本于2023年11月09日 21:50:35创建&#xff0c;本篇笔记适合熟悉Python函数及基本数据类型的coder翻阅) 【学习的细节是欢悦的历程】…