前端学习笔记 | Vue组件化编程

一、组件

1、引入组件

传统  :关系混乱,互相引用,复用性低,麻烦。

组件方式

组件可以嵌套

2、模块

因为js文件多而复杂,需要彼此引用依赖,提供一个特定js文件,以复用js,提高效率

3、组件

用来实现局部功能,是局部功能代码和资源的集合。

4、组件分类

(1)非单文件组件:一个文件包含n个组件

(2)单文件组件:一个文件只包含1个组件

 二、非单文件组件

1、vue使用组件的3大步骤

(1)定义组件(创建组件)

//使用Vue.extend(options)创建,其中options和new Vue(options)时传入的那个options几乎一样,但也有点区别;区别如下:
//1.el不要写,为什么? ——— 最终所有的组件都要经过一个vm的管理,由vm中的el决定服务哪个容器。
//2.data必须写成函数,为什么? ———— 避免组件被复用时,数据存在引用关系。
//备注:使用template可以配置组件结构。

const school = Vue.extend({
			template:`
				<div class="demo">
					<h2>学校名称:{{schoolName}}</h2>
					<h2>学校地址:{{address}}</h2>
					<button @click="showName">点我提示学校名</button>	
				</div>
			`,
			// el:'#root', //组件定义时,一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器。
			data(){
				return {
					schoolName:'尚硅谷',
					address:'北京昌平'
				}
			},
			methods: {
				showName(){
					alert(this.schoolName)
				}
			},
		})

(2)注册组件

//1.局部注册:靠new Vue的时候传入components选项
//2.全局注册:靠Vue.component('组件名',组件)

//全局注册组件
		Vue.component('hello',hello)


//局部注册注册组件
		//创建vm
		new Vue({
			el:'#root',
			data:{
				msg:'你好啊!'
			},

//注册组件(局部注册)
			components:{
				school,
				student
			}
		})

(3)使用组件(写组件标签)

<school></school>

2、注意事项-关于组件名
(1)一个单词组成:

  • 第一种写法(首字母小写):school
  • 第二种写法(首字母大写):School

(2)多个单词组成:

  • 第一种写法(kebab-case命名):my-school
  • 第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持)

(3)备注:

  • 组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。
  • 可以使用name配置项指定组件在开发者工具中呈现的名字。

3、注意事项-关于组件标签

  • 第一种写法:<school></school>
  • 第二种写法:<school/>
  • 备注:不用使用脚手架时,<school/>会导致后续组件不能渲染。

4、注意事项-一个简写方式
const school = Vue.extend(options) 可简写为:const school = options

5、组件的嵌套

一般用app组件管理所有的组件

//定义app组件
		const app = Vue.extend({
			template:`
				<div>	
					<hello></hello>
					<school></school>
				</div>
			`,
			components:{
				school,
				hello
			}
		})

 三、组件原理和重要的内置关系

1、VueComponent

(1)school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。

(2)我们只需要写<school/>或<school></school>,Vue解析时会帮我们创建school组件的实例对象, 即Vue帮我们执行的:new VueComponent(options)。

(3)特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!

(4)关于this指向:

  • 组件配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是VueComponent实例对象
  • new Vue(options)配置中:data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】

(5)VueComponent的实例对象,以后简称vc(也可称之为:组件实例对象)。Vue的实例对象,以后简称vm。

——vm管理众多vc

2、vm和vc区别

——vc是可复用的Vue实例

 vm可以写el配置属性,vc不可以指定el

vm的data对象可以用对象,vc只能用data(){return...}函数

3、一个重要的内置关系

!!!VueComponent.prototype.__proto__ === Vue.prototype

因为该内置关系,vc也可以用vm的原型对象

 四、单文件组件

1、.vue文件

仅支持template、script、style标签

<template>
	<div class="demo">
		<h2>学校名称:{{name}}</h2>
		<h2>学校地址:{{address}}</h2>
		<button @click="showName">点我提示学校名</button>	
	</div>
</template>

<script>
	 export default {
		name:'School',
		data(){
			return {
				name:'尚硅谷',
				address:'北京昌平'
			}
		},
		methods: {
			showName(){
				alert(this.name)
			}
		},
	}
</script>

<style>
	.demo{
		background-color: orange;
	}
</style>

2、APP.vue管理所有的组件

<template>
	<div>
		<School></School>
		<Student></Student>
	</div>
</template>

