Vue脚手架学习笔记

news2024/10/7 18:22:43

视频

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>

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C# OpenCvSharp 玉米粒计数

效果 项目 代码 using OpenCvSharp; using System; using System.Drawing; using System.Text; using System.Windows.Forms;namespace OpenCvSharp_Demo {public partial class frmMain : Form{public frmMain(){InitializeComponent();}string fileFilter "*.*|*.bmp;…

2023年CCF非专业级别软件能力认证第二轮 (CSP-S)提高级C++语言试题

2023年CCF非专业级别软件能力认证第二轮 &#xff08;CSP-S&#xff09;提高级C语言试题 编程题第 1 题 问答题 密码锁&#xff08;lock&#xff09; 题目描述 小Y有一把五个拨圈的密码锁。如图所示&#xff0c;每个拨圈上是从0到9的数字。每个拨圈都是从0到9的循环&#xf…

【算法 | 模拟No.4】AcWing 756. 蛇形矩阵 AcWing 40. 顺时针打印矩阵

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【AcWing算法提高学习专栏】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&a…

汉诺塔 --- 递归回溯算法练习一

目录 1. 什么叫汉诺塔 2. 分析算法原理 2.1. 当盘子的数量为1 2.2. 当盘子的数量为2 2.3. 当盘子的数量为3时 3. 编写代码 3.1. 挖掘重复子问题 3.2. 只关心某一个子问题如何处理 3.3. 递归的结束条件 3.4. 代码的编写 4. 递归展开图分析 1. 什么叫汉诺塔 力扣上的原…

Go并发编程(上)

目录 一、go语言当中的协程 二、MPG模型介绍 三、Goroutine 的使用 3.1 协程的开启 3.2 优雅地等待子协程结束 四、捕获子协程的panic 五、管道Channel 5.1、认识管道 5.2、Channel的遍历和关闭 5.3 、用管道实现生产者消费者模型 5.4、Channel一些使用细节和注意事…

揭秘!2024年热门的图标设计工具

在这个瞬息万变的世界里&#xff0c;设计师们对创新和实用的工具的渴望日益热切。我们需要时刻紧跟潮流&#xff0c;发掘和尝试最新&#xff0c;最有价值的图标设计工具&#xff0c;才能在剧烈的市场竞争中引人注目。以下是我们细心挑选的2024年图标设计工具的热门推荐&#xf…

CentOS 7 双网卡绑定热备 —— 筑梦之路

为什么需要&#xff1f; 1. 增强网络的可靠性 2. 保障服务的可持续性 3. 降低网卡故障带来的不良影响 有哪些模式&#xff1f; 模式0&#xff1a;轮询策略&#xff08;round robin&#xff09;&#xff0c;mode0&#xff0c;优点&#xff1a;流量提高一倍缺点&#xff1a;需要接…

《QT从基础到进阶·十五》用鼠标绘制矩形(QGraphicsView、QPainter、QGraphicsRectItem)

以下是鼠标绘制矩形最全的一种用法&#xff0c;完整源码将会放在最后面。 QT版本&#xff1a;5.15.2 VS版本&#xff1a;2019 1、在界面加载一张图片 界面的搭建选用QGraphicsView&#xff0c;自定义类GraphicsView继承QGraphicsView&#xff0c;在主程序中点击按钮打开 图片&…

opencv4笔记

图像二值化 全局法Threshold 大津法 大津法OSTU阈值类型——适用于双峰直方图 OTSU算法也称最大类间差法&#xff0c;由大津于1979年提出&#xff0c;被认为是图像分割中阈值选取的最佳算法&#xff0c;计算简单&#xff0c;不受图像亮度和对比度的影响&#xff0c;它是按图…

浅谈泛在电力物联网在智能配电系统应用

贾丽丽 安科瑞电气股份有限公司 上海嘉定 201801 摘要&#xff1a;在社会经济和科学技术不断发展中&#xff0c;配电网实现了角色转变&#xff0c;传统的单向供电服务形式已经被双向能流服务形式取代&#xff0c;社会多样化的用电需求也得以有效满足。随着物联网技术的发展&am…

c#数据类型

常量 /*常量是固定的量&#xff0c;在运行过程中不可以改变的量 const 来修饰不能改变的量*/ // public private protected internal 是访问修饰符using System.Security.Cryptography.X509Certificates;namespace ConsoleApp1 {internal class Program{public const int a 1…

科技云报道:数智化升级,如何跨越数字世界与实体产业的鸿沟?

科技云报道原创。 数智化是当下商业环境下最大的确定性。 2022年&#xff0c;中国数字经济规模达50.2万亿元&#xff0c;占国内生产总值比重提升至41.5%&#xff0c;数字经济成为推动经济发展的重要引擎。从小型创业公司到跨国巨头&#xff0c;数字化转型在企业发展历程中彰显…

javaSE学习笔记(二)数组,类,对象,成员变量,匿名对象,构造方法,static,final,封装,继承,多态

目录 三、面向对象 1.概述 面向过程与面向对象 面向对象编程特点 面向对象三个基本特征 2.数组 数组定义格式 数组的初始化 动态初始化 静态初始化 数组的内存分配 Java中的内存分配 数组的内存分配 数组的角标 数组的基本操作 二维数组&#xff08;实际开发几乎…

maven 下载和安装

点击进入Maven下载网址 Maven – Download Apache Maven Maven详细下载列表 Index of /dist/maven/maven-3 本地仓库配置文件 配置环境变量 idea编辑器配置 maven Javajdk配置 字节码版本是否11

yolov5 通过视频进行目标检测

打开yolov5-master文件夹&#xff0c;可以看到一个名为data的文件夹&#xff0c;在data中创建一个新的文件夹&#xff0c;命名为videos。 打开yolov5-master中的detect.py可以看到一行代码&#xff08;大概在245行左右&#xff09;为 parser.add_argument(--source, typestr,…

POI.5.2.4常用操作-数据导入导出常规操作

1、APACHE POI简介 Apache POI 简介是用Java编写的免费开源的跨平台的 Java API&#xff0c;Apache POI提供API给Java程式对Microsoft Office&#xff08;Excel、WORD、PowerPoint、Visio等&#xff09;格式档案读和写的功能。 1.1、其他操作Excel工具 Java Excel是一开放源码…

类直径树上贪心

http://cplusoj.com/d/senior/p/SS231109C 场上想到枚举点&#xff0c;然后最大值为高&#xff0c;然后可以求最大值。但是感觉计数会重 计数其实不会重&#xff0c;如图中&#xff0c;红色线段显然比蓝色线段优 所以我们枚举3叉点时没错的 #include<bits/stdc.h> usin…

Terminator终端

Terminator终端 terminator快捷键 sudo apt install terminator使用ctrlaltt开启终端 terminator快捷键 E O W 都是ctrl shift结合 alt方向键&#xff0c;为切换焦点 e分屏失效的解决方案&#xff08;原因是快捷键占有问题&#xff09; ibus-setup将表情符号注释就行了 …

ARMday2(环境创建+工程配置+创建文件+单步调试)

目录 一、汇编环境的创建 二、为工程配置链接脚本&#xff08;map.lds&#xff09; 三、为工程创建汇编文件 start.s 编程调试 接下来我们需要建立一个 start.s 汇编文件添加到我们的工程中去 四、对汇编代码进行单步调试&#xff08;仿真&#xff09; 五、汇编工程的编译 …

遍历List集合和Map进行修改和删除报java.util.ConcurrentModificationException错误详解

一、异常产生 当我们使用foreach迭代一个ArrayList或者HashMap时&#xff0c;如果尝试对集合做一些修改操作&#xff08;例如删除元素或新增&#xff09;&#xff0c;可能会抛出java.util.ConcurrentModificationException的异常。 javapublic static void main(String[] args)…