Vue入门

Vue入门

    • 组件化编程
    • Vue CLI脚手架
    • 脚手架结构说明
    • ref属性(id选中器)
    • props配置项(组件的数据传递)
    • mixin混入(多个组件使用共有的方法,数据,配置……)
    • plugin插件(自定插件,及插件使用)
    • scoped样式(多组件防止,样式名重复,样式冲突)
    • 浏览器的本地存储
    • 自定义事件(组件的数组传递)
    • 自定义事件的销毁
    • 自定义组件绑定原生事件
    • 全局事件总线(组件的数据传递)
    • 消息的发布与订阅(组件的数据传递)
    • $nextTick(回调函数)
    • Axios异步通信(接口调用)
    • Axios请求跨域
    • 插槽(自定义组件中编写html)
    • Vuex(多组件操作同一数据)
    • Vuex的基本使用
    • 使用mapState,mapGetters, mapActions,mapMutations简化调用方式
    • Vuex多组件数据共享
    • Vuex模块化,对共享数据进行分类(推荐使用)
    • Vue Router路由管理器(单页面应用)
    • 路由嵌套(一个组件中跳转另一个子组件)
    • 路由跳转传递参数
    • 命名路由(简化跳转路径)
    • 控制路由跳转时操作浏览器的后退前进记录
    • 编程式路由导航(定时跳转,自动跳转)
    • 缓存路由组件(通过路由跳转到其他页面后,保存原页面数据)
    • 路由守卫(路由跳转时,进行过滤)
    • 路由器的两种工作模式
    • Vue UI组件库
    • ElementUI全局引入
    • ElementUI按需引入

参考博客

组件化编程

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

  • 非单文件组件
    1.编写组件
	//第一步:创建student组件
		const student = Vue.extend({
			template:`
				
//此处的div必须存在,需要放置一个根节点

学生姓名:{{studentName}}

学生年龄:{{age}}

`
, data(){ return { studentName:'JOJO', age:20 } } })

2.局部注册组件

//创建vm
		new Vue({
			el:'#root',
			data:{
				msg:'你好,JOJO!'
			},
			//第二步:注册组件(局部注册)
			components:{
				xuesheng:student //这里的xuesheng为组件的key,及第三步使用的标签名称,student为第一步中创建的组件名称,也可以按照如下方式简写
				//student      直接写组件名称,那么,标签也将会是这个
				
			}
		})

全局注册

//全局注册组件,第一个参数为组件标签名,即组件key,第二个参数为创建的组件实例
	Vue.component("student",student)

3.使用组件

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>基本使用</title>
		<script type="text/javascript" src="../js/vue.js"></script>
	</head>
	<body>
		<div id="root">
			<h1>{{msg}}</h1>
			<!-- 第三步:编写组件标签 -->
			<student></student>
			<!-- 此处若使用的是,xuesheng作为组件key,那么将会是如下形式 -->
			<xuesheng></xuesheng>
		</div>
	</body>
</html>

注意组件的命名规范:

关于组件名:

当组件名由一个单词组成时:
第一种写法(首字母小写):school
第二种写法(首字母大写):School

当组件名由多个单词组成时:
第一种写法(kebab-case命名):my-school
第二种写法(CamelCase命名):MySchool (这种写法需要Vue CLI 脚手架支持)
备注:
组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行
可以使用Vue.extend()中的name属性项指定组件在开发者工具中呈现的名字
关于组件标签:
第一种写法:
第二种写法:
备注: 不使用脚手架时,会导致后续组件不能渲染

  • 组件嵌套

  • 定义子组件

//定义student组件
		const student = Vue.extend({
			template:`
				

学生名称:{{name}}

学生年龄:{{age}}

`
, data(){ return { name:'JOJO', age:20 } } })
  • 定义父组件
//定义school组件
		const school = Vue.extend({
			template:`
				

学校名称:{{name}}

学校地址:{{address}}

//此处使用子组件
`
, components:{ student//将student子组件注册到自己当中 }, data(){ return { name:'尚硅谷', address:'北京' } } })
  • 注册父组件
//创建vm
		new Vue({
			el:'#root',
			components:{
				school 
			}
		})
  • 单文件组件
    单文件组件的格式:
//在template编写html代码,此处的template标签只是为了区分模块代码,并不具有实际意义,等代码编译后,该标签将不会再存在,需要注意的是,template标签下必须存在一个根节点,即div
<template> 
<div id="demo">

</div>
</template>

//在script标签中编写当前组价的js代码,即vue代码
<script>
	//此处的 export default为es6语法,作用为将当前组件抛出,便于其他组件导入
    export default {
        name:'组件名称,通常为文件名',
        data() {
            return {
                
            }
        },
        methods: {
            
        },
    }
/**
注:
此处的代码实际就是如下代码,只不过Vue.extend可以省略

 export default  Vue.extend({
			template:`
				
`, data(){ return { name:'111' } } methods: { add(){ alert(this) } }, }) **/
</script> //此处编写该组件的样式 <style> #demo{ background: orange; } </style>

1.编写子组件
School.vue:

<template>
    <div id='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: orange;
    }
</style>


2.编写全局组件管理父组件
App.vue

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

<script>
//此处的import 为es6语法,作用是将步骤1中通过 export default 抛出的组件进行导入
    import School from './School.vue'
  
//相当于App.vue是所有组件的父组件,由他来管理所有组件,程序到时候只需要引入这一个就可以了,所以他也需要抛出去,便于其他地方引入
    export default {
        name:'App',
        components:{
            School
        }
    }
</script>

3.编写js,用于引入总组件
main.js

//将管理所有组件的app组件导入
import App from './App.vue'

new Vue({
    template:``,
    el:'#root',
    components:{App}
})
4.编写html展示组件内容
index.html

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>单文件组件练习</title>
</head>
<body>
    <div id="root"></div>
    <script src="../../js/vue.js"></script>
    <script src="./main.js"></script>
</body>
</html>

执行过程:
打开index.html–>加载vue.js–>加载自己编写的main.js–>在main.js中会引入app.vue这个组件–>app.vue组件又会引入School.vue组件——>渲染数据

注:以上流程并不能实际运行,因为import 等关键字,并不能被浏览器解析,需要通过脚手架进行编译,才能被浏览器识别解析

Vue CLI脚手架

Vue 脚手架是 Vue 官方提供的标准化开发工具(开发平台)

  • 安装步骤:(前提是已经安装了node)
    1.cmd 中执行
    配置 npm 淘宝镜像,加速下载
npm config set registry http://registry.npm.taobao.org

2.全局安装@vue/cli

npm install -g @vue/cli
  • 使用步骤:
    1.在需要创建项目的目录下,进入cmd,,使用如下命令创建项目文件
vue create 项目名称

2.选择vue的使用版本,通过上下键切换,回车确定,此处使用版本2
Vue入门_第1张图片
3.在项目文件目录下(D:\IDEXiangMu\Vue\vue-for),进入cmd,执行如下命令启动项目

npm run serve

4,在cmd窗口中执行Ctrl+C暂停项目
5.编译打包,执行命令后出现的dist文件夹就是编译后的文件

npm run build

6.全局检查语法,一般不用

npm run lint

脚手架结构说明

.文件目录
├── node_modules
├── public
│ ├── favicon.ico: 页签图标
│ └── index.html: 主页面
├── src
│ ├── assets: 存放静态资源,比如图片,视频
│ │ └── logo.png
│ │── component: 存放自定义的组件
│ │ └── HelloWorld.vue
│ │── App.vue: 汇总所有组件
│ └── main.js: 整个项目的入口文件,执行启动命令后首先执行的就是该文件
├── .gitignore: git版本管制忽略的配置,及哪些文件不需要接受Git的管理,在此配置
├── babel.config.js: babel的配置文件,不需要管
├── package.json: 应用包配置文件 ,配置应用名称,版本等信息
├── README.md: 应用描述文件
├── vue.config.js: 配置脚手架的文件,对脚手架的配置,可以添加到此处
└── package-lock.json: 包版本控制文件,不需要管

文件解析

  • main.js
// main.js是整个项目文件的入口,当执行npm run serve命令后首先执行的就是改文件

//引入Vue
import Vue from 'vue'
//引入app组件,他是所有组件的父组件
import App from './App.vue'

//关闭vue的生产提示
Vue.config.productionTip = false

//创建vue实例对象,vm
new Vue({
	//将APP组件放入容器中,即注册组件
  render: h => h(App),
}).$mount('#app')

/**
 * 以上代码相当于:
 * 
 
 new Vue({
	el:'#app'
  render: h => h(App),
})


 */
  • index.html
DOCTYPE html>
<html lang="">
  <head>
    <meta charset="utf-8">
	  
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
	  
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
	 
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
	  
    <title><%= htmlWebpackPlugin.options.title %>title>
  head>
  <body>
	  
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.strong>
    noscript>
	
    <div id="app">div>
    
  body>
html>


vue.config.js
官方配置参考

const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
	//避免构建后的代码中出现未转译的第三方依赖
  transpileDependencies: true,
	//关闭语法检查
  lintOnSave:false
})

