【十】Vue之高级

【一】ref属性

【1】详解

  • 被用来给元素或子组件注册引用信息(id的替代者)
  • 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)
  • 在Vue中,$refs是一个特殊的属性,用于给元素或子组件注册引用信息。
    • 它允许我们在模板或组件中通过引用名称来访问对应的DOM元素或组件实例。
  • 当我们使用$refs在HTML标签上打标识时,可以直接获取到真实的DOM元素。
    • 例如,我们可以通过给一个input元素添加ref属性来获取这个输入框的值或者操作该元素的其他属性,具体代码如下:
<template>
  <div>
    <input ref="myInput" type="text">
    <button @click="handleClick">获取输入框的值</button>
  </div>
</template>

<script>
export default {
  methods: {
    handleClick() {
      const inputValue = this.$refs.myInput.value;
      console.log(inputValue);
    }
  }
}
</script>
  • 在上述代码中,我们给input元素添加了一个名为myInput的ref属性。
    • 然后,通过this.$refs.myInput.value就可以获取到输入框的值。
  • 类似地,当我们在组件标签上使用$refs打标识时,可以获取到这个组件的实例对象(vc)。
    • 这样可以让我们直接调用该组件实例上的方法或访问其属性。下面是一个示例代码:
<template>
  <div>
    <child-component ref="myComponent"></child-component>
    <button @click="callChildMethod">调用子组件方法</button>
  </div>
</template>

<script>
import ChildComponent from './ChildComponent.vue';

export default {
  components: {
    ChildComponent
  },
  methods: {
    callChildMethod() {
      this.$refs.myComponent.childMethod();
    }
  }
}
</script>
  • 在上述代码中,我们引入了一个名为ChildComponent的子组件,并在父组件中使用ref属性给此子组件打上名为myComponent的标识。
    • 然后,通过this.$refs.myComponent可以访问到子组件的实例对象。
    • 接着,我们可以调用该实例上的childMethod方法来执行特定的逻辑。

总结来说

  • $refs允许我们在Vue中获取到真实DOM元素或者组件实例对象,从而能够进行进一步的操作或交互。
  • 但需要注意的是,尽量避免过度滥用$refs,并遵循Vue的响应式规则来编写可维护性和可测试性的代码。

【2】案例

<template>
  <div>
    <h1 v-text="msg" ref="title"></h1>
    <button ref="btn" @click="showDOM">点我输出上方的DOM元素</button>
    <HelloWorld ref="sch" />
  </div>
</template>

<script>
import HelloWorld from "./components/HelloWorld.vue";

export default {
  name: "App",
  components: { HelloWorld },
  data() {
    return {
      msg: "lqz",
    };
  },
  methods: {
    showDOM() {
      console.log(this.$refs.title); //真实DOM元素
      console.log(this.$refs.btn); //真实DOM元素
      console.log(this.$refs.sch); //School组件的实例对象(vc)
    },
  },
};
</script>

【二】props配置项

【1】引入

  • 功能:

    • 让组件接收外部传过来的数据
  • 传递数据:

  • 接收数据:

    • 第一种方式(只接收):props:['name']

    • 第二种方式(限制类型):props:

    • 第三种方式(限制类型、限制必要性、指定默认值):

      props:{
      	name:{
      	type:String, //类型
      	required:true, //必要性
      	default:'老王' //默认值
      	}
      }
  • 在Vue中,props是一个配置项,用于让组件接收外部传递的数据。
  • 通过props,我们可以将父组件的数据传递给子组件,并在子组件中使用这些数据。
  • 以下是三种常见的props使用方式:

【2】第一种方式(只接收):props:['name']

  • 这种方式是最简单的props配置方式
  • 通过数组的形式,可以接收传递给组件的任意类型的数据。
  • 在子组件中,我们可以通过this.name来访问这个数据。
  • 例如:
<template>
  <div>
    <p>{{name}}</p>
  </div>
</template>

<script>
export default {
  props: ['name']
}
</script>
  • 在这个例子中,父组件可以通过传递一个名为name的数据给子组件,子组件然后可以直接使用this.name来引用这个数据。

【3】第二种方式(限制类型):props:

  • 这种方式可以限制传递给子组件的数据类型。
  • 在props配置中,我们可以使用对象的形式,并指定一个名为name的属性,并将其类型设置为String。
  • 这样就可以确保只有字符串类型的数据被传递给子组件。
  • 例如:
<template>
  <div>
    <p>{{name}}</p>
  </div>
</template>

<script>
export default {
  props: {
    name: String
  }
}
</script>
  • 在这个例子中,父组件只能传递一个字符串类型的数据给子组件,否则会在开发者工具的控制台中抛出警告。

【4】第三种方式(限制类型、限制必要性、指定默认值):

  • 这种方式进一步扩展了props的功能。我们可以通过对象的形式来设置更多的约束条件。例如:
<template>
  <div>
    <p>{{name}}</p>
  </div>
</template>

<script>
export default {
  props: {
    name: {
      type: String,
      required: true,
      default: 'John'
    }
  }
}
</script>
  • 在这个例子中
    • 我们通过props对象的方式定义了一个name属性,并设置了其类型为String,必须传递给子组件,且默认值为'John'。
    • 如果父组件没有传递name属性,则会产生一个控制台警告。如果传递了name属性,但不是字符串类型,也会抛出一个警告。
  • 通过以上props的使用方式,我们可以让组件接收外部传递的数据,并进行类型限制、必要性约束以及默认值设置,从而确保数据传递的正确性和可靠性。
  • 这样就能够更好地实现组件之间的数据通信和复用。

【三】mixin(混入)

【1】简解

mixin(混入)
功能:可以把多个组件共用的配置提取成一个混入对象

使用方式:

第一步定义混入:

export const hunhe = {
  methods: {
    showName() {
      alert(this.name);
    },
  },
  mounted() {
    console.log("你好啊!");
  },
};
export const hunhe2 = {
  data() {
    return {
      x: 100,
      y: 200,
    };
  },
};

第二步:使用混入(全局)

//引入Vue
import Vue from 'vue'
//引入App
import App from './App.vue'
import {hunhe,hunhe2} from './mixin'
//关闭Vue的生产提示
Vue.config.productionTip = false

Vue.mixin(hunhe)
Vue.mixin(hunhe2)


//创建vm
new Vue({
	el:'#app',
	render: h => h(App)
})

第三步:使用混入(局部)

<template>
  <div>

  </div>
</template>

<script>
import {hunhe,hunhe2} from '../mixin'

export default {
  name: "App",
  data() {
    return {
      name: "lqz",
    };
  },
  mixins:[hunhe,hunhe2]
};
</script>

【2】详解

  • 在Vue中,mixin是一种将多个组件共用的配置提取成一个混入对象的方式。
  • 通过使用mixin
    • 我们可以将一些重复的逻辑、方法、组件选项等抽离出来
    • 然后混入到多个组件中,以便实现代码的复用和组件的扩展。
  • 使用mixin的方式如下:
// 定义一个混入对象
const myMixin = {
  data() {
    return {
      message: 'Hello, mixin!'
    };
  },
  methods: {
    greet() {
      console.log(this.message);
    }
  }
};

// 使用混入对象
Vue.component('my-component', {
  mixins: [myMixin],
  mounted() {
    this.greet(); // 调用混入对象中的方法
  }
});
  • 在上述示例中
    • 首先定义了一个名为myMixin的混入对象。
    • 这个混入对象包含了一个data选项(数据)和一个methods选项(方法),其中data选项中定义了一个message变量,methods选项中定义了一个greet方法。
  • 然后
    • 我们使用Vue.component创建了一个名为my-component的组件,并通过mixins选项将myMixin混入到该组件中。
    • 在mounted钩子函数中,我们可以通过this来访问混入对象中的数据和方法,例如调用greet方法。
  • 使用mixin的好处在于可以避免代码的重复,尤其是当多个组件都需要使用相同的逻辑或方法时。
    • 通过将这些共用的配置提取成一个混入对象,我们可以在多个组件中使用mixin选项来引入这些配置,避免了重复编写相同的代码,提高了代码的重用性和维护性。
  • 需要注意的是
    • 混入是一种强大但也具有潜在风险的机制。
    • 因为混入的选项会被合并到组件自身的选项中,所以如果混入对象和组件定义了相同的选项,可能会导致命名冲突和意外结果。
    • 因此,在使用混入时,应当注意命名冲突,并确保混入对象和组件之间的选项不会产生冲突。
  • 总结起来
    • mixin是一种提取多个组件共用配置的方式,可以减少重复代码并增加代码的可维护性。
    • 通过混入,我们可以将一些通用的逻辑从组件中抽离出来,使得组件更加简洁和专注于自身的业务。

【四】插件

  1. 功能:用于增强Vue

  2. 本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。

  3. 定义插件:plugins/index.js

    import Vue from "vue";
    
    export default {
        install(a) {
            console.log('执行了插件', a)
            // 定义指令
            //定义全局指令:跟v-bind一样,获取焦点
            Vue.directive("fbind", {
                //指令与元素成功绑定时(一上来)
                bind(element, binding) {
                    element.value = binding.value;
                },
                //指令所在元素被插入页面时
                inserted(element, binding) {
                    element.focus();
                },
                //指令所在的模板被重新解析时
                update(element, binding) {
                    element.value = binding.value;
                },
            });
    
            //定义混入,所有vc和vm上都有name和lqz
            Vue.mixin({
                data() {
                    return {
                        name: '彭于晏',
                        age: 19,
                    };
                },
            });
    
            // 原型上放方法,所有vc和vm都可以用hello
            Vue.prototype.hello = () => {
                alert("你好啊");
            };
    
    
        }
    }
  4. 使用插件:main.js中

    import plugins from './plugins'
    
    Vue.use(plugins, 1, 2, 3);
  5. App.vue中

<template>
  <div>
  {{name}}
    <input type="text" v-fbind:value="v">
    <br>
    <button @click="hello">点我</button>
  </div>
</template>

<script>

export default {
  name: "App",
  data() {
    return {
      v:'xxx'
    };
  },
};
</script>

【五】scoped样式

  • 作用:让样式在局部生效,防止冲突。
  • 写法:<style scoped>
  • 在Vue中,scoped样式是一种用于让样式在局部生效,防止冲突的特殊样式写法。
    • 通过在组件的<style>标签上添加scoped属性,可以将该样式限定在当前组件的范围内,不会影响其他组件。
  • 使用scoped样式的方式如下:
<template>
  <div class="container">
    <p class="text">Hello, world!</p>
  </div>
</template>

<style scoped>
.container {
  background-color: #f0f0f0;
}
.text {
  color: red;
}
</style>
  • 在上述示例中,我们在组件的<style>标签上添加了scoped属性。
    • 这意味着.container类和.text类将只会作用于当前组件,并不会对其他组件产生影响。
  • 在页面渲染时,Vue会自动给.container.text类名生成一个唯一的哈希值,并将其添加到对应的元素上
    • 例如 data-v-XXXXXXX
    • 这样一来,每个组件都有了自己独特的类名,从而保证了样式的局部生效性。
  • 使用scoped样式的好处在于可以避免样式冲突问题。
    • 在大型项目中,可能存在多个组件具有相同的类名或选择器,如果没有使用scoped样式,那么它们的样式会相互影响,可能导致样式的混乱和不可预测的结果。
    • 而通过使用scoped样式,我们可以确保每个组件的样式只作用于对应的组件,避免了样式冲突问题,提高了代码的可维护性。
  • 需要注意的是,scoped样式只会将组件内部的样式限定在组件自身范围内,并不影响子组件的样式。
    • 如果希望将样式限制在子组件内部,可以使用::v-deep>>>选择器:
<template>
  <div class="container">
    <ChildComponent></ChildComponent>
  </div>
</template>

<style scoped>
.container >>> .child {
  color: blue;
}
</style>
  • 在上述示例中,.container类下的.child类的样式会限定在当前组件及其子组件中。

  • 总结起来,scoped样式是一种让样式在局部生效,防止冲突的特殊写法。

    • 通过在组件的<style>标签上添加scoped属性,可以将样式限定在当前组件的范围内。
    • 这可以避免样式冲突问题,提高代码的可维护性,并使得每个组件的样式独立且具有局部生效性。

【六】插槽

【1】简解

  1. 作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于 父组件 ===> 子组件
  2. 分类:默认插槽、具名插槽
  3. 使用方式:
<template v-slot:footer>
    <div>html结构2</div>
</template>

【2】详解

(1)介绍

  • 插槽(slot)是一种用于组件间通信的方式,在Vue中主要用于父组件向子组件指定位置插入HTML结构。
  • 通过插槽,我们可以将父组件中的内容传递给子组件,并在子组件中进行展示或处理。

(2)插槽的作用有两个方面:

  • 实现父组件向子组件传递内容:

    • 通过插槽,父组件可以将任意HTML内容传递给子组件,子组件可以将这些内容插入到指定位置上。
  • 封装可复用组件:

    • 通过定义插槽,子组件可以提供可配置的结构,使得父组件可以根据自己的需要定制子组件的外观和功能。

(3)插槽可以分为默认插槽和具名插槽两种类型。

默认插槽:
  • 默认插槽是最基本的插槽形式,在一个组件中可以定义一个默认插槽,使用<slot>标签表示。
  • 父组件中的内容将会替换掉子组件中的<slot>标签。
<!-- 子组件 MyComponent -->
<template>
  <div>
    <h2>子组件内容:</h2>
    <slot></slot>
  </div>
</template>

<!-- 父组件 -->
<template>
  <my-component>
    <p>父组件传递的内容</p>
  </my-component>
</template>
  • 在上述示例中,父组件中的<p>标签将会替换掉子组件中的<slot>标签,从而实现了父组件传递内容给子组件。
具名插槽:
  • 具名插槽是一种可以在子组件中定义多个插槽,并且可以根据需要在父组件中选择性地进行使用的插槽形式。
  • 使用<slot>标签加上name属性来定义和使用具名插槽。
<!-- 子组件 MyComponent -->
<template>
  <div>
    <h2>子组件内容:</h2>
    <slot name="header"></slot>
    <slot></slot>
    <slot name="footer"></slot>
  </div>
</template>

<!-- 父组件 -->
<template>
  <my-component>
    <template v-slot:header>
      <!-- 使用具名插槽 -->
      <h3>这是头部插槽的内容</h3>
    </template>

    <p>父组件传递到默认插槽的内容</p>

    <template v-slot:footer>
      <!-- 使用具名插槽 -->
      <h3>这是尾部插槽的内容</h3>
    </template>
  </my-component>
</template>
  • 在上述示例中,父组件通过<template>标签加上v-slot指令来使用具名插槽。通过这种方式,可以将特定内容分别插入到子组件的不同插槽位置上。
  • 需要注意的是,如果子组件中未使用<slot>标签或没有具名插槽,那么父组件中传递给子组件的内容将会被忽略。

(4)总结

  • 插槽是一种用于实现父组件向子组件传递内容的机制,在Vue中分为默认插槽和具名插槽两种类型。
  • 默认插槽用于简单地替换子组件中的<slot>标签,而具名插槽可以在子组件中定义多个插槽位置,并可以根据需要在父组件中选择性地进行插入。
  • 通过使用插槽,可以实现父子组件间的数据交流和灵活的组件复用。

【七】Elementui的使用

https://element.eleme.cn/#/zh-CN/component/installation

【八】vuex的使用

【1】概念

  • 在Vue中实现集中式状态(数据)管理的一个Vue插件,对vue应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间通信的方式,且适用于任意组件间通信。

【2】何时使用?

  • 多个组件需要共享数据时

【3】搭建vuex环境

  • 创建文件:src/store/index.js
//引入Vue核心库
   import Vue from 'vue'
   //引入Vuex
   import Vuex from 'vuex'
   //应用Vuex插件
   Vue.use(Vuex)
   
   //准备actions对象——响应组件中用户的动作
   const actions = {}
   //准备mutations对象——修改state中的数据
   const mutations = {}
   //准备state对象——保存具体的数据
   const state = {}
   
   //创建并暴露store
   export default new Vuex.Store({
   	actions,
   	mutations,
   	state
   })
  • main.js中创建vm时传入store配置项
......
   //引入store
   import store from './store'
   ......
   
   //创建vm
   new Vue({
   	el:'#app',
   	render: h => h(App),
   	store
   })

【4】基本使用

  • 初始化数据、配置actions、配置mutations,操作文件store.js
//引入Vue核心库
   import Vue from 'vue'
   //引入Vuex
   import Vuex from 'vuex'
   //引用Vuex
   Vue.use(Vuex)
   
   const actions = {
       //响应组件中加的动作
   	jia(context,value){
   		// console.log('actions中的jia被调用了',miniStore,value)
   		context.commit('JIA',value)
   	},
   }
   
   const mutations = {
       //执行加
   	JIA(state,value){
   		// console.log('mutations中的JIA被调用了',state,value)
   		state.sum += value
   	}
   }
   
   //初始化数据
   const state = {
      sum:0
   }
   
   //创建并暴露store
   export default new Vuex.Store({
   	actions,
   	mutations,
   	state,
   })
  • 组件中读取vuex中的数据:$store.state.sum
  • 组件中修改vuex中的数据:$store.dispatch('action中的方法名',数据)$store.commit('mutations中的方法名',数据)
<template>
  <div>

    <hr>
    {{sum}}
    <button @click="handleClick">点我</button>
  </div>
</template>

<script>

export default {
  name: "App",
  data() {
    return {
      v:'xxx',
      sum:this.$store.state.sum
    };
  },
  methods:{
    handleClick(){
      // action中的方法名
      // this.$store.dispatch('jia',2)
      // console.log(this.$store.state.sum)

      //mutations中的方法名
      this.$store.commit('JIA',4)
      console.log(this.$store.state.sum)
    }
  }
};
</script>
  • 备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch,直接编写commit

【九】Router使用

【1】说明

  1. 官方提供的用来实现SPA 的vue 插件
  2. github: https://github.com/vuejs/vue-router
  3. 中文文档: http://router.vuejs.org/zh-cn/
  4. 下载: npm install vue-router --save
//引入VueRouter
   import VueRouter from 'vue-router'
   //引入Luyou 组件
   import About from '../components/About'
   import Home from '../components/Home'
   
   //创建router实例对象,去管理一组一组的路由规则
   const router = new VueRouter({
   	routes:[
   		{
   			path:'/about',
   			component:About
   		},
   		{
   			path:'/home',
   			component:Home
   		}
   	]
   })
   
   //暴露router
   export default router

【2】相关API

(1)VueRouter(): 用于创建路由器的构建函数

new VueRouter({
// 多个配置项
})

(2)路由配置

routes: [
	{ // 一般路由
		path: '/about',
		component: About
	},
	{ // 自动跳转路由
		path: '/',
		redirect: '/about'
	}
]

(3)注册路由

import router from './router'
new Vue({
	router
})

(4)使用路由组件标签

  • <router-link>: 用来生成路由链接
<router-link to="/xxx">Go to XXX</router-link>
  • <router-view>: 用来显示当前路由组件界面
<router-view></router-view>

【3】路由嵌套

  • 在Vue.js应用程序中,Vuex和Vue Router可以结合使用以管理状态和路由。当涉及到嵌套路由时,你可以使用Vuex来集中管理共享的状态数据。

  • 下面是一些处理Vue Router嵌套路由时如何使用Vuex的步骤:

    • 创建Vuex存储:

      • 首先,在你的Vue.js应用程序中创建Vuex存储。

      • 你可以使用Vuex提供的Vuex.Store构造函数创建一个存储对象,并将其导入你的应用程序。

      • 存储对象可以包含多个模块,每个模块都有自己的状态、mutations、actions等。

    • 定义模块:

      • 如果你计划使用嵌套路由,那么你可能需要为每个路由模块定义一个对应的Vuex模块。

      • 这样做可以使你能够在每个路由级别上独立管理状态。

    • 设置路由守卫:

      • 你可以使用Vue Router提供的导航守卫来确保你的Vuex状态与路由的层次结构保持同步。

      • 例如,你可以使用beforeEach导航守卫来在切换路由前更新对应的Vuex模块中的状态。

    • 在组件中使用:

      • 一旦你设置了Vuex存储并在路由级别定义了对应的模块,你就可以在组件中使用它们了。
      • 你可以通过使用mapState辅助函数将Vuex状态映射到组件的计算属性上,并使用mapActions辅助函数将Vuex的actions映射到组件的方法中。
  • 这样,你就可以在Vue.js应用程序中实现路由嵌套时的状态管理。

    • 通过集中管理状态,你可以更方便地跨组件、跨路由访问和修改状态数据,以及确保状态在不同的路由层次结构中保持一致。

【4】向路由组件传递数据

//1 路由配置
children: [
	{
	path: 'mdetail/:id',
	component: MessageDetail
	}
]
// 2 <router-link :to="'/home/message/mdetail/'+m.id">{{m.title}}</router-link>

// 3 this.$route.params.id

【5】相关API

  • this.$router.push(path): 相当于点击路由链接(可以返回到当前路由界面)
  • this.$router.replace(path): 用新路由替换当前路由(不可以返回到当前路由界面)
  • this.$router.back(): 请求(返回)上一个记录路由
  • this.$router.go(-1): 请求(返回)上一个记录路由
  • this.$router.go(1): 请求下一个记录路由
  • this.$router.push(path)

    • 这个方法相当于点击一个路由链接,它会将用户导航到指定的路径(path)。

    • 与点击链接不同的是,使用这个方法进行导航时,用户可以返回到当前路由界面。

    • 这个方法会添加新的历史记录,因此在浏览器的历史记录中会增加一个新的页面。

  • this.$router.replace(path)

    • 这个方法用新的路由替换当前的路由,它不会添加新的历史记录,因此用户不能返回到当前路由界面。

    • 使用这个方法进行导航时,当前路由会被新的路由替换掉,浏览器的历史记录中不会增加新的页面。

  • this.$router.back()

    • 这个方法用于请求(返回到)上一个记录的路由。

    • 它相当于用户点击浏览器的返回按钮。

    • 调用这个方法会导航至上一个记录的路由,并更新浏览器的历史记录。

  • this.$router.go(-1)

    • 这个方法也是请求返回上一个记录的路由,它与this.$router.back()的作用相同,都是返回上一个路由。

    • 使用这个方法时,可以通过传入参数-1来指定要返回的步数。

  • this.$router.go(1)

    • 这个方法用于请求导航到下一个记录的路由,类似于用户点击浏览器的前进按钮。
    • 它可以通过传入参数1来指定要前进的步数。

【6】多级路由

routes:[
   	{
   		path:'/about',
   		component:About,
   	},
   	{
   		path:'/home',
   		component:Home,
   		children:[ //通过children配置子级路由
   			{
   				path:'news', //此处一定不要写:/news
   				component:News
   			},
   			{
   				path:'message',//此处一定不要写:/message
   				component:Message
   			}
   		]
   	}
   ]

// 跳转
<router-link to="/home/news">News</router-link>

【7】命名路由(可以简化路由的跳转)

{
      	path:'/demo',
      	component:Demo,
      	children:[
      		{
      			path:'test',
      			component:Test,
      			children:[
      				{
                name:'hello' //给路由命名
      					path:'welcome',
      					component:Hello,
      				}
      			]
      		}
      	]
      }
 <!--简化前,需要写完整的路径 -->
      <router-link to="/demo/test/welcome">跳转</router-link>
      
      <!--简化后,直接通过名字跳转 -->
      <router-link :to="{name:'hello'}">跳转</router-link>
      
      <!--简化写法配合传递参数 -->
      <router-link 
      	:to="{
      		name:'hello',
      		query:{
      		   id:666,
             title:'你好'
      		}
      	}"
      >跳转</router-link>

【8】router-link的replace属性

  • 作用:控制路由跳转时操作浏览器历史记录的模式
  • 浏览器的历史记录有两种写入方式:分别为push和replace,push是追加历史记录,replace是替换当前记录。路由跳转时候默认为push
  • 如何开启replace模式:News

【9】编程式路由导航

//$router的两个API
   this.$router.push({
   	name:'xiangqing',
   		params:{
   			id:xxx,
   			title:xxx
   		}
   })
   
   this.$router.replace({
   	name:'xiangqing',
   		params:{
   			id:xxx,
   			title:xxx
   		}
   })
   this.$router.forward() //前进
   this.$router.back() //后退
   this.$router.go() //可前进也可后退

【10】路由守卫

  1. 作用:对路由进行权限控制
  2. 分类:全局守卫、独享守卫、组件内守卫

全局守卫

// 该文件专门用于创建整个应用的路由器
import VueRouter from 'vue-router'
//引入组件
import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'

//创建并暴露一个路由器
const router =  new VueRouter({
	routes:[
		{
			name:'guanyu',
			path:'/about',
			component:About,
			meta:{title:'关于'}
		},
		{
			name:'zhuye',
			path:'/home',
			component:Home,
			meta:{title:'主页'},
			children:[
				{
					name:'xinwen',
					path:'news',
					component:News,
					meta:{isAuth:true,title:'新闻'}
				},
				{
					name:'xiaoxi',
					path:'message',
					component:Message,
					meta:{isAuth:true,title:'消息'},
					children:[
						{
							name:'xiangqing',
							path:'detail',
							component:Detail,
							meta:{isAuth:true,title:'详情'},

							//props的第一种写法,值为对象,该对象中的所有key-value都会以props的形式传给Detail组件。
							// props:{a:1,b:'hello'}

							//props的第二种写法,值为布尔值,若布尔值为真,就会把该路由组件收到的所有params参数,以props的形式传给Detail组件。
							// props:true

							//props的第三种写法,值为函数
							props($route){
								return {
									id:$route.query.id,
									title:$route.query.title,
									a:1,
									b:'hello'
								}
							}

						}
					]
				}
			]
		}
	]
})

//全局前置路由守卫————初始化的时候被调用、每次路由切换之前被调用
router.beforeEach((to,from,next)=>{
	console.log('前置路由守卫',to,from)
	if(to.meta.isAuth){ //判断是否需要鉴权
		if(localStorage.getItem('name')==='lqz'){
			next()
		}else{
			alert('名不对,无权限查看!')
		}
	}else{
		next()
	}
})

//全局后置路由守卫————初始化的时候被调用、每次路由切换之后被调用
router.afterEach((to,from)=>{
	console.log('后置路由守卫',to,from)
	document.title = to.meta.title || 'lqz系统'
})

export default router

独享守卫

// 该文件专门用于创建整个应用的路由器
import VueRouter from 'vue-router'
//引入组件
import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'

//创建并暴露一个路由器
const router =  new VueRouter({
	routes:[
		{
			name:'guanyu',
			path:'/about',
			component:About,
			meta:{title:'关于'}
		},
		{
			name:'zhuye',
			path:'/home',
			component:Home,
			meta:{title:'主页'},
			children:[
				{
					name:'xinwen',
					path:'news',
					component:News,
					meta:{isAuth:true,title:'新闻'},
					beforeEnter: (to, from, next) => {
						console.log('独享路由守卫',to,from)
						if(to.meta.isAuth){ //判断是否需要鉴权
							if(localStorage.getItem('name')==='lqz'){
								next()
							}else{
								alert('名不对,无权限查看!')
							}
						}else{
							next()
						}
					}
				},
				{
					name:'xiaoxi',
					path:'message',
					component:Message,
					meta:{isAuth:true,title:'消息'},
					children:[
						{
							name:'xiangqing',
							path:'detail',
							component:Detail,
							meta:{isAuth:true,title:'详情'},

						}
					]
				}
			]
		}
	]
})


export default router

组件内守卫

//进入守卫:通过路由规则,进入该组件时被调用
   beforeRouteEnter (to, from, next) {
   },
   //离开守卫:通过路由规则,离开该组件时被调用
   beforeRouteLeave (to, from, next) {
   }


	//通过路由规则,进入该组件时被调用
		beforeRouteEnter (to, from, next) {
			console.log('About--beforeRouteEnter',to,from)
			if(to.meta.isAuth){ //判断是否需要鉴权
				if(localStorage.getItem('school')==='atguigu'){
					next()
				}else{
					alert('学校名不对,无权限查看!')
				}
			}else{
				next()
			}
		},

		//通过路由规则,离开该组件时被调用
		beforeRouteLeave (to, from, next) {
			console.log('About--beforeRouteLeave',to,from)
			next()
		}

【11】路由器的两种工作模式

  • 对于一个URL来说,hash值是指URL中的#符号及其后面的内容。

    • 在浏览器中,通过修改hash值可以改变URL的片段标识符,但是不会触发页面的完全刷新。

    • 例如,在http://example.com/#section1中,#section1就是hash值。

  • hash值不会包含在HTTP请求中发送给服务器。

    • 因为hash值是在客户端(浏览器)中进行的处理,用于在同一页面内进行导航或滚动到特定位置,不会被发送到服务器。
  • hash模式:

    • 在这种模式下,URL地址中始终带有#号。

      • 例如,http://example.com/#/section1
    • 这种模式具有以下特点:

      • 地址中带有#号,不够美观,可能影响用户体验;
      • 如果将地址通过第三方手机App分享,某些服务严格校验URL的合法性,可能会认为带有#号的地址是不合法的;
      • 在各种浏览器和设备上兼容性较好。
  • history模式:

    • 在这种模式下,URL地址不带有#号,称为干净、美观的URL。

      • 例如,http://example.com/section1
    • 这种模式具有以下特点:

      • 地址干净、美观,更符合用户的期望;
      • 在使用第三方手机App分享地址时不会被标记为不合法;
      • 与hash模式相比,兼容性稍差一些,某些旧版浏览器可能不支持history模式的路由。

假设我们正在开发一个电子商务网站,在商品列表页面中,用户点击某个商品后进入商品详情页。假设商品详情页的URL如下:

  1. hash模式:http://example.com/#/product/12345

    • 在hash模式下,地址中带有#号,例如#/product/12345表示是第12345号商品的详情页。
    • 当用户在该页面进行滚动或导航到其他内容时,hash值可以用于保持页面位置的同步。
    • 但如果将这个地址通过第三方手机App分享,某些严格校验URL合法性的App可能会认为这个地址不合法。
  2. history模式:http://example.com/product/12345

    • 在history模式下,地址中不带#号,例如/product/12345表示是第12345号商品的详情页。
    • 这种模式下的URL更干净、美观,更符合用户的期望。
    • 不会出现以#号开头的URL,因此在分享给第三方手机App时不会被标记为不合法。
    • 但如果用户在浏览器中刷新页面或直接访问该地址,需要服务器支持,否则可能会导致服务端返回404错误。

【12】localStorage和sessionStorage

//存:
    var obj = {"name":"xiaoming","age":"16"}
    localStorage.setItem("userInfo",JSON.stringify(obj));

//取:
    var user = JSON.parse(localStorage.getItem("userInfo"))
//删除:
    localStorage.remove("userInfo);
//清空:
    localStorage.clear();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值