<script>
	//引入组件
	import School from './School.vue'
	import Student from './Student.vue'

	export default {
		name:'App',
		components:{
			School,
			Student
		}
	}
</script>

3、main.js是vue项目入口文件

引入组件+创建实例

import App from './App.vue'

new Vue({
	el:'#root',
	template:`<App></App>`,
	components:{App},
})

五、使用Vue脚手架

1、定义

Vue脚手架(command line interface,CLI)是Vue提供的开发工具

2、具体步骤

(1)备注

为防止npm下载缓慢,先配置npm淘宝镜像

npm config set registry https://registry.npmmirror.com/

(2)详细步骤

第一步(仅第一次执行):全局安装@vue/cli

npm install -g @vue/cli

第二步:在cmd中创建vue实例

(1)cd 到创建的目录文件夹
(2)Vue create 执行创建Vue命令
(3)cd 到创建的vue目录文件夹
(4)npm run serve 编译

3、脚手架结构

src/assets:放静态资源

components:放所有组件

/* 
	该文件是整个项目的入口文件
*/
//引入Vue
import Vue from 'vue'
//引入App组件,它是所有组件的父组件
import App from './App.vue'
//关闭vue的生产提示
Vue.config.productionTip = false

/* 
	关于不同版本的Vue:
		1.vue.js与vue.runtime.xxx.js的区别:
				(1).vue.js是完整版的Vue,包含:核心功能+模板解析器。
				(2).vue.runtime.xxx.js是运行版的Vue,只包含:核心功能;没有模板解析器。

		2.因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用
			render函数接收到的createElement函数去指定具体内容。
*/

//创建Vue实例对象---vm
new Vue({
	el:'#app',
	//render函数完成了这个功能:将App组件放入容器中
  render: h => h(App),
	// render:q=> q('h1','你好啊')

	// template:`<h1>你好啊</h1>`,
	// components:{App},
})

4、render函数

render是vue调用的函数,是让引入残缺版的vue也可以正确解析vue

vue组成:核心+模板解析器(1/3体积),残缺版vue省去了模板解析器,更精简

5、关于不同版本的Vue
(1)vue.js与vue.runtime.xxx.js的区别:

  • vue.js是完整版的Vue,包含:核心功能+模板解析器。
  • vue.runtime.xxx.js是运行版的Vue,只包含:核心功能;没有模板解析器。

(2)因为vue.runtime.xxx.js没有模板解析器,所以不能使用template配置项,需要使用render函数接收到的createElement函数去指定具体内容。

六、ref属性 

1、为什么要ref?

vue中最好不要直接操作原生DOM,ref可以替代id,用this.$refs.值获取

2、ref属性

(1)被用来给元素或子组件注册引用信息(id的替代者)

(2)应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(vc)

(3)使用方式

  • 打标识:<h1 ref="xxx">...</h1>或<School ref="xxx">...</School>
  • 获取:this.$refs.xxx

七、props配置

1、为什么有props

data数据相同属性的值可能不同,为了复用data中的属性

需要在组件中定义props,让组件接收外部传过来的数据

父传递数据给子

<Demo name="xxx"/>

2、简单声明接收(只接收)

组件中接收

props:['name','age','sex'] 

3、接收的同时对数据进行类型限制(限制类型)

props:{
    name:String,
    age:Number,
    sex:String
} 

4、接收的同时对数据:进行类型限制+默认值的指定+必要性的限制

props:{
			name:{
				type:String, //name的类型是字符串
				required:true, //name是必要的
			},
			age:{
				type:Number,
				default:99 //默认值
			},
			sex:{
				type:String,
				required:true
			}
		}

备注:props是只读的,Vue检测到你对props进行修改会发出警告。如果业务需求需要修改props,则需复制内容到data,让Myxxx=this.xxx,然后修改Myxxx。

 八、mixin混入

1、为什么有mixin?

为了实现两个组件共享一个配置,如methods方法一样,可复用

2、语法

(1)局部混合

main.js暴露 export const hunhe