ref属性(id选中器)

被用来给元素或子组件注册引用信息(等同于id属性)
应用在html标签上获取的是真实DOM元素,应用在组件标签上获取的是组件实例对象(vc)

使用对比:

<template>
	<div id="app">
		<h1 id="title_one">{{msg}}</h1>
		<h1 ref="title">{{msg}}</h1>
		<!-- 自定义组件school -->
		<school ref="sch" />
		<button @click="show" ref="btn">点我输出ref</button>
	</div>
</template>

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

	export default {
		name: 'App',
		components: {
			school
		},
		data() {
			return {
				msg: "这是app组件"
			}
		},
		methods: {
			show() {
				console.log("ref信息--》", this.$refs.title)
				console.log("ref信息--》", this.$refs.sch)
				console.log("ref信息--》", this.$refs.btn)
				console.log("ref信息2--》", document.getElementById("title_one"))
			}
		}
	}
</script>

使用方式:

ref的使用方式:this.$refs.名称
id的使用方式:document.getElementById("名称")

注:当ref属性条件到自定义的组件时,那么获取到的将会是VueComponent对象,比如上例中的school

props配置项(组件的数据传递)

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

例:
自定义组件Student.vue

<template>
    <div>
        <h1>{{msg}}</h1>
        <h2>学生姓名:{{name}}</h2>
        <h2>学生性别:{{sex}}</h2>
        <!--此处使用本组件中变量-->
        <h2>学生年龄:{{myAge}}</h2>     
		<button @click="add" ref="btn">点我增加年龄</button>
    </div>
</template>

<script>
    export default {
        name:'Student',
        data() {
            return {
                msg:"我~~",
				myAge:this.age//vue不能对传递过来的参数直接操作,所以需要将传过来的参数age赋值到本组件当中,进行操作
            }
        },
        // 简单声明接收,不对传递过来的参数类型做限制
		// props:['name','age','sex']

        // 接收的同时对数据进行类型限制
		/* props:{
			name:String, //表示当前name参数必须是Sting类型
			age:Number, //表示当前age参数必须是Number类型
			sex:String  //表示当前sex参数必须是Sting类型
		} */

        // 接收的同时对数据进行类型限制 + 指定默认值 + 限制必要性
		props:{
			name:{
				type:String, //表示当前name参数必须为String类型,且必须传递
				required:true,
			},
			age:{
				type:Number,//表示当前age参数必须为Number类型,不是必须传递,若不传则默认值为99
				default:99
			},
			sex:{
				type:String,
				required:true
			}
		},
		methods:{
			add(){ //通过此方法,对传递过来的参数进行操作
				this.myAge++
			}
		}
    0}
</script>

使用:

<!------此处传递的参数必须用引号,默认传递的数据类型都是String,对于其他类型需要通过v-bind的形式,vue才会进行判断,例如此处的age需要的类型是Number,如果不使用v-bind那么就会认为是一个字符串,就会报错-------->
<Student  name="张三" :age="18" sex="男"/>

注:vue中,不能对通过组件传递过来的参数进行直接操作,需要通过赋值,之后在进行操作,例如上文当中的age,需要将age 赋值到myAge当中,在对myAge进行操作,否则会报错,对于非String类型的参数,在传递时应该使用v-bind的形式,例如上文中的 :age

mixin混入(多个组件使用共有的方法,数据,配置……)

可以把多个组件共用的配置提取成一个混入对象

  • 编写共有配置文件:mixin.js
export  const  add_minx = {
	// 公用数据
	data(){
		return {
			x:100,
			y:100
		}
	},
	// 公用方法
	methods:{
			  add(){
				  alert(this.name)
			  }
	},
	
}
  • 两个文件共同应用
    Student.vue
<template>
    <div>
     
        <h2>学生姓名:{{name}}</h2>
        <h2>学生性别:{{sex}}</h2>
         
		<button @click="add" ref="btn">点我</button>
    </div>
</template>

<script>
//引入自定义的mixin文件,使用该文件中的add方法
	 import {add_minx} from '../mixin.js'
	
    export default {
        name:'Student',
        data() {
            return {
                name:"我~~",
				sex:"女"
            }
        },
     mixins:[add_minx]
    }
</script>

School.vue

<template>
    <div>
       
        <h2>学校名称:{{name}}</h2>
        <h2>学校地址:{{addres}}</h2>
    		<button @click="add" ref="btn">点我</button>
    </div>
</template>

<script>
//引入自定义的mixin文件,使用该文件中的add方法
	import {add_minx} from '../mixin.js'
    export default {
        name:'School',
        data() {
            return {
                name:"我是学校",
				addres:"我是地址"
            }
        },
		mixins:[add_minx]
    }
</script>

plugin插件(自定插件,及插件使用)

新建plugin.js,在文件中自定一个插件,作用为,添加一个全局过滤器,给vm,vc添加一个方法

export default {
	install(Vue){

		//全局过滤器
		Vue.filter('mySlice',function(value){
			return value.slice(0,4)
		})



		//给Vue原型上添加一个方法(vm和vc就都能用了)
		Vue.prototype.hello = ()=>{alert('你好啊')}
	}
}

使用:
1.main.js中开启插件

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

Vue.config.productionTip = false
//使用插件
Vue.use(plugin)

new Vue({
    el:"#app",
    render: h => h(App)
})

2.在School.vue中使用插件

<template>
    <div>
    <!--使用插件中的过滤器-->
        <h2>学校姓名:{{name | mySlice}}</h2>
        <h2>学校地址:{{address}}</h2>   
    </div>
</template>

<script>
    export default {
        name:'School',
        data() {
            return {
                name:'尚硅谷atguigu',
				address:'北京'
            }
        },
        methods:{
            test() {
            //使用插件中的方法
                this.hello()
            }
        }
    }
</script>

scoped样式(多组件防止,样式名重复,样式冲突)

当多个组件同时被引入时,可能存在样式名重复,比如组件A和组件B都定义了 .demo{}名字相同的样式,scoped 就是让样式在局部生效,防止冲突

使用:

<!--表示当前样式只作用域当前组件-->
<style scoped>
	.demo{
		color: aliceblue;
	}
</style>

浏览器的本地存储

  • Window.localStorage(可以简写为localStorage)
<script>
        let person = {name:"JOJO",age:20}
        //存储数据
         localStorage.setItem('person',JSON.stringify(person))
       //等同于
        Window.localStorage.setItem('person',JSON.stringify(person))


		//读取数据	
            const person = localStorage.getItem('person')
            console.log(JSON.parse(person))
       
       //删除指定数据
            localStorage.removeItem('person')
       
        //删除全部数据
            localStorage.clear()
        
    </script>

  • Window.sessionStorage(可以简写为sessionStorage)
<script>
        let person = {name:"JOJO",age:20}

      		//存储数据
            sessionStorage.setItem('person',JSON.stringify(person))
            //等同于
            Window.sessionStorage.setItem('person',JSON.stringify(person))
        
   			//读取数据
            const person = sessionStorage.getItem('person')
            console.log(JSON.parse(person))
        
   			//删除指定数据
            sessionStorage.removeItem('person')
        
      		//删除全部数据
            sessionStorage.clear()
        
    </script>
  • Window.sessionStorage 存储的内容会随着浏览器窗口关闭而消失
  • Window.localStorage 存储的内容,需要手动清除才会消失

自定义事件(组件的数组传递)

  • 通过标签进行绑定
    App.vue
<template>
	<div id="app">
		<!--永久绑定自定义事件-->
		<!-- <Student v-on:myEvent="myFunction" />-->
		
		<!--绑定自定义事件,但只执行一次-->
		<Student v-on:myEvent.once="myFunction" />

		<!--等同于-->
		<Student @myEvent.once="myFunction" />
		
	</div>
</template>

<script>
	import Student from './components/Student.vue'
	
	export default {
		name: 'App',
		components: {
			Student
		},
		methods:{
			myFunction(name){
				console.log("自定义事件的监听方法被调用",name)
			}
		}
	}
</script>

触发事件:
Student.vue

<template>
    <div>
        <h2>学生姓名:{{name}}</h2>
        <h2>学生性别:{{sex}}</h2>
	<button @click="sendStudentName" ref="btn">点我</button>
    </div>
</template>

<script>
	
	
    export default {
        name:'Student',
        data() {
            return {
                name:"我~~",
				sex:"女"
            }
        },
		methods:{
			sendStudentName(){
				//此处触发事件,myEvent指的是时间名称类似于onClick,此处的this.name表示对于事件监听的函数传递的参数
				this.$emit("myEvent",this.name)
			}
		}
    }
</script>
  • 通过函数进行绑定
    App.vue
<template>
	<div id="app">
		<!--通过函数进行绑定-->	
		<Student ref="stu" /> 
	</div>
</template>

<script>
	import Student from './components/Student.vue'
	
	export default {
		name: 'App',
		components: {
			Student
		},
		methods:{
			myFunction(name){
				console.log("自定义事件的监听方法被调用",name)
			}
		},//添加一个钩子函数,组件挂在完毕后执行
		mounted(){
			//为ref属性名为stu的组件,绑定一个名为myEvent的事件,事件触发后执行myFunction方法
			 this.$refs.stu.$on("myEvent",this.myFunction)
			//以上这种绑定方式灵活性更高,比如,需要等待5秒后才为该组件绑定事件,或者,调用接口后再绑定事件
			
			
			//表示当前事件绑定后只能执行一次,一次过后就会失效
			this.$refs.stu.$once("myEvent",this.myFunction)
		}
	}
</script>

触发事件:(同上)

自定义事件的销毁

//销毁指定事件
this.$off('事件名称')
//销毁多个事件
this.$off(['事件名称1','事件名称2'])
//销毁全部事件
this.$off()

自定义组件绑定原生事件

<!--给自定义组件添加原生事件-->
<Student @click.native="myFunction" /> 

全局事件总线(组件的数据传递)

全局事件总线是一种可以在任意组件间通信的方式,本质上就是一个对象。

  • 安装全局事件总线

main.js

new Vue({
  render: h => h(App),
  beforeCreate(){
	  Vue.prototype.$bus=this;  //配置全局事件总线,以实现组件通信,此处的 $bus 是自定义的,
  }
}).$mount('#app')

  • 使用事件总线

1.接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身
例: Student.vue


<script>
	export default {
		name: 'Student',
		methods:{
			demo(name) {
				console.log("我是学生,我的学校名称是", name)
			}
		},
		mounted() {//组件挂载完毕后执行
				//参数1:事件名称,参数2:事件被触发后的回调方法
				this.$bus.$on("sendSchoolName", this.demo)
		},
		beforeDestroy() { //组件被销毁的时候执行
		
		//组件销毁的时候,将当前组件绑定的事件进行销毁
		
			this.$bus.$off("sendSchoolName")
		}
	}
</script>

2.提供数据:B组件给A组件提供数组,触犯A中定义的事件
例:School.vue

<script>
	export default {
		name: 'School',
		methods:{
			sendSchooleName(){
				//将学校名称传递给sendSchoolName事件
				this.$bus.$emit("sendSchoolName",this.name);
			}
		}
	}
</script>

注:应当在beforeDestroy钩子中,用$off去解绑当前组件所用到的事件

消息的发布与订阅(组件的数据传递)

  • 安装pubsub(在项目路径下的cmd中执行如下命令)
npm i pubsub-js
  • 引入pubsub
import pubsub from 'pubsub-js'
  • 接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身
    例:Student.vue

<script>
	//引入pubsub
	import pubsub from 'pubsub-js'

	export default {
		name: 'Student',
		methods: {
			demo(msgName, data) {
				console.log("我是学生,我的学校名称是", data)
			}
		},
		mounted() { //组件挂载完毕后执行
			this.pubId = pubsub.subscribe('demo', this.demo) //订阅消息
		},
		beforeDestroy() { //组件被销毁的时候执行

			//组件销毁的时候,将当前组件绑定的事件进行销毁

			pubsub.unsubscribe(this.pubId) //取消订阅
		}
	}
</script>
  • 提供数据
    例:School.vue
<script>
	//引入pubsub
	import pubsub from 'pubsub-js'
	
	export default {
		name: 'School',
		methods:{
			sendSchooleName(){
				//将学校名称传递给schoolName事件
				pubsub.publish('demo',this.name) //发布消息
			}
		}
	}
</script>

$nextTick(回调函数)

$nextTick(回调函数)可以将回调延迟到下次 DOM 更新循环之后执行,比如对一个元素进行操作,当代码执行到此处,元素还没有被渲染,那么可以使用该函数,进行回调操作

	//等模板解析完成之后再执行
				this.$nextTick(function(){
				//编写逻辑
				//此处是,将ref为inputEdit的input元素让其获取焦点
					this.$refs.inputEdit.focus()
				})

Axios异步通信(接口调用)

  • 安装依赖库(在项目文件夹下的cmd窗口执行)
npm install axios
  • 发起请求
 //发起请求
                axios(
                    {
                        method: 'post', //请求方式,默认get
                        url: '/data.json', //请求地址
                        // 如果url不是绝对路径,那么会将baseURL和url拼接作为请求的接口地址
                        // 用来区分不同环境,建议使用
                        baseURL: 'http://localhost:63342/vue-first/demo',
                        //请求参数只有当请求方法为'PUT', 'POST',和'PATCH'时可用
                        data: {
                            firstName: 'Fred',
                            lastName: 'Flintstone'
                        },
                        // 用于请求之前对请求数据进行操作
                        // 只用当请求方法为‘PUT’,‘POST’和‘PATCH’时可用
                        // 最后一个函数需return出相应数据
                        // 可以修改headers
                        transformRequest: [function (data, headers) {
                            // 可以对data做任何操作

                            return data;
                        }],

                        // 用于对相应数据进行处理
                        // 它会通过then或者catch
                        transformResponse: [function (data) {
                            // 可以对data做任何操作

                            return data;
                        }],
                        // 必须是一个纯对象或者 URL参数对象
                        params: {
                            ID: 12345
                        },
                        // 请求超时时间(毫秒)
                        timeout: 1000,

                        // 是否携带cookie信息
                        withCredentials: false, // default
                        // 响应格式
                        // 可选项 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
                        responseType: 'json', // 默认值是json
                        // 设置http响应内容的最大长度
                        maxContentLength: 2000,
                    }
                    //将请求回来的数据绑定给info
                ).then(
				response => { //此处接收响应回来的数据
					console.log("数据结果", response.data)
				},
				error => {
					console.log("请求失败了,失败信息", error)
				}
			);

Axios请求跨域

  • 解决方案
    1.后端接口添加注解
@CrossOrigin(origins = "*")

例:


    @GetMapping(value = "/getData")
    //解决接口调用跨域
    @CrossOrigin(origins = "*")
    public String getData()
    { 
    return null;
    }

2.vue CLI 配置代理

  • 服务器单击版
    在vue.config.js中添加如下配置:
const {
	defineConfig
} = require('@vue/cli-service')
module.exports = defineConfig({
	transpileDependencies: true,
	//关闭语法检查
	lintOnSave: false,
	// 开启代理服务器(方式一)
	devServer: {
	    proxy:'http://localhost:8002'
	}
})



使用方式:

 import axios from 'axios'
export default {
		name: 'App',
		methods: {
			getMsg() {//此处使用vue cli 代理,所以直接写localhost:8080
				axios.get("http://localhost:8080/getData").then(
					response => { //此处接收响应回来的数据
						console.log("数据", response.data)
					},
					error => {
						console.log("请求失败了", error)
					}
				)
			}
		}
	}
  • 微服务版
    在vue.config.js中添加如下配置:
const {
	defineConfig
} = require('@vue/cli-service')
module.exports = defineConfig({
	transpileDependencies: true,
	//关闭语法检查
	lintOnSave: false,
	//开启代理服务器(方式二)
	devServer: {
		proxy: {
			'/stuApi': { //自定义一个前缀,只要使用stuApi这个前缀,那么,都会代理到target中配置的服务器上
				target: 'http://localhost:8002',
				//因为添加了前缀,所以访问路径会从http://localhost:8001/data变成http://localhost:8001/stuApi/data
				//但是服务器并不存在/stuApi/data的资源,所以通过pathRewrite配置正则表达式,将/stuApi这个前缀去掉
				pathRewrite: {
					'^/stuApi': '' //将/stuApi的前缀替换为空字符串
				},
				ws: true, //用于支持websocket,默认值为true
				changeOrigin: true //用于控制请求头中的host值,默认值为true
			},
			//配置第二个服务器
			'/carApi': { 
				target: 'http://localhost:8001',
				pathRewrite: {
					'^/carApi': '' 
				},
				ws: true, 
				changeOrigin: true 
			}
		 }
		
	}

})

使用方式:

 import axios from 'axios'
export default {
		name: 'App',
		methods: {
			getSchoolMsg() {
				//发起请求
				axios({
						method: 'get', //此处使用Vue cli代理,所以直接使用localhost:8080
						url: 'http://localhost:8080/stuApi/getData', 
						responseType: 'json', // 默认值是json
					}
				).then(
					response => { //此处接收响应回来的数据
						console.log("数据2222", response.data)
					},
					error => {
						console.log("请求失败了222", error)
					}
				);

			},
			getMsg() {//此处使用Vue cli代理,所以直接使用localhost:8080
				axios.get("http://localhost:8080/carApi/getData").then(
					response => { //此处接收响应回来的数据
						console.log("数据", response.data)
					},
					error => {
						console.log("请求失败了", error)
					}
				)
			}
		}
	}

插槽(自定义组件中编写html)

总结:

  • 默认插槽:适用于只需要使用一个插槽的情况(不太推荐)
  • 具名插槽:适用于需要使用多个插槽的情况
  • 作用域插槽:适用于数据在组件本身,外部应用需要使用组件自己的数据,但是渲染数据的结构不同时使用

1.默认插槽

  • 自定义一个组件
    Category.vue
<template>
	<div class="category">
		<!-- 此处的 slot 就是定义了一个插槽,当其他组件使用本组件时,就可以在 slot 的位置添加html代码-->
		<slot>此处是默认值,当使用者没有传递具体结构时,出现</slot>
	</div>
</template>

  • 引用该组件
<template>
	<div class="container">
	<!--Category 为自定义的组件,当前组件内编写的html代码就会展示到 Category 组件中标注slot插槽的位置-->
		<Category >
			<img src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="">
		</Category>

		<Category  >
			<ul>
				<li v-for="(g,index) in games" :key="index">{{g}}</li>
			</ul>
		</Category>

		<Category >
			<video controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
		</Category>
	</div>
</template>
<script>
	import Category from './components/Category'
	export default {
		name:'App',
		components:{Category},
		data() {
			return {
				games:['植物大战僵尸','红色警戒','空洞骑士','王国']
			}
		},
	}
</script>

注:当使用自定义组件时,如果不对组件中的插槽值进行填充,那么组件就会展示slot标签中的内容
2.具名插槽

  • 自定义一个组件
    Category.vue
<template>
	<div class="category">
		<!--此处定义了一个名为 center 的插槽-->
		<slot  name="center">此处是默认值,当使用者没有传递具体结构时,出现</slot>
		<slot  name="footer">此处是默认值,当使用者没有传递具体结构时,出现</slot>
	</div>
</template>

  • 引用该组件
<template>
	<div class="container">
		<Category  >
		<!--指定使用名为center的插槽-->
			<img slot="center" src="https://s3.ax1x.com/2021/01/16/srJlq0.jpg" alt="">
			<a slot="footer" href="http://www.atguigu.com">更多美食</a>
		</Category>

		<Category  >
			<ul slot="center">
				<li v-for="(g,index) in games" :key="index">{{g}}</li>
			</ul>
			<!--当前这个div下的html代码都会使用名为footer的这个插槽,但是会额外增加一个div的结构-->
			<div class="foot" slot="footer">
				<a href="http://www.atguigu.com">单机游戏</a>
				<a href="http://www.atguigu.com">网络游戏</a>
			</div>
		</Category>

		<Category >
			<video slot="center" controls src="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"></video>
			<!--当前这个template 下的html代码都会使用名为footer的这个插槽,且不会增减额外结构-->
			<template v-slot:footer>
				<div class="foot">
					<a href="http://www.atguigu.com">经典</a>
					<a href="http://www.atguigu.com">热门</a>
					<a href="http://www.atguigu.com">推荐</a>
				</div>
				<h4>欢迎前来观影</h4>
			</template>
		</Category>
	</div>
</template>
<script>
	import Category from './components/Category'
	export default {
		name:'App',
		components:{Category},
		data() {
			return {
				games:['植物大战僵尸','红色警戒','空洞骑士','王国']
			}
		},
	}
</script>

3.作用域插槽 (数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定)

  • 自定义组件
    Category.vue
<template>
	<div class="category">
		<h3>{{title}}分类</h3>
		<!-- 定义一个插槽 ,当谁使用这个插槽时,就给他传一个数据 games-->
		<slot :games="games">我是一些默认值,当使用者没有传递具体结构时,我会出现1</slot>
	</div>
</template>

<script>
	export default {
		name:'Category',
		props:['title'],
        data() {
			return {
				games:['植物大战僵尸','红色警戒','空洞骑士','王国']
			}
		},
	}
</script>
  • 应用该组件
<template>
	<div class="container">
		<Category title="游戏" >
			
			<!--此处使用scope定义一个data,用于接收插槽传过来的数据,-->
			<template scope="data">
				<ul>
					<!-- 此处的 data.games 就是插槽当中的传递过来的数据,这个 games 是插槽当中定义的,插槽当中写的是什么那就是什么 -->
					<li v-for="(g,index) in data.games" :key="index">{{g}}</li>
				</ul>
			</template>
		</Category>

		<Category title="游戏" >
			<!-- 也可以使用{games}这样的语法,等同于data.games -->
			<template scope="{games}">
				<ol>
					<li v-for="(g,index) in games" :key="index">{{g}}</li>
				</ol>
			</template>
		</Category>

		<Category title="游戏" >
			<!-- 也可以使用solt-scope= "{games}"这样的语法,等同于scope="{games}" -->
			<template solt-scope= "{games}">
				<h4 v-for="(g,index) in games" :key="index">{{g}}</h4>
			</template>
		</Category>
	</div>
</template>

<script>
	import Category from './components/Category'
	export default {
		name:'App',
		components:{Category}
	}
</script>

Vuex(多组件操作同一数据)

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

组件中读取vuex中的数据$store.state.自定义的key
组件中读取vuex中getters的数据$store.getters.自定义的key
(当state中的数据需要经过加工后再使用时,可以使用getters加工)

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

注:若调用过程的业务逻辑简单,比如下文使用案例中数据求和的add(),那么就可以越过actions,即不写dispatch,直接编写commit,但是像案例中的addOdd(),因为逻辑较为复杂,比如真是的业务场景可能会请求接口等操作,那么就应该使用dispatch,在actions中编写业务逻辑,或请求接口等操作

Vuex的基本使用

  • 安装Vuex
//安装最新的vuex
npm i vuex
//安装指定版本
npm i vuex@3
  • 搭建环境
    1.新建src/vuex/store.js
//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)
   
//准备actions对象——响应组件中用户的动作、处理业务逻辑
const actions = { //此处编写需要对数据处理的逻辑,比如调用接口,或者逻辑判断
	//此处编写使用 this.$store.dispatch()方法时的配置
}
//准备mutations对象——修改state中的数据
const mutations = {//当state中的数据需要经过加工后再使用时,可以使用getters加工
	
}
//准备getters对象——用于将state中的数据进行加工
const getters = {
 
}
//准备state对象——保存具体的数据
const state = {}
   
//创建并暴露store
export default new Vuex.Store({
   	actions,
   	mutations,
   	state,
   	getters 
})

2.在main.js中导入store.js

import Vue from 'vue'
import App from './App.vue'
//引入store文件
import store from "./vuex/store.js"

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
  store , //应用store 
}).$mount('#app')

  1. 使用案例
    store.js
//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//应用Vuex插件
Vue.use(Vuex)
   
//准备actions对象——响应组件中用户的动作、处理业务逻辑
const actions = {//此处编写需要对数据处理的逻辑,比如调用接口,或者逻辑判断
	//此处编写使用 this.$store.dispatch()方法时的配置
	oddJIa(context,value){
		//判断当前的和,是否为奇数
		if(context.state.sum % 2){
			//调用下方mutations中的JIA方法
		 context.commit('JIA',value)
		}
	}
	
}
//准备mutations对象——修改state中的数据
const mutations = {//此处编写对数据的直接操作
	//自己定义一个加法,此处的方法名尽量大写,便于与actions中的方法名进行区分
	JIA(state,value){
		console.log(state,value);
		state.sum+=value;
	}

}
//准备getters对象——用于将state中的数据进行加工
const getters = {
    bigSum(){
        return state.sum * 10
    }
}


//准备state对象——保存具体的数据
const state = {
	//初始化数据
	sum:0
}
   
//创建并暴露store
export default new Vuex.Store({
   	actions,
   	mutations,
   	state,
   	getters 
})

自定义组件中调用:

<template>
	<div class="category">
	<!--读取数据-->
		当前求和:{{$store.state.sum}}
		<h3>当前求和的10倍为:{{$store.getters.bigSum}}</h3>
		<select v-model="n">
			<option :value="1">1</option>
			<option :value="2">2</option>
			<option :value="3">3</option>
		</select>
		<button @click="add">+</button>
		<button @click="addOdd">奇数再加</button>
	</div>
</template>

<script>
	export default {
		name:'Count',
		data(){
			return {
				n:1,			
				sum:0
			}
		},
		methods:{
			add(){
				//调用store.js中的mutations下的JIA方法
				this.$store.commit("JIA",this.n);
	
			},
			
			addOdd(){
				//调用store.js中的actions下的oddJIa方法
				this.$store.dispatch("oddJIa",this.n);
			}
		}
	}
</script>

使用mapState,mapGetters, mapActions,mapMutations简化调用方式

1.引入mapState,mapGetters

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

2.使用

<template>
	<div class="category">
	<!--读取数据-->
		当前求和:{{sum}}
		<h3>当前求和的10倍为:{{bigSum}}</h3>
		<select v-model="n">
			<option :value="1">1</option>
			<option :value="2">2</option>
			<option :value="3">3</option>
		</select>
		<button @click="add(n)">+</button>
		<button @click="addOdd(n)">奇数再加</button>
	</div>
</template>

<script>
import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'
	export default {
		name:'Count',
		data(){
			return {
				n:1
			}
		},
		methods:{
		
				/**
			 * 此处使用 mapMutations简化this.$store.commit的这个调用方式,
			 * 同理,add为本组件中定义的方法,JIA为store.js中mutations对象下定义的方法,
			 * 使用这种写法需要注意,本组件中add方法需要传递参数,否则会出现 Nan,
			 * 如果,组件中的方法名和store.js中的方法名相同,那么就可以使用数组简写的形式,如下
			 * 简写形式:
			    ...mapMutations({JIA:'JIA',JIAN:'JIAN'})
			 */
		
			 
			 ...mapMutations({add:'JIA'}),
			
			
			/**
			 * 此处使用 mapActions简化	this.$store.dispatch的这个调用方式
			 * 简写形式:
			 * ...mapActions({oddJIa:'oddJIa',oddJIa:'addWait'})
			 */
			...mapActions({addOdd:'oddJIa'})
				
			
		},
		computed:{
			/**
			 * 此处的...(三个点)表示的是将mapState返回的属性,合并到computed中去
			此处的sum为store.js中state对象下的属性,这里使用了简写的形式,所以,
			template标签中渲染数据的key必须和这里的sum保持一致,也必须和store.js中state对象下的属性sum保持一致,
			都使用相同的key
			 */
			
			...mapState(["sum"]),
			//若不一致,也可以使用这种形式,mySum为本组件中即将渲染的变量
			...mapState({mySum:'sum'}),
			
			/**
			 * mapGetters的作用等同于mapState,但他的作用是获取getters中配置的内容,
			并且key也应该和store.js中getters对象下的属性
			保持一致
			 */
			
			...mapGetters(["bigSum"])
	
		}
	}
</script>

Vuex多组件数据共享

  • 定义Student.vue读取通过Count.vue改边过的数值
<template>
	<div class="category">
		我是学生组件,我拿到了当前求和数值:{{sum}}
	</div>
</template>

<script>
	import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'
	export default {
		name:'Student',
		computed:{
			...mapState(["sum"])
		}
	}
</script>

-在App.vue中引入Student.vue

<template>
	<div class="container">
		<Count/>
		<hr>
		<Student/>
	</div>
</template>

<script>
	import Count from './components/Count'
	import Student from './components/Student'
	export default {
		name:'App',
		components:{Count,Student}
	}
</script>
  • 效果
    Vue入门_第2张图片

Vuex模块化,对共享数据进行分类(推荐使用)

  • 安装Vuex
  • 创建src/vuex/store.js
//引入Vue核心库
import Vue from 'vue'
//引入Vuex
import Vuex from 'vuex'
//引入自定义的count.js数据文件
import countOptions from './count.js'
//引入person.js数据文件
import personOptions from './person.js'
//应用Vuex插件
Vue.use(Vuex)
   
//创建并暴露store
export default new Vuex.Store({
    modules:{
        countOptions,//ziding
        personOptions
    }
})

  • 创建src/vuex/count.js
export default{
    namespaced:true,//开启命名空间
    actions:{
        addOdd(context,value){
            console.log("actions中的addOdd被调用了")
            if(context.state.sum % 2){
                context.commit('ADD',value)
            }
        },
        addWait(context,value){
            console.log("actions中的addWait被调用了")
            setTimeout(()=>{
                context.commit('ADD',value)
            },500)
        }
    },
    mutations:{
        ADD(state,value){
            state.sum += value
        },
        SUBTRACT(state,value){
            state.sum -= value
        }
    },
    state:{
        sum:0, //当前的和
        name:'111',
        school:'尚硅谷',
    },
    getters:{
        bigSum(state){
            return state.sum * 10
        }
    }
}

  • 创建src/vuex/person.js
import axios from "axios"
import { nanoid } from "nanoid"

export default{
    namespaced:true,
    actions:{
        addPersonWang(context,value){
            if(value.name.indexOf('王') === 0){
                context.commit('ADD_PERSON',value)
            }else{
                alert('添加的人必须姓王!')
            }
        },
        addPersonServer(context){
            axios.get('http://api.uixsj.cn/hitokoto/get?type=social').then(
                response => {
                    context.commit('ADD_PERSON',{id:nanoid(),name:response.data})
                },
                error => {
                    alert(error.message)
                }
            )
        }
    },
    mutations:{
        ADD_PERSON(state,value){
            console.log('mutations中的ADD_PERSON被调用了')
            state.personList.unshift(value)
        }
    },
    state:{
        personList:[
            {id:'001',name:'JOJO'}
        ]
    },
    getters:{
        firstPersonName(state){
            return state.personList[0].name
        }
    }
}

  • 创建src/components/Count.vue
<template>
	<div>
		<h1>当前求和为:{{sum}}</h1>
		<h3>当前求和的10倍为:{{bigSum}}</h3>
		<h3>我是{{name}},我在{{school}}学习</h3>
		<h3 style="color:red">Person组件的总人数是:{{personList.length}}</h3>
		<select v-model.number="n">
			<option value="1">1</option>
			<option value="2">2</option>
			<option value="3">3</option>
		</select>
		<button @click="increment(n)">+</button>
		<button @click="decrement(n)">-</button>
		<button @click="incrementOdd(n)">当前求和为奇数再加</button>
		<button @click="incrementWait(n)">等一等再加</button>
	</div>
</template>

<script>
	import {mapState,mapGetters,mapMutations,mapActions} from 'vuex'

	export default {
		name:'Count',
		data() {
			return {
				n:1, //用户选择的数字
			}
		},
		methods: {
			...mapMutations('countOptions',{increment:'ADD',decrement:'SUBTRACT'}),
			...mapActions('countOptions',{incrementOdd:'addOdd',incrementWait:'addWait'})
		},
		computed:{
			...mapState('countOptions',['sum','school','name']),
			...mapGetters('countOptions',['bigSum']),
			...mapState('personOptions',['personList'])
		}
	}
</script>

<style>
	button{
		margin-left: 5px;
	}
</style>

  • 创建src/components/Person.vue
<template>
	<div>
		<h1>人员列表</h1>
		<h3 style="color:red">Count组件求和为:{{sum}}</h3>
        <h3>列表中第一个人的名字是:{{firstPersonName}}</h3>
		<input type="text" placeholder="请输入名字" v-model="name">
		<button @click="add">添加</button>
        <button @click="addWang">添加一个姓王的人</button>
        <button @click="addPerson">随机添加一个人</button>
		<ul>
			<li v-for="p in personList" :key="p.id">{{p.name}}</li>
		</ul>
	</div>
</template>

<script>
	import {nanoid} from 'nanoid'
	export default {
		name:'Person',
		data() {
			return {
				name:''
			}
		},
		computed:{
			personList(){
				return this.$store.state.personOptions.personList
			},
			sum(){
				return this.$store.state.personOptions.sum
			},
            firstPersonName(){
                return this.$store.getters['personOptions/firstPersonName']
            }
		},
		methods: {
			add(){
				const personObj = {id:nanoid(),name:this.name}
				this.$store.commit('personOptions/ADD_PERSON',personObj)
				this.name = ''
			},
            addWang(){
                const personObj = {id:nanoid(),name:this.name}
				this.$store.dispatch('personOptions/addPersonWang',personObj)
				this.name = ''   
            },
            addPerson(){
                this.$store.dispatch('personOptions/addPersonServer')
            }
		},
	}
</script>

App.vue

<template>
	<div class="container">
		<Count/>
		<hr>
		<Person/>
	</div>
</template>

<script>
	import Count from './components/Count'
	import Person from './components/Person'
	export default {
		name:'App',
		components:{Count,Person}
	}
</script>

Vue Router路由管理器(单页面应用)

基本使用:
1.安装vue-router

npm i vue-router

2.编写router配置项,新建src/router/index.js文件

//该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router";
//引入自定义的组件
import xxx from '../components/xxx'
import xxx2 from '../components/xxx2 '

//创建并暴露一个路由器
export default new VueRouter({
    routes:[
        {
            path:'/xxx',//定义跳转,About组件的路由(路径)
            component:xxx  //注册自定义的组件
        },
        {
            path:'/xxx2',//定义跳转,Home组件的路由(路径)
            component:xxx2 //注册自定义的组件
        }
    ]
})

3.在main.js中应用插件:

//引入VueRouter插件
import VueRouter from 'vue-router'
//引入自定义的src/touter/index.js
import router from './router/index.js'
Vue.config.productionTip = false
Vue.use(VueRouter)
new Vue({
    el:"#app",
    render: h => h(App),
    router//注册自定义的路由
})

4.在App.vue组件中使用路由跳转组件

	<!-- 	Vue中借助router-link标签实现路由的切换,
			此处的属性to中配置的是在src/router/index.js中配置的组件路由路径,
			active-class中配置的是,当选中当前路由后,导航栏执行的样式
	 -->
	 
<router-link class="list-group-item" active-class="active" to="/about"> About</router-link>
<br/>
<router-link class="list-group-item" active-class="active" to="/home">Home</router-link>
			
<!-- 指定通过路由跳转的组件的呈现位置 -->
<router-view></router-view>
		

注:路由组件通常存放在src/pages文件夹,一般组件通常存放在src/components文件夹,通过切换,“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载,每个组件都有自己的 $route属性,里面存储着自己的路由信息,整个应用只有一个router,可以通过组件的$router属性获取到

使用步骤案例:

  • 安装
//安装指定版本
npm i vue-router@3
//安装最新版本
npm i vue-router
  • 配置路由
    新建src/router/index.js文件
//该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router";
//引入自定义的组件
import Home from '../components/Home'
import About from '../components/About'

//创建并暴露一个路由器
export default new VueRouter({
    routes:[
        {
            path:'/about',//定义跳转,About组件的路由(路径)
            component:About //注册自定义的组件
        },
        {
            path:'/home',//定义跳转,Home组件的路由(路径)
            component:Home//注册自定义的组件
        }
    ]
})

  • 应用自定义路由配置
    src/main.js
import Vue from 'vue'
import App from './App.vue'
//引入VueRouter插件
import VueRouter from 'vue-router'
//引入自定义的src/touter/index.js
import router from './router/index.js'

Vue.config.productionTip = false
Vue.use(VueRouter)

new Vue({
    el:"#app",
    render: h => h(App),
    router//注册自定义的路由
})

  • 自定义组件
    src/components/Home.vue
<template>
  <h2>我是Home组件的内容</h2>
</template>

<script>
    export default {
        name:'Home'
    }
</script>

src/components/About.vue

<template>
  <h2>我是About组件的内容</h2>
</template>

<script>
    export default {
        name:'About'
    }
</script>

  • 使用路由跳转组件
<template>
	<div>
		<div class="row">
			<div class="col-xs-offset-2 col-xs-8">
				<div class="page-header"><h2>Vue Router Demo</h2></div>
			</div>
		</div>
		<div class="row">
			<div class="col-xs-2 col-xs-offset-2">
				<div class="list-group">
					<!-- 原始html中我们使用a标签实现页面跳转 -->
					<!-- <a class="list-group-item active" href="./about.html">About</a>
					<a class="list-group-item" href="./home.html">Home</a> -->
					
				<!-- 	Vue中借助router-link标签实现路由的切换,
					此处的属性to中配置的是在src/router/index.js中配置的组件路由路径,
					active-class中配置的是,当选中当前路由后,导航栏执行的样式 -->
					<router-link class="list-group-item" active-class="active" to="/about"> 
					 About
    				</router-link>
					<br/>
					<router-link class="list-group-item" active-class="active" to="/home">
                        Home
    				</router-link>
				</div>
			</div>
			<div class="col-xs-6">
				<div class="panel">
					<div class="panel-body">
						<!-- 指定通过路由跳转的组件的呈现位置 -->
						<router-view></router-view>
					</div>
				</div>
			</div>
		</div>
	</div>
</template>

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

路由嵌套(一个组件中跳转另一个子组件)

  • 配置路由规则
    \src\router\index.js
//该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router";
//引入自定义的组件
import xxx from '../components/xxx'
import xxx2 from '../components/xxx2 '

//创建并暴露一个路由器
export default new VueRouter({
    routes:[
        {
            path:'/xxx',//定义跳转,About组件的路由(路径)
            component:xxx  //注册自定义的组件
        },
        {
            path:'/xxx2',//定义跳转,Home组件的路由(路径)
            component:xxx2 //注册自定义的组件
            children:[//配置子路由
				{
				                    path:'xx22', //子组件路由的路径,此处配置的路径
				                    component:xx22//子组件
				                },
				                {
				                    path:'message',
				                    component:Message
				                }
				
			]
        }
    ]
})

  • 使用
<router-link to="/xx2/xx22">News</router-link>
<router-link to="/xx2/xx222">News</router-link>

路由跳转传递参数

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>

  • 接收参数
$route.query.id
$route.query.title

例:
<ul>
        <li>消息编号:{{$route.query.id}}</li>
        <li>消息标题:{{$route.query.title}}</li>
</ul>
  • 通过query传递参数,可以结合props配置,让路由组件更方便的收到参数
{
	
	path:'/home/message/detail',
	component:Detail,

	//第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
	// props:{a:900}

	//第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件
	// props:true
	
	//第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件
	props(route){
		return {
			id:route.query.id,
			title:route.query.title
		}
	}
}

  • 接收props处理过的参数
例:
<template>
    <ul>
        <li>消息编号:{{id}}</li>
        <li>消息标题:{{title}}</li>
    </ul>
</template>

<script>
    export default {
        name:'Detail',
        props:['id','title']
    }
</script>

2.传递params参数

  • 配置路由,声明接收params参数
{
	path:'/home',
	component:Home,
	children:[
		{
			path:'news',
			component:News
		},
		{
			component:Message,
			children:[
				{
					name:'xiangqing',//给路径命名
					path:'detail/:id/:title', //使用占位符声明接收params参数
					component:Detail
				}
			]
		}
	]
}

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

  • 接收参数
$route.params.id
$route.params.title
例:
<ul>
        <li>消息编号:{{$route.params.id}}</li>
        <li>消息标题:{{$route.params.title}}</li>
</ul>

注:路由携带params参数时,若使用to的对象写法,则不能使用path配置项,必须使用name配置!

命名路由(简化跳转路径)

  • 命名路由
{
	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>

控制路由跳转时操作浏览器的后退前进记录

浏览器的历史记录有两种写入方式:push和replace,其中push是追加历史记录,replace是替换当前记录。路由跳转时候默认为push方式

使用:

<router-link replace ...>News</router-link>

编程式路由导航(定时跳转,自动跳转)

使用router-link标签进行跳转,最终router-link都会解析成一个a标签,但是有的时候并不想代码结构中出现这个a标签,所以为了不破坏代码结构,就可以使用变成编程式路由导航从而实现这个功能,或者,有的时候我们希望可以实现,定时跳转,或者自动跳转,那么就可以实现这种方式

//报存本次跳转记录进行跳转
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(1) //前进或后退到指定步数的页面,正数代表前进,负数代表后退

例:

<template>
    <div>
        <ul>
            <li v-for="m in messageList" :key="m.id">
        		<!--通过h1标签进行跳转-->
				<h1 @click="showPush(m)"> 
					 {{m.title}} - push查看
				</h1>
				<h1 @click="showReplace(m)">
					 {{m.title}} - >replace查看
				</h1>
			
            </li>
        </ul>
        <hr/>
        <router-view></router-view>
    </div>
</template>

<script>
    export default {
        name:'News',
        data(){
            return{
                messageList:[
                    {id:'001',title:'消息001'},
                    {id:'002',title:'消息002'},
                    {id:'003',title:'消息003'}
                ]
            }
        },
        methods:{
            showPush(m){
            	//使用push方法进行跳转会在浏览器上留下本次跳转的记录。所以点击浏览器的回退,就会回退到上一个页面
                this.$router.push({
                    name:'xiangqing',
                    query:{
                        id:m.id,
                        title:m.title
                    }
                })
            },
            showReplace(m){
            //使用replace方法跳转,不会在浏览器上留下跳转记录,所以点击回退,就会回退到上上一个页面
                this.$router.replace({
                    name:'xiangqing',
                    query:{
                        id:m.id,
                        title:m.title
                    }
                })
            }
        }
    }
</script>


缓存路由组件(通过路由跳转到其他页面后,保存原页面数据)

因为router在进行路由跳转时,每次都会销毁原来的组件,比如通过A组件跳转到B组件,那么跳转的B组件之后,A组件就会被销毁,所以假如说,原本在A组件当中填写的数据,当跳转到B之后,数据就不存在了,那么就可以使用缓存路由组件的这种方式,避免这种情况的发生

//缓存一个路由组件,
<keep-alive include="News"> //include中写想要缓存的组件名称,不写表示缓存全部组件
    <router-view></router-view>//路由的组件展示位置
</keep-alive>

//缓存多个路由组件
<keep-alive :include="['News','Message']"> 
    <router-view></router-view>//路由的组件展示位置
</keep-alive>

路由守卫(路由跳转时,进行过滤)

以下配置均在src/router/index.js文件中进行:

  • 全局守卫

//该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router";
//创建一个路由器
const router = new VueRouter({
    routes:[
    { name:'xinwen',
      path:'news',
      component:News,
      meta:{//这个meta中定义的数据可以自行变动,只是起到一个携带数据的作用
      isAuth:true,//是否需要路由跳转校验
      title:'我是网页的小标题'//浏览器上展示的网页标题
      }
   }
]
})

//全局前置守卫:初始化时执行、每次路由切换前执行
router.beforeEach((to,from,next)=>{
	console.log('beforeEach',to,from)
	 //判断当前路由是否需要进行权限控制
	if(to.meta.isAuth){
		//获取浏览器本地数据,验证用户是否为管理员,如果是管理员,才允许跳转
		if(localStorage.getItem('username') === '管理员'){ 
			next() //放行
		}else{
			alert('你不是管理员,暂无权限查看')
		}
	}else{
		next() //放行
	}
})

//全局后置守卫:初始化时执行、每次路由切换后执行,即跳转完成之后调用
router.afterEach((to,from) => {
	console.log('afterEach',to,from)
	//判断当前组件中是否配置了title
	if(to.meta.title){ 
	//将当前网页展示的title进行修改
		document.title = to.meta.title 
	}else{
		document.title = '我是默认的网页标题'
	}
})


//导出路由器
export default router
  • 独享守卫

//该文件专门用于创建整个应用的路由器
import VueRouter from "vue-router";
//创建一个路由器
const router = new VueRouter({
    routes:[
    { name:'xinwen',
      path:'news',
      component:News,
      meta:{//这个meta中定义的数据可以自行变动,只是起到一个携带数据的作用
      isAuth:true,//是否需要路由跳转校验
      title:'我是网页的小标题'//浏览器上展示的网页标题
      },
      beforeEnter(to,from,next){//配置一个独享路由守卫,他只服务于当前路由,跳转前执行
	 //获取浏览器本地数据,验证用户是否为管理员,如果是管理员,才允许跳转
		if(localStorage.getItem('username') === '管理员'){ 
			next() //放行
		}else{
			alert('你不是管理员,暂无权限查看')
		}
	}else{
		next() //放行
	} 
  }
 }
]
})


//导出路由器
export default router
  • 组件内部守卫
    在自定义组件src/pages/About.vue中:
<template>
    <h2>我是About组件的内容</h2>
</template>

<script>
    export default {
        name:'About',
        //通过路由规则,进入该组件时被调用,也就是说,别人跳转过来的时候就会调用
        beforeRouteEnter (to, from, next) {
          	 //获取浏览器本地数据,验证用户是否为管理员,如果是管理员,才允许跳转
		if(localStorage.getItem('username') === '管理员'){ 
			next() //放行
		}else{
			alert('你不是管理员,暂无权限查看')
		}
	}else{
		next() //放行
	} 
        },
        //通过路由规则,离开该组件时被调用,也就是说,从该组件切换到其他组件时调用
        beforeRouteLeave (to, from, next) {
            console.log('About--beforeRouteLeave',to,from)
            next()
        }
    }
</script>

路由器的两种工作模式

  • hash模式:
    优点:兼容性较好
    缺点:地址中永远带着#号,不美观
    若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法
    例:
    在这里插入图片描述

  • history模式:
    优点:地址干净,美观
    缺点:兼容性和hash模式相比略差,部署上线后不能刷新和输入url,出现404的问题
    例:
    在这里插入图片描述
    模式切换:

//创建一个路由器
const router = new VueRouter({
	mode:"history"//切换到history模式,默认是hash模式,所以,默认无需配置
    routes:[...]
})

解决在history模式下,页面404问题

Vue UI组件库

ElementUI官网

使用vue+elementui搭建的后台管理系统模板

ElementUI全局引入

  • 安装
npm i element-ui -S
  • 使用
    src/main.js
import Vue from 'vue'
import App from './App.vue'
//引入ElementUI组件库
import ElementUI from 'element-ui';
//引入ElementUI全部样式
import 'element-ui/lib/theme-chalk/index.css';

Vue.config.productionTip = false
//使用ElementUI
Vue.use(ElementUI)

new Vue({
    el:"#app",
    render: h => h(App),
})

src/App.vue

<template>
	<div>
		<br>
		<el-row>
			<el-button icon="el-icon-search" circle></el-button>
			<el-button type="primary" icon="el-icon-edit" circle></el-button>
			<el-button type="success" icon="el-icon-check" circle></el-button>
			<el-button type="info" icon="el-icon-message" circle></el-button>
			<el-button type="warning" icon="el-icon-star-off" circle></el-button>
			<el-button type="danger" icon="el-icon-delete" circle></el-button>
		</el-row>
	</div>
</template>

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

ElementUI按需引入

  • 安装 babel-plugin-component
npm install babel-plugin-component -D
  • 修改babel-config-js

module.exports = {
  presets: [
    '@vue/app',
    ["@babel/preset-env", { "modules": false }]
  ],
  plugins: [
    [
      "component",
      {
        "libraryName": "element-ui",
        "styleLibraryName": "theme-chalk"
      }
    ]
  ]
}

  • 按需引入相应组件
    src/main.js
import Vue from 'vue'
import App from './App.vue'
//按需引入
import { Button,Row } from 'element-ui'


Vue.config.productionTip = false

Vue.component(Button.name, Button);
Vue.component(Row.name, Row);
/* 或写为
 * Vue.use(Button)
 * Vue.use(Row)
 */

new Vue({
    el:"#app",
    render: h => h(App),
})

你可能感兴趣的:(vue.js,javascript,前端)