组件中引入 import {hunhe from ... 

组件配置项mixin:[hunhe,...]

(2)全局混合

在main.js中

import {hunhe,hunhe2} from './mixin'
Vue.mixin(hunhe)
Vue.mixin(hunhe2)

3、插件

(1)作用:用于增强Vue

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

(3)定义插件

plugins.js 暴露 export default

main.js 引入 import plugins from './plugins'

对象.install = function (Vue, options) {
    // 1. 添加全局过滤器
    Vue.filter(....)

    // 2. 添加全局指令
    Vue.directive(....)

    // 3. 配置全局混入(合)
    Vue.mixin(....)

    // 4. 添加实例方法
    Vue.prototype.$myMethod = function () {...}
    Vue.prototype.$myProperty = xxxx
}

或
export default{
    install(Vue){


    }
}

(4)使用插件

main.js 用vue使用 Vue.use(plugins)

Vue.use()

4、scoped样式

各个组件都有style,会被合在一起,加上scoped让样式局部化,防止style被同名覆盖。

5、lang属性

lang全称language,可以用less语言写css。但是脚手架不能写less,需要安装less-loader(注意版本)

//用less语言
<style lang="less"></style>

//用css语言(不写lang默认用css)
<style lang="css"></style>

 九、组件化编码流程(通用)

1、实现静态组件

组件:按功能划分,尽量语义化

为html的静态页面进行组件化编程,实现组件管理

2、展示动态数据

(1)怎么展示

数据类型、名称是什么

数据保存在哪个组件

(2)补充:nanoid库 可以绑定唯一id

步骤1:下载 npm i nanoid

步骤2:引用 import {nanoid} from './nanoid'

步骤3:使用 nanoid()

(3)兄弟之间传信息——初级不太好办到

初级能用propos进行父子传递信息

父传子:父在子标签进行:属性,子定义propos

子传父:父在子标签传一个带参函数,子定义propos

3、交互——从绑定事件监听开始

十、 组件自定义事件

1、是什么?

组件间通信方式,适用于子组件→父组件。除了click、keyup等,用户可自定义事件

2、应用:子传父

//方法1
<!-- 通过父组件给子组件传递函数类型的props实现:子给父传递数据 -->
        <School :getSchoolName="getSchoolName"/>
//父给子传一个回调函数,子在自己的methods的函数调用这个函数传参

//方法2
<!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第一种写法,使用@或v-on) -->
        <!-- <Student @atguigu="getStudentName" @demo="m1"/> -->
父给子绑定事件,父有带有参数的函数,子通过method函数+绑定事件触发this.$emit传参

//方法3
<!-- 通过父组件给子组件绑定一个自定义事件实现:子给父传递数据(第二种写法,使用ref,更灵活) -->
        <Student ref="student" @click.native="show"/>

3、解绑事件

配置项:unbind{ this.$off([1,2..]) }

4、特别注意

通过this.$refs.xxx.$on('atguigu',回调)绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题!

 十一、全局事件总线

1、是什么

任意组件间通信

2、安装全局事件

在main.js中

new Vue({
    ...
	beforeCreate() {
		Vue.prototype.$bus = this //安装全局事件总线,$bus就是当前应用的vm
	},
    ......
}) 

3、使用事件总线

(1)接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身。 

methods(){
  demo(data){......}
}
......
mounted() {
  this.$bus.$on('xxxx',this.demo)
}

(2)提供数据:this.$bus.$emit('xxxx',数据)

4、最好在beforeDestroy钩子中,用$off去解绑<当前组件所用到的事件。

十二、消息订阅与发布

 1、是什么

任意组件通信

2、原理

订阅消息:消息名,发布消息:消息内容

3、借助第三方库 pubsub-js

(1)安装pubsub:npm i pubsub-js

(2)引入: import pubsub from 'pubsub-js'

(3)接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身。

methods(){
  demo(data){......}
}
......
mounted() {
  this.pid = pubsub.subscribe('xxx',this.demo) //订阅消息
}

(4)提供数据:pubsub.publish('xxx',数据)

(5)最好在beforeDestroy钩子中,用PubSub.unsubscribe(pid)去取消订阅。

 十二、$nextTick()

  1. 作用:在下一次 DOM 更新结束后执行其指定的回调。

  2. 语法:this.$nextTick(回调函数)

  3. 什么时候用:当改变数据后,要基于更新后的新DOM进行某些操作时,要在nextTick所指定的回调函数中执行。(应用:todolist案例中,文字变input获取焦点)

十三、配置代理

1、是什么

配置代理服务器, 解决(用户端和服务器之间)跨域问题

2、方法一

在vue.config.js中添加如下配置:

devServer:{
  proxy:"http://localhost:5000"
}

说明:

(1)优点:配置简单,请求资源时直接发给前端(8080)即可。

(2)缺点:不能配置多个代理,不能灵活的控制请求是否走代理。

(3)工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器 (优先匹配前端资源)

3、方法二

编写vue.config.js配置具体代理规则:

module.exports = {
	devServer: {
      proxy: {
      '/api1': {// 匹配所有以 '/api1'开头的请求路径
        target: 'http://localhost:5000',// 代理目标的基础路径
        changeOrigin: true,
        pathRewrite: {'^/api1': ''}
      },
      '/api2': {// 匹配所有以 '/api2'开头的请求路径
        target: 'http://localhost:5001',// 代理目标的基础路径
        changeOrigin: true,
        pathRewrite: {'^/api2': ''}
      }
    }
  }
}
/*
   changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
   changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080
   changeOrigin默认值为true
*/

说明:

(1)优点:可以配置多个代理,且可以灵活的控制请求是否走代理。

(2)缺点:配置略微繁琐,请求资源时必须加前缀。

 十四、vue-resource

1、服务器通信方法

(1)xhr;(2)jQuery;(3)axios;(4)fetch;(5)vue-resource

2、axios=this.$http

十五、插槽

 1、是什么

一种组件间通信的方式:让父组件可以向子组件指定位置插入html结构

2、分类

默认插槽、具名插槽、作用域插槽

3、默认插槽

父组件中:
        <Category>
           <div>html结构1</div>
        </Category>
子组件中:
        <template>
            <div>
               <!-- 定义插槽 -->
               <slot>插槽默认内容...</slot>
            </div>
        </template>

4、具名插槽

父组件中:
        <Category>
            <template slot="center">
              <div>html结构1</div>
            </template>

            <template v-slot:footer>
               <div>html结构2</div>
            </template>
        </Category>
子组件中:
        <template>
            <div>
               <!-- 定义插槽 -->
               <slot name="center">插槽默认内容...</slot>
               <slot name="footer">插槽默认内容...</slot>
            </div>
        </template>

5、作用域插槽

理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。(games数据在Category组件中,但使用数据所遍历出来的结构由App组件决定)

父组件中:
		<Category>
			<template scope="scopeData">
				<!-- 生成的是ul列表 -->
				<ul>
					<li v-for="g in scopeData.games" :key="g">{{g}}</li>
				</ul>
			</template>
		</Category>

		<Category>
			<template slot-scope="scopeData">
				<!-- 生成的是h4标题 -->
				<h4 v-for="g in scopeData.games" :key="g">{{g}}</h4>
			</template>
		</Category>
子组件中:
        <template>
            <div>
                <slot :games="games"></slot>
            </div>
        </template>
		
        <script>
            export default {
                name:'Category',
                props:['title'],
                //数据在子组件自身
                data() {
                    return {
                        games:['红色警戒','穿越火线','劲舞团','超级玛丽']
                    }
                },
            }
        </script>

 十六、vuex

1、概念

集中式管理数据的vue插件

2、搭建vuex环境

(1)创建文件: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
})

(2)在main.js中创建vm时传入store配置项

......
//引入store
import store from './store'
......

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

3、基本使用

(1)初始化数据、配置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,
})

(2)组件中读取vuex中的数据:$store.state.sum

(3)组件中修改vuex中的数据:$store.dispatch('action中的方法名',数据)$store.commit('mutations中的方法名',数据)

备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch,直接编写commit

4、getters的使用

(1)概念:当state中的数据需要经过加工后再使用时,可以使用getters加工。

(2)在store.js中追加getters配置

......

const getters = {
	bigSum(state){
		return state.sum * 10
	}
}

//创建并暴露store
export default new Vuex.Store({
	......
	getters
})

(3)组件中读取数据:$store.getters.bigSum

5、四个map方法的使用

(1)mapState方法:用于帮助我们映射state中的数据为计算属性

computed: {
    //借助mapState生成计算属性:sum、school、subject(对象写法)
     ...mapState({sum:'sum',school:'school',subject:'subject'}),
         
    //借助mapState生成计算属性:sum、school、subject(数组写法)
    ...mapState(['sum','school','subject']),
},

(2)mapGetters方法:用于帮助我们映射getters中的数据为计算属性

computed: {
    //借助mapGetters生成计算属性:bigSum(对象写法)
    ...mapGetters({bigSum:'bigSum'}),

    //借助mapGetters生成计算属性:bigSum(数组写法)
    ...mapGetters(['bigSum'])
},

(3)mapActions方法:用于帮助我们生成与actions对话的方法,即:包含$store.dispatch(xxx)的函数

methods:{
    //靠mapActions生成:incrementOdd、incrementWait(对象形式)
    ...mapActions({incrementOdd:'jiaOdd',incrementWait:'jiaWait'})

    //靠mapActions生成:incrementOdd、incrementWait(数组形式)
    ...mapActions(['jiaOdd','jiaWait'])
}

(4)mapMutations方法:用于帮助我们生成与mutations对话的方法,即:包含$store.commit(xxx)的函数

methods:{
    //靠mapActions生成:increment、decrement(对象形式)
    ...mapMutations({increment:'JIA',decrement:'JIAN'}),
    
    //靠mapMutations生成:JIA、JIAN(对象形式)
    ...mapMutations(['JIA','JIAN']),
}

备注:mapActions与mapMutations使用时,若需要传递参数需要:在模板中绑定事件时传递好参数,否则参数是事件对象。

6、模块化+命名空间

(1)目的:让代码更好维护,让多种数据分类更加明确。

(2)修改store.js

const countAbout = {
  namespaced:true,//开启命名空间
  state:{x:1},
  mutations: { ... },
  actions: { ... },
  getters: {
    bigSum(state){
       return state.sum * 10
    }
  }
}

const personAbout = {
  namespaced:true,//开启命名空间
  state:{ ... },
  mutations: { ... },
  actions: { ... }
}

const store = new Vuex.Store({
  modules: {
    countAbout,
    personAbout
  }
})

(3)开启命名空间后,组件中读取state数据:

//方式一:自己直接读取
this.$store.state.personAbout.list
//方式二:借助mapState读取:
...mapState('countAbout',['sum','school','subject']),

(4)开启命名空间后,组件中读取getters数据:

//方式一:自己直接读取
this.$store.getters['personAbout/firstPersonName']
//方式二:借助mapGetters读取:
...mapGetters('countAbout',['bigSum'])

(5)开启命名空间后,组件中调用dispatch

//方式一:自己直接dispatch
this.$store.dispatch('personAbout/addPersonWang',person)
//方式二:借助mapActions:
...mapActions('countAbout',{incrementOdd:'jiaOdd',incrementWait:'jiaWait'})

(6)开启命名空间后,组件中调用commit

//方式一:自己直接commit
this.$store.commit('personAbout/ADD_PERSON',person)
//方式二:借助mapMutations:
...mapMutations('countAbout',{increment:'JIA',decrement:'JIAN'}),

十七、路由

1、概念

一个路由(route)就是一组映射关系(key - value),多个路由需要路由器(router)进行管理。前端路由:key是路径,value是组件或function

2、特点

路由分类

  • 后端路由-工作过程:服务器收到一个请求,根据请求路径找到匹配函数处理请求,返回响应数据。
  • 前端路由-工作过程:浏览器路径改变,对应的组件显示。    

3、基本使用

(1)安装vue-router,命令:npm i vue-router

(2)应用插件:Vue.use(VueRouter)

(3)编写router配置项:

//引入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

(4)实现切换(active-class可配置高亮样式)

<router-link active-class="active" to="/about">About</router-link>

(5)指定展示位置

<router-view></router-view>

4、嵌套路由(多级路由)  

(1)是什么:可以实现多个路由嵌套

(2)方法

在路由配置项中使用children配置项

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>

5、路由传参(query):作用是一级路由传参到二级路由并传参 

(1)传递参数:query传参的两种写法

在组件中传递参数

<!-- 跳转并携带query参数,to的字符串写法 -->
<router-link :to="/home/message/detail?id=666&title=你好">跳转</router-link>
				
<!-- 跳转并携带query参数,to的对象写法 -->
<router-link 
	:to="{
		path:'/home/message/detail',
		query:{
		   id:666,
            title:'你好'
		}
	}"
>跳转</router-link>

(2)接收参数

$route.query.id
$route.query.title

6、路由命名

在路由的配置项中添加name,简化路由的跳转

(1)命名路由

{
	path:'/demo',
	component:Demo,
	children:[
		{
			path:'test',
			component:Test,
			children:[
				{
                      name:'hello' //给路由命名
					path:'welcome',
					component:Hello,
				}
			]
		}
	]
}

(2)简化跳转

<!--简化前,需要写完整的路径 -->
<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>

7、路由传参(params)

(1)配置路由,声明接收params参数

{
	path:'/home',
	component:Home,
	children:[
		{
			path:'news',
			component:News
		},
		{
			component:Message,
			children:[
				{
					name:'xiangqing',
					path:'detail/:id/:title', //使用占位符声明接收params参数
					component:Detail
				}
			]
		}
	]
}

(2)传递参数:两种写法

<!-- 跳转并携带params参数,to的字符串写法 -->
<router-link :to="/home/message/detail/666/你好">跳转</router-link>
				
<!-- 跳转并携带params参数,to的对象写法 -->
<router-link 
	:to="{
		name:'xiangqing',
		params:{
		   id:666,
            title:'你好'
		}
	}"
>跳转</router-link>

(3)接收参数

$route.params.id
$route.params.title

8、路由的props配置让路由组件更方便收到参数

(1)配置路由,声明接收params参数

{
	path:'/home',
	component:Home,
	children:[
		{
			path:'news',
			component:News
		},
		{
			component:Message,
			children:[
				{
					name:'xiangqing',
					path:'detail/:id/:title', //使用占位符声明接收params参数
					component:Detail
				}
			]
		}
	]
}

(2)一级路由组件中传递参数

<!-- 跳转并携带params参数,to的字符串写法 -->
<router-link :to="/home/message/detail/666/你好">跳转</router-link>
				
<!-- 跳转并携带params参数,to的对象写法 -->
<router-link 
	:to="{
		name:'xiangqing',
		params:{
		   id:666,
            title:'你好'
		}
	}"
>跳转</router-link>

(3)跳转二级路由接收参数

$route.params.id
$route.params.title

9、编程式路由导航

不借助router-link标签,实现路由跳转

//$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、缓存路由组件

作用:让不展示的路由组件保持挂载,不被销毁。

<keep-alive include="News"> 
    <router-view></router-view>
</keep-alive>

11、两个新的生命周期钩子

(1)作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。

(2)具体名字:

  • activated路由组件被激活时触发。
  • deactivated路由组件失活时触发。

12、路由守卫

(1)作用:对路由进行权限控制,保护路由的安全

(2)分类:全局守卫、独享守卫、组件内守卫

(3)全局路由守卫:前置守卫、后置首位

//全局前置守卫:初始化时执行、每次路由切换前执行
router.beforeEach((to,from,next)=>{
	console.log('beforeEach',to,from)
	if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制
		if(localStorage.getItem('school') === 'atguigu'){ //权限控制的具体规则
			next() //放行
		}else{
			alert('暂无权限查看')
			// next({name:'guanyu'})
		}
	}else{
		next() //放行
	}
})

//全局后置守卫:初始化时执行、每次路由切换后执行
router.afterEach((to,from)=>{
	console.log('afterEach',to,from)
	if(to.meta.title){ 
		document.title = to.meta.title //修改网页的title
	}else{
		document.title = 'vue_test'
	}
})

(4)独享路由守卫:某个路由独享,只有前置路由守卫

beforeEnter(to,from,next){
	console.log('beforeEnter',to,from)
	if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制
		if(localStorage.getItem('school') === 'atguigu'){
			next()
		}else{
			alert('暂无权限查看')
			// next({name:'guanyu'})
		}
	}else{
		next()
	}
}

(5)组件内路由守卫:不在路由配置中设置,在组件中设置

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

十八、路由器的两种工作模式

1、history模式和hash模式

2、对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值。

3、hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器。

  • hash模式:
    • (1)地址中永远带着#号,不美观 。
    • (2)若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
    • (3)兼容性较好。
  • history模式:
  • (1)地址干净,美观 。
  • (2)兼容性和hash模式相比略差。
  • (3)应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。

十九、UI组件库

移动端常用 UI 组件

1. Vant https://youzan.github.io/vant

2. Cube UI https://didi.github.io/cube-ui

3. Mint UI http://mint-ui.github.io

PC 端常用 UI 组件

1. Element UI https://element.eleme.cn

2. IView UI https://www.iviewui.co

 二十、按需引入Element UI

1、安装babel-plugin-component库

2、修改babel.config.js

3、按需引入componet

4、脚手架更新但是Element UI可能未更新会报错,需要自行解决

  • 9
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值