Vue保姆级入门教程


提示:以下是本篇文章正文内容,下面案例可供参考

一、Vue

1.1 Vue介绍

  • Vue官网
  • 动态构建用户界面的渐进式 JavaScript 框架
  • 作者: 尤雨溪

1.2 Vue特点

  • 遵循 MVVM 模式
  • 编码简洁, 体积小, 运行效率高, 适合移动/PC 端开发
  • 它本身只关注 UI, 也可以引入其它第三方库开发项目

1.3 Vue周边库

  • vue-cli: vue 脚手架
  • vue-resource
  • axios
  • vue-router: 路由
  • vuex: 状态管理
  • element-ui: 基于 vue 的 UI 组件库(PC 端)

二、初始Vue

2.1 插值语法

  • 功能: 用于解析标签体内容
  • 语法: {{xxx}} ,xxxx 会作为 js 表达式解析
<!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>Document</title>
    <script src="js/vue.js"></script>
</head>
<body>
    <!-- 创建一个存放vue数据的容器 -->
    <div id="root">
        <!-- {{xxx}}  可以直接获取vue实例中data里相对应的数据 -->
            {{name}} 
    </div>
    <script>
        // 创建一个vue实例对象
        let x=new Vue({
            //对应的容器id,也可以是类选择器
            el:"#root",
            //存放的数据  
            data:{
                name:"zhangsan",
                url:"www.baidu.com",
            }
        });
    </script>
</body>
</html>

2.2 指令语法

2.2.1 v:bind / 简写 : 指令 单向数据绑定

  • 功能: 解析标签属性、解析标签体内容、绑定事件
  • 举例:v-bind:href = ‘xxxx’ ,xxxx 会作为 js 表达式被解析 xxx为数字时,不会被当做String类型解析
  • 说明:Vue 中有有很多的指令,此处只是用 v-bind 举个例子
<!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>Document</title>
    <script src="js/vue.js"></script>
</head>
<body>
    <!-- 创建一个存放vue数据的容器 -->
    <div id="root">
            <a v-bind:href="url">跳转页面(会获取实例中data里面的url数据)</a>
    </div>
    <script>
        // 创建一个vue实例对象
        let x=new Vue({
            //对应的容器id,也可以是类选择器
            el:"#root",
            //存放的数据  
            data:{
                name:"zhangsan",
                url:"www.baidu.com",
            }
        });
    </script>
</body>
</html>

2.2.2 v-model 双向数据绑定

  • 语法:v-mode:value=“xxx” 或简写为 v-model=“xxx”
  • 特点:数据不仅能从 data 流向页面,还能从页面流向 data
  • 备注:v-model:value可以简写为v-model,因为v-model默认收集的就是value值
  • 注意:v-model只能应用在表单类元素(输入类元素 input,select 等)
	<input type="text" v-model:value="name">

2.3 事件处理

语法:v-on:xxx 或 @xxx 绑定事件,十中xxx是事件名 例: v-on:click 单击事件

<!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>Document</title>
    <script src="js/vue.js"></script>
</head>
<body>
    <!-- 创建一个存放vue数据的容器 -->
            <!-- 事件绑定的两种方法 -->
            <span id="cli" v-on:click="showInfo">点我</span>
            <span @click="showInfo($event,66)">点我</span>
    </div>

    <script>
        // 创建一个vue实例对象
        let x=new Vue({
            //对应的容器id,也可以是类选择器
            el:"#root",
            //存放的数据  
            data:{
                name:"zhangsan",
                url:"www.baidu.com",
            },
            methods: {
                showInfo(){
                    alert(1);
                },
                showInfo(event,number){
                    console.log(event,number);
                }
            },
        });
        
    </script>
</body>
</html>

2.4 事件修饰符

  • 加在事件处理的后面 以 . 开始 加
	1. prevent:阻止默认事件(常用)
	<a href="www.baidu.com" @click.prevent="showInfo($event,66)">点我阻止默认事件</a>
	2. stop:阻止事件冒泡(常用)
	
	3. once:事件只触发一次(常用)

2.5 键盘事件

  • Vue中常用的按键别名 @keyup.xxx=“方法名”/@keydown.xxx=“方法名” xxx代表下面的按键别名
	1. 回车=> enter
	2. 删除=> delete(捕获“删除”和“退格”键)
	3. 退出=> esc
	4. 空格=> space
	5. 换行=> tab(特殊,必须配合@keydown使用)
	6. 上=> up
	7. 下=> down
	8. 左=> left
	9. 右=>right
  • 使用按键别名
<!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>Document</title>
    <script src="js/vue.js"></script>
</head>
<body>
    <!-- 创建一个存放vue数据的容器 -->
    <div id="root" v-bind:href="url">
            键盘事件:<input type="text" @keyup.enter="keycode">
    </div>

    <script>
        // 创建一个vue实例对象
        let x=new Vue({
            //对应的容器id,也可以是类选择器
            el:"#root",
            //存放的数据  
            data:{
                name:"zhangsan",
                url:"www.baidu.com",
            },
            methods: {
                keycode(e){
                    //打印文本的值
                    console.log(e.target.value);
                }

            },
        });
        
    </script>
</body>
</html>

2.6 计算属性

	计算属性:
		1. 定义:要用的属性不存在,要通过已有属性计算得来
		2. 原理:底层借助了Object.defineproperty方法提供的getter和setter
		3. get函数什么时候执行?
			(1). 初次读取时会执行一次
			(2). 当依赖的数据发生改变时会被再次调用。
		4. 优势:与methods实现相比,内部有缓存机制(复用),效率更高,调试方便。
		5. 备注:
			(1). 计算属性最终会出现在vm上,直接读取使用即可。
			(2). 如果计算属性要被修改,那必须写set函数去响应修改,且set中要引起计算时依赖的数据发生改变。
<!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>Document</title>
    <script src="js/vue.js"></script>
</head>
<body>
    <div id="root">
        firstName:<input type="text" v-model="firstName"><br>
        lastName:<input type="text" v-model="lastName"><br>
        全名:<span> {{fullName}} </span>
    </div>
    <script>
        new Vue({
            el:"#root",
            data:{
                firstName:"张",
                lastName:"三",
            },
            computed: {
                // 直接当做普通属性调用不加括号
                // 任何data中数据变化立即重新计算
                // 计算属性会缓存
                fullName:{
                    //get有什么用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
                    //get什么时候用? 1.初次读取fullName时候。 2.所依赖的数据发生变化时。
                    get(){
                        return this.firstName+"-"+this.lastName;
                    }
                    set(value){
                        console.log(属性被修改);
                        const arr=value.split["-"];
                        this.firstName=arr[0];
                        this.lastName=arr[1];
                    }
                }
            },
        })
    </script>
</body>
</html>
  • 计算属性简写:只考虑展示数据,不考虑修改数据时,可以使用
<body>
    <div id="root">
        firstName:<input type="text" v-model="firstName"><br>
        lastName:<input type="text" v-model="lastName"><br>
        全名:<span> {{fullName}} </span>
    </div>
    <script>
        new Vue({
            el:"#root",
            data:{
                firstName:"张",
                lastName:"三",
            },
            computed: {
                // 直接当做普通属性调用不加括号
                // 任何data中数据变化立即重新计算
                // 计算属性会缓存
                // fullName:{
                //     //get有什么用?当有人读取fullName时,get就会被调用,且返回值就作为fullName的值
                //     //get什么时候用? 1.初次读取fullName时候。 2.所依赖的数据发生变化时。
                //     get(){
                //         return this.firstName+"-"+this.lastName;
                //     },
                //     set(value){
                //         console.log(属性被修改);
                //         const arr=value.split["-"];
                //         this.firstName=arr[0];
                //         this.lastName=arr[1];
                //     }
                // },

                //上面fullName的简写 可以直接写要展示的方法即可
                fullName(){
                    return this.firstName+"-"+this.lastName;
                }
            },
        })
    </script>
</body>  

2.7 监听属性

<script>
        new Vue({
            el: "#root",
            data: {
                firstName: "张",
                lastName: "三",
            },
            watch: {
                //语法
                /** 1.
                 *  要监视的对象:{
                 *      handler(newVal,oldVal){
                 *          
                 *      }
                 *  }
                 *  2.
                 *  要监视的对象:(newVal,oldVal)->{
                 *      业务
                 *  }
                **/
                firstName: (newVal, oldVal) => {
                    console.log(newVal, oldVal);
                },
                lastName: {
                	immediate:true, //初始化时让handler调用一下
                    handler(newVal, oldVal) {
                        console.log(newVal, oldVal);
                    }
                },
                //监测属性 简写
                firstName(newVal, oldVal){
                    console.log(newVal, oldVal);
                }
            },

        })
    </script>

2.8 计算属性与监听属性之间的区别

  • computed和watch的区别
	1. computed能完成的功能,watch都可以完成。
	2. watch能完成的功能,computed不一定能完成,例如:watch可以进行异步操作。
  • 两个重要的小原则:
	1. 所被Vue管理的函数,最好写成普通函数,这样this的指向才是 vm 或 组件实例对象
	2. 所有不被Vue管理的函数(定时器回调函数,ajax的回调函数,Promise的回调函数),最好写成箭头函数,这样this的指向才是 vm 或 组件实例对象

2.9 条件渲染

<!-- v-show做条件渲染:true显示标签,false给标签加上display:none隐藏标签 -->
        <a href="#" v-show="true">超链接</a>
        <a href="#" v-show="false">超链接</a>
        <!-- v-if做条件渲染:true显示标签,false给标签删除 -->
        <a href="#" v-if="true">超链接</a>
        <a href="#" v-if="false">超链接</a>

2.10 条件渲染

<body>
    <div id="root">
        <ul>
            <!-- 需要遍历哪个标签,v-for遍历就加在哪个标签身上  -->
            <!-- key放在虚拟DOM中进行diff算法运行时用到,key最好使用数据中的唯一表示,防止出现意想不到的BUG-->
            <!-- 若不写key,默认是采用index索引值当做key-->
            <li v-for="(person,index) in persons" :key="person.id">
                {{person.name}}--{{person.age}}-{{index}}--{{person.id}}
            </li>
        </ul>
    </div>
    <script>
        new Vue({
            el:"#root",
            data:{
                persons:[
                    {id:"001",name:"张三",age:16},
                    {id:"002",name:"李四",age:17},
                    {id:"003",name:"王五",age:18},
                ]
            }
        })
    </script>
</body>

2.11 收集表单数据的细节

<!-- 
			收集表单数据:
					若:<input type="text"/>,则v-model收集的是value值,用户输入的就是value值。
					若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值。
					若:<input type="checkbox"/>
							1.没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)
							2.配置input的value属性:
									(1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
									(2)v-model的初始值是数组,那么收集的的就是value组成的数组
					备注:v-model的三个修饰符:
									lazy:失去焦点再收集数据
									number:输入字符串转为有效的数字
									trim:输入首尾空格过滤
		-->
	<body>
		<!-- 
			收集表单数据:
					若:<input type="text"/>,则v-model收集的是value值,用户输入的就是value值。
					若:<input type="radio"/>,则v-model收集的是value值,且要给标签配置value值。
					若:<input type="checkbox"/>
							1.没有配置input的value属性,那么收集的就是checked(勾选 or 未勾选,是布尔值)
							2.配置input的value属性:
									(1)v-model的初始值是非数组,那么收集的就是checked(勾选 or 未勾选,是布尔值)
									(2)v-model的初始值是数组,那么收集的的就是value组成的数组
					备注:v-model的三个修饰符:
									lazy:失去焦点再收集数据
									number:输入字符串转为有效的数字
									trim:输入首尾空格过滤
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<form @submit.prevent="demo">
				账号:<input type="text" v-model.trim="userInfo.account"> <br/><br/>
				密码:<input type="password" v-model="userInfo.password"> <br/><br/>
				年龄:<input type="number" v-model.number="userInfo.age"> <br/><br/>
				性别:
				男<input type="radio" name="sex" v-model="userInfo.sex" value="male"><input type="radio" name="sex" v-model="userInfo.sex" value="female"> <br/><br/>
				爱好:
				学习<input type="checkbox" v-model="userInfo.hobby" value="study">
				打游戏<input type="checkbox" v-model="userInfo.hobby" value="game">
				吃饭<input type="checkbox" v-model="userInfo.hobby" value="eat">
				<br/><br/>
				所属校区
				<select v-model="userInfo.city">
					<option value="">请选择校区</option>
					<option value="beijing">北京</option>
					<option value="shanghai">上海</option>
					<option value="shenzhen">深圳</option>
					<option value="wuhan">武汉</option>
				</select>
				<br/><br/>
				其他信息:
				<textarea v-model.lazy="userInfo.other"></textarea> <br/><br/>
				<input type="checkbox" v-model="userInfo.agree">阅读并接受<a href="http://www.baidu.com">《用户协议》</a>
				<button>提交</button>
			</form>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false

		new Vue({
			el:'#root',
			data:{
				userInfo:{
					account:'',
					password:'',
					age:18,
					sex:'female',
					hobby:[],
					city:'beijing',
					other:'',
					agree:''
				}
			},
			methods: {
				demo(){
					console.log(JSON.stringify(this.userInfo))
				}
			}
		})
	</script>

2.12 内置指令

2.12.1 v-text

  • 向其所在的标签插入文本
v-text指令:
						1.作用:向其所在的节点中渲染文本内容。
						2.与插值语法的区别:v-text会替换掉节点中的内容,{{xx}}则不会。
<!-- 准备好一个容器-->
		<div id="root">
			<div>你好,{{name}}</div>
			<div v-text="name"></div>
			<div v-text="str"></div>
		</div>

2.12.2 v-html

<!-- 
				v-html指令:
						1.作用:向指定节点中渲染包含html结构的内容。
						2.与插值语法的区别:
									(1).v-html会替换掉节点中所有的内容,{{xx}}则不会。
									(2).v-html可以识别html结构。
						3.严重注意:v-html有安全性问题!!!!
									(1).在网站上动态渲染任意HTML是非常危险的,容易导致XSS攻击。
									(2).一定要在可信的内容上使用v-html,永不要用在用户提交的内容上!
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<div>你好,{{name}}</div>
			<div v-html="str"></div>
			<div v-html="str2"></div>
		</div>

2.12.3 v-once

<body>
		<!-- 
			v-once指令:
						1.v-once所在节点在初次动态渲染后,就视为静态内容了。
						2.以后数据的改变不会引起v-once所在结构的更新,可以用于优化性能。
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<h2 v-once>初始化的n值是:{{n}}</h2>
			<h2>当前的n值是:{{n}}</h2>
			<button @click="n++">点我n+1</button>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		
		new Vue({
			el:'#root',
			data:{
				n:1
			}
		})
	</script>

2.12.4 v-pre

<body>
		<!-- 
			v-pre指令:
					1.跳过其所在节点的编译过程。
					2.可利用它跳过:没有使用指令语法、没有使用插值语法的节点,会加快编译。
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<h2 v-pre>Vue其实很简单</h2>
			<h2 >当前的n值是:{{n}}</h2>
			<button @click="n++">点我n+1</button>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。

		new Vue({
			el:'#root',
			data:{
				n:1
			}
		})
	</script>

2.13 Vue生命周期

2.13.1 什么是生命周期

				生命周期:
						1.又名:生命周期回调函数、生命周期函数、生命周期钩子。
						2.是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。
						3.生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。
						4.生命周期函数中的this指向是vm 或 组件实例对象。
  • 演示
	<body>
		<!-- 
				生命周期:
						1.又名:生命周期回调函数、生命周期函数、生命周期钩子。
						2.是什么:Vue在关键时刻帮我们调用的一些特殊名称的函数。
						3.生命周期函数的名字不可更改,但函数的具体内容是程序员根据需求编写的。
						4.生命周期函数中的this指向是vm 或 组件实例对象。
		-->
		<!-- 准备好一个容器-->
		<div id="root">
			<h2 v-if="a">你好啊</h2>
			<h2 :style="{opacity}">欢迎学习Vue</h2>
		</div>
	</body>

	<script type="text/javascript">
		Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
		
		 new Vue({
			el:'#root',
			data:{
				a:false,
				opacity:1
			},
			methods: {
				
			},
			//Vue完成模板的解析并把初始的真实DOM元素放入页面后(挂载完毕)调用mounted
			mounted(){
				console.log('mounted',this)
				setInterval(() => {
					this.opacity -= 0.01
					if(this.opacity <= 0) this.opacity = 1
				},16)
			},
		})

		//通过外部的定时器实现(不推荐)
		/* setInterval(() => {
			vm.opacity -= 0.01
			if(vm.opacity <= 0) vm.opacity = 1
		},16) */
	</script>
</html>
  • 借鉴声明周期图
    在这里插入图片描述

2.13.2 声明周期总结

常用的生命周期钩子:
				1.mounted: 发送ajax请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】。
				2.beforeDestroy: 清除定时器、解绑自定义事件、取消订阅消息等【收尾工作】。

关于销毁Vue实例
				1.销毁后借助Vue开发者工具看不到任何信息。
				2.销毁后自定义事件会失效,但原生DOM事件依然有效。
				3.一般不会在beforeDestroy操作数据,因为即便操作数据,也不会再触发更新流程了。

三、Vue组件化编程

3.1组件的理解

  • 组件的定义:实现应用中局部功能代码和资源的集合
    在这里插入图片描述

3.2 非单文件组件

  • 一个文件中包含n个组件

3.3 组件的基本实用(以后基本不会使用)

Vue中使用组件的三大步骤:
					一、定义组件(创建组件)
					二、注册组件
					三、使用组件(写组件标签)

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

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

			三、编写组件标签:
							<school></school>
  • 演示
<body>
    <div id="root">
        <!-- 第三步:编写组件标签 -->
        <student></student>
        <hr>
    </div>
    <script>
        //第一步:创建school组件
        const student=Vue.extend({
            template:`
                <div>
                    <h2>{{student}}</h2>    
                    <h2>{{major}}</h2>    
                </div>
            `,
            // el:'#root', //组件定义时,一定不要写el配置项,因为最终所有的组件都要被一个vm管理,由vm决定服务于哪个容器。
            data(){
                return {
                  student:"安阳工学院",
                  major:"计算机",
                }
            },
        })
        //第二步:全局注册组件
		Vue.component('student',student)
        new Vue({
            el:"#root",
            //第二步:注册组件(局部注册)
            components:{
                student:student,
            }
        })
    </script>
</body>

3.4 VueComponent

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

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

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

	4.关于this指向:
			(1).组件配置中:
				data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】。
			(2).new Vue(options)配置中:
				data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。

3.5 模块化的三种暴露方式

  • 模块化三种暴露方式
  1. 分别暴露
<script>
// 组件交换相关的代码(数据、方法等)
       export const student=Vue.extend({
            data(){
                return {
                  student:"安阳工学院",
                  major:"计算机",
                }
            },
        })
</script>
  1. 同意暴露
<script>
// 组件交换相关的代码(数据、方法等)
        const student=Vue.extend({
            data(){
                return {
                  student:"安阳工学院",
                  major:"计算机",
                }
            },
        })
        export {school}
</script>
  1. 默认暴露(用的较多)
<script>
// 组件交换相关的代码(数据、方法等)
        export default {
        	name:"和当前vue组件的文件名同步"
            data(){
                return {
                  student:"安阳工学院",
                  major:"计算机",
                }
            },
        }
        export default school
</script>

四、安装vue-cli

  • 安装 vue-cli之前先安装node

4.1 步骤

  • 使用cmd 管理员
	1. 配置npm淘宝镜像 防止下载过慢
		npm config set registry https://registry.npm.taobao.org
	2.  全局安装@Vue/cli
		npm install -g @vue/cli
	3. 创建项目
		vue create 项目名
		创建vue2项目要使用 npm 
	4. 启动项目
		npm run serve

4.2 文件结构

在这里插入图片描述

4.3 ref属性

	1. 被用来给元素或子组件注册引用信息(id的替代者)
	2. 应用在html标签上获取的是真实DOM元素,应用在组件标签上是组件实例对象(VueComponent)
	3. 使用方式
		打标识: <h1 ref="xxx"></h1> 或 <School ref="xxx"></School>
		获取:this.$refs.xxx

4.4 props属性

  • 当别人要用我们的组件,数据不一样时,我们就不能把当前组件的数据写死,我们需要让调用者给我们这个组件的标签 传入参数
  • 传入参数
<template>
  <div>
  	//动态传入参数
    <Student name="张三" :age="16"></Student>
    <div v-text="msg"></div>
    <button>点我输出</button>
  </div>
</template>
    
<script>
import Student from "./components/Student.vue";
export default {
  data() {
      return {
          msg: "欢迎学习Vue",
      }
  },
  components: {
    Student,
  },

};
</script>
  • 定义props 接收参数
<template>
    <div>
        <h2>姓名:{{name}}</h2>
        <h2>年龄:{{age}}</h2>
    </div>
</template>

<script>
export default {
    name:"Student",
    data() {
        return {
            // name:"法外狂徒-张三",
            // age:16,
        }
    },
    //简单声明接收
    props:["name","age"],
    //接收的同时对数据进行类型的限制
    props:{
        name:String,
        age:Number,
    },
    //接收的同时对数据:进行类型限制+默认值指定+必要性的限制
    props:{
        name:{
            type:String,//name的类型
            required:true,//name是必须要传的
        },
        age:{
            type:Number,//age的类型
            default:22,//age如果不传,默认值是22
        }
    }
}
</script>
  • 备注:
	props是只读的,Vue底层会检测你对props的修改,如果进行了修改,就会发出警告。若业务需要确实需要修改,那么请赋值props的内容到data中一份,然后去修改data中的数据。

4.5 mixin属性

  • mixin(混入)
	功能:可以把多个组件共用的配置提取成一个混入对象
	使用方式:
		第一步定义混合,例如:
			export default {
				data(){...},
				methods:{...},
				...
			}
		第二步使用混入,例如:
			1. 全局混入:Vue.mixin(xxx)
			2. 局部混入:mixins:[xxx]

4.6 插件

  • 功能:用于增强Vue
  • 本质:包含install方法的一个对象,install的第一个参数是Vue,第二个以后的参数是插件使用者传递的数据。
	定义插件:
		export default{
			install(Vue){
				插件,
				插件,
				...
			}
		}
	使用插件:
		引入插件:
			import plugins from "插件的js文件"
		应用插件:
			Vue.use(plugins)
		

4.7 scoped样式

  • 作用:让样式在局部(每个组件中)生效,防止冲突
  • 写法:

4.8 组件自定义事件

  1. 一种组件之间的通信方式,适用于 子组件===>父组件
  • 写法1:
  1. 组件Student.vue
<template>
    <div>
        <h2>姓名:{{name}}</h2>
        <h2>年龄:{{age}}</h2>
        
        <button @click="sendStudentName">触发mk事件</button>
    </div>
</template>

<script>
export default {
    name:"Student",
    data() {
        return {
            name:"法外狂徒-张三",
            age:16,
        }
    },
    methods:{
        sendStudentName(){
            //触发Student组件实例对象身上的mk事件
            this.$emit("mk",this.name);
        }
    }
}
</script>

<style>
</style>
  1. App.vue
<template>
  <div>
  	//自定义组件 名称 mk 当触发了mk事件 调用 demo方法
    <Student v-on:mk="demo"></Student>
    <div v-text="msg"></div>
  </div>
</template>
    
<script>
import Student from "./components/Student.vue";
export default {
  data() {
      return {
          msg: "欢迎学习Vue",
      }
  },
  methods:{
    demo(name){
      console.log("demo方法被调用了",name);
    }
  },
  components: {
    Student,
  },

};
</script>
  • 写法2:
  1. 组件Student.vue
<template>
    <div>
        <h2>姓名:{{name}}</h2>
        <h2>年龄:{{age}}</h2>

        <button @click="sendStudentName">触发t1事件</button>
    </div>
</template>

<script>
export default {
    name:"Student",
    data() {
        return {
            name:"法外狂徒-张三",
            age:16,
        }
    },
    methods:{
        sendStudentName(){
            //触发Student组件实例对象身上的mk事件
            this.$emit("t1",this.name);
        }
    }
}
</script>
  1. App.vue
<template>
  <div>
    <Student ref="t1"></Student>
    <div v-text="msg"></div>
  </div>
</template>
    
<script>
import Student from "./components/Student.vue";
export default {
  data() {
      return {
          msg: "欢迎学习Vue",
      }
  },
  methods:{
    demo(name){
      console.log("demo方法被调用了");
    }
  },
  //当App.vue中的数据创建好后,会触发mounted方法执行
  mounted() {
    //this.$refs.mk会拿到mk的这个组件实例对象
    //给mk这个组件实例对象绑定 自定义事件t1,当t1这个自定义事件被触发调用 demo方法
    this.$refs.mk.$on("t1",this.demo);
  },
  components: {
    Student,
  },

};
</script>

4.9 解绑自定义事件

  • 组件Student.vue 解绑自定义事件
<script>
export default {
    name:"Student",
    data() {
        return {
            name:"法外狂徒-张三",
            age:16,
        }
    },
    methods:{
        sendStudentName(){
            //触发Student组件实例对象身上的mk事件
            this.$emit("t1",this.name);
            this.$emit("t2",this.age);
        },
        unbind(){
            this.$off("t1");//解绑一个自定义事件
            this.$off(["t1","t2"]);//解绑多个自定义事件
            this.$off();//解绑所有自定义事件
        }
    }
}
</script>
  • App.vue
<script>
import Student from "./components/Student.vue";
export default {
  data() {
      return {
          msg: "欢迎学习Vue",
      }
  },
  methods:{
    demo(name){
      console.log("demo方法被调用了");
    },
    t2(age){
      console.log(age);
    }
  },
  //当App.vue中的数据创建好后,会触发mounted方法执行
  mounted() {
    //this.$refs.mk会拿到mk的这个组件实例对象
    //给mk这个组件实例对象绑定 自定义事件t1,当t1这个自定义事件被触发调用 demo方法
    this.$refs.mk.$on("t1",this.demo);
    this.$refs.mk.$on("t2",this.t2);
  },
  components: {
    Student,
  },

};
</script>

4.10 全局事件总线(开发中用的较多)

  • 全局时间总线:任意组件之间的通信
  1. 安装全局事件总线 main.js
//引入Vue
import Vue from "vue"
import App from './App.vue'
//关闭生产提示
Vue.config.productionTip=false
new Vue({
    //将App组件放入到容器中
    render:h=>h(App),
    beforeCreate() {
        Vue.prototype.$bus=this;//安装全局事件总线,this指的是当前应用的vm
    },
}).$mount("#app")
  1. 使用全局事件总线:A想接受数据
export default {
  data() {
      return {
          msg: "欢迎学习Vue",
      }
  },
  methods:{
    demo(name){
      console.log("demo方法被调用了");
    },
    t2(age){
      console.log(age);
    },
    t3(data){
      console.log("全局事件总线===>",data);
    }
  },
  //当App.vue中的数据创建好后,会触发mounted方法执行
  mounted() {
    //给$bus这个全局事件总线绑定 自定义事件hello,当hello这个自定义事件被触发调用 this.t3方法
    this.$bus.$on("hello",this.t3);
  },
  components: {
    Student,
  },

};
  1. 使用全局事件总线:
export default {
    name:"Student",
    data() {
        return {
            name:"法外狂徒-张三",
            age:16,
        }
    },
    methods:{
        sendStudentName(){
            //触发全局事件总线身上的hello事件,给hello的回调方法传参
            this.$bus.$emit("hello",this.name);
        },
        beforeDestroy(){
        //最好用beforeDestory钩子中,用$off("事件名")去解绑当前组件所用到的事件
        this.$bus.$off("hello");
    	}
    }
}

4.11 Vue过度动画

<template>
  <div>
      <button @click="isShow = !isShow">显示/隐藏</button>
      <!-- Vue内置动画标签,把动画放入即可
        appear:打开浏览器动画从无到有
        name:若给name赋予了名字,那么Vue定义的动画类名 必须写为: xxx-enter/leave-active
       -->
      <transition name="xxx" appear>   
            <h1 v-show="isShow" >你好啊</h1>
      </transition>
  </div>
</template>

<script>
export default {
    name:"Test",
    data() {
        return {
            isShow:true,
        }
    },
}
</script>

<style>
    h1{
        background-color: orange;
    }
    /* Vue定义的动画起始类名 */
    .v-enter-active{
        animation: ani 1s;
    }
        /* Vue定义的动画反转类名 */
    .v-leave-active{
        animation: ani 1s reverse;
    }
    /* 定义一个动画 */
    @keyframes ani {
        from{
            transform: translateX(-100%);
        }
        to{
            transform: translateX(0px);
        }
    }
</style>

4.11.1 继承第三方动画库

animate第三方动画库官网

  • 使用
	0. 下载animate.css
		npm install animate.css --save
	1. 引入animate.css文件
		import 'animate.css'
	2. 在Vue动画标签上的name属性写入动画库指定的名称
		name="animate__animated animate__bounce"
	3. 在Vue动画标签上写入进场动画类名和退场动画类名
		enter-active-class="进场效果" leave-active-class="退场效果"
	4. 效果去官方获取想要的写入类名即可
  • 测试
<template>
  <div>
      <button @click="isShow = !isShow">显示/隐藏</button>
      <!-- Vue内置动画标签,把动画放入即可
        appear:打开浏览器动画从无到有
        name:若给name赋予了名字,那么Vue定义的动画类名 必须写为: xxx-enter/leave-active
       -->
      <transition name="animate__animated animate__bounce" enter-active-class="animate__bounce" leave-active-class="animate__backOutUp" appear>   
            <h1 v-show="isShow"  >你好啊</h1>
      </transition>
  </div>
</template>

<script>
import 'animate.css'
export default {
    name:"Test",
    data() {
        return {
            isShow:true,
        }
    },
}
</script>

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

五、Axios

5.1 使用axios

  1. 下载axios
	npm i axios
  1. 引用axios
	import axios from 'axios'

5.2 Vue脚手架配置代理

  • 解决跨域问题
  1. 方法一: 在vue.config.js中添加如下配置
//配置代理对象
devServer: {
    proxy: 'http://localhost:后端端口号'
  }
  • 说明:
    1. 优点:配置简单,请求资源时直接发给前端(8080)即可
    2. 缺点:不能配置多个代理,不能灵活控制请求是否走代理
    3. 工作方式:若按照上述配置代理,当请求了前端不存在的资源时,那么该请求会转发给服务器(有限匹配前端资源)
  1. 方法二
module.exports = {
	devServer: {
      proxy: {
      '/api1': {// 匹配所有以 '/api1'开头的请求路径
        target: 'http://localhost:5000',// 代理目标的基础路径
        changeOrigin: true,
        pathRewrite: {'^/api1': ''}//把以api1开头的路径去掉发送给target路径
      },
      '/api2': {// 匹配所有以 '/api2'开头的请求路径
        target: 'http://localhost:5001',// 代理目标的基础路径
        changeOrigin: true,
        pathRewrite: {'^/api2': ''}
      }
    }
  }
}
/*
   changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
   changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:8080
   changeOrigin默认值为true
*/
  • 前台发送请求
export default {
    methods: {
        getStu(){
            axios.get("http://localhost:8080/api1/students").then(
                response=>{
                    console.log("请求成功了",response,response.data);
                },error=>{
                    console.log("请求失败了",error,error.message);
                }
            )
        }
    },
  

};

说明:

  1. 优点:可以配置多个代理,且可以灵活的控制请求是否走代理。
  2. 缺点:配置略微繁琐,请求资源时必须加前缀。

5.3 插槽

  • 作用:让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于 父组件 ===> 子组件
  • 分类:默认插槽、具名插槽、作用域插槽
  1. 默认插槽
父组件中:
        <Student>
           <div>html结构1</div>
        </Student>
子组件中:
        <template>
            <div>
               <!-- 定义插槽 -->
               <slot>插槽默认内容...</slot>
            </div>
        </template>
  1. 具名插槽
父组件中:
        <Student>
            <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>
  1. 作用域插槽
  • 理解:数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。(数据在Stu组件中,但使用数据遍历出来的解构由App主组件决定)
父组件中:
		<Stu>
			//scope中定义的变量名就是子组件中定义的games所有数据(名字不强制要求可以随意)
			<template scope="scopeData">
				<!-- 生成的是ul列表 -->
				<ul>
					<li v-for="g in scopeData.games" :key="g">{{g}}</li>
				</ul>
			</template>
		</Stu>

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

六、Vuex

在这里插入图片描述

6.1概念

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

6.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
})
  1. main.js中创建vm时传入store配置项
......
//引入store
import store from './store/index.js'
......

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

6.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,
})
  1. 组件中读取vuex中的数据:$store.state.sum
  2. 组件中修改vuex中的数据:$store.dispatch('action中的方法名',数据)$store.commit('mutations中的方法名',数据)
  3. 备注:若没有网络请求或其他业务逻辑,组件中也可以越过actions,即不写dispatch,直接编写commit

6.5 getters

  • 概念:当state中的数据需要经过加工后再使用时,可以使用getters加工。
  • store/index.js中追加getters配置
const getters = {
	bigSum(state){
		return state.sum * 10
	}
}

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

七、路由

  • 理解: 一个路由(route)就是一组映射关系(key - value),多个路由需要路由器(router)进行管理。
  • 前端路由:key是路径,value是组件。 当访问key路径时,指定的位置会展示指定的组件
    注意点
    1. 路由组件通常存放在pages文件夹,一般组件通常存放在components文件夹。
    2. 通过切换,“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载。
    3. 每个组件都有自己的$route属性,里面存储着自己的路由信息。
    4. 整个应用只有一个router,可以通过组件的$router属性获取到。

7.1 基本使用

  1. 安装vue-router路由命令: npm i vue-router
  2. 应用插件:Vue.use(引入路由的自定义名称)
  3. 编写route配置:在src下创建index.js配置路由 src/index.js
//该文件专门用于创建整个应用的路由器
//引入VueRouter
import VueRouter from 'vue-router'
//引入Luyou 组件
import About from '../components/About'
import Home from '../components/Home'

//创建router实例对象,去管理一组一组的路由规则
export default new VueRouter({
	routes:[
		{
			path:'/about',
			component:About
		},
		{
			path:'/home',
			component:Home
		}
	]
})
  1. 实现切换(active-class可配置高亮样式)
<router-link active-class="active" to="/home(路由中配置的路径)">About</router-link>
  1. 指定展示位置
	<router-view></router-view>

7.2 多级路由(覆盖路由)

  • 在一个路由规则中再定义路由
  1. 配置路由规则,使用children配置项:
//创建一个路由器
export default new VueRouter({
    //路由
    routes:[
        {
            path:'/about',component:About,
            
        },
        {
            path:'/home',component:Home,       
            //配置子级路由
            children:[
                {
                    //此处不要加 /
                    path:"news",
                    component:News,
                },
                {
                    path:"message",
                    component:Message,
                }
            ]
        },
    ]
})
  1. 跳转(要写完整路径):
<router-link to="/home/news">News</router-link>

7.3 路由的query参数

  • 当我们利用router路由发送请求时,可以携带一些参数进行传递
  1. 传递参数
<template>
  <div>
    <ul>
    <!-- 跳转并携带query参数,to的字符串写法 -->
      <li v-for="data in DataList" :key="data.id">
        <router-link :to="`/home/message/detail?id=${data.id}&title=${data.title}`">{{data.title}}</router-link>
      </li>
      <li v-for="data in DataList" :key="data.id">
        <router-link :to="{
          path:'/home/message/detail',
          query:{
            id:data.id,
            title:data.title,
          }
        }">
        {{data.title}}
        </router-link>
      </li>
    </ul>
    <hr>
    <router-view></router-view>
  </div>

</template>

<script>
export default {
    name:"Message",
    data() {
      return {
        DataList:[
          {id:"001",title:"message001"},
          {id:'002',title:"message002"},
          {id:'003',title:"message003"},
        ]
      }
    },
};
</script>
  1. 接收参数
<template>
    <ul>
        <li>消息编号:{{$route.query.id}}</li>
        <li>消息详情:{{$route.query.title}}</li>
    </ul>
</template>
$route.query.id
$route.query.title

7.4 命名路由

  1. 作用可以简化路由的跳转。
  2. 如何使用?
    2.1 给路由命名
//创建一个路由器
export default new VueRouter({
    //路由
    routes:[
        {
            path:'/about',component:About,
            
        },
        {
            path:'/home',component:Home,       
            //配置子级路由
            children:[
                {
                    //此处不要加 /
                    path:"news",
                    component:News,
                },
                {
                    path:"message",
                    component:Message,
                    children:[
                        {
                            name:"detail",//给当前路由命名
                            path:"detail",
                            component:Detail,
                        }
                    ]
                }
            ]
        },
    ]
})

2.2 简化跳转:

<!--简化前,需要写完整的路径 -->
<router-link to="/demo/test/detail">跳转</router-link>

<!--简化后,直接通过名字跳转 -->
<router-link :to="{name:'detail'}">跳转</router-link>

<!--简化写法配合传递参数 -->
<router-link 
	:to="{
		name:'detail',
		query:{
		   id:666,
            title:'你好'
		}
	}"
>跳转</router-link>

7.5 路由的params参数(RestFul风格)

  1. router/index.js配置路由,声明接收params参数 使用 :参数名来当占位符
{
	path:'/home',
	component:Home,
	children:[
		{
			path:'news',
			component:News
		},
		{
			component:Message,
			children:[
				{
					name:'xiangqing',
					path:'detail/:id/:title', //使用占位符声明接收params参数
					component:Detail
				}
			]
		}
	]
}
  1. 传递参数
<!-- 跳转并携带params参数,to的字符串写法 -->
<router-link :to="/home/message/detail/666/你好">跳转</router-link>
				
<!-- 跳转并携带params参数,to的对象写法 -->
<router-link 
	:to="{
		name:'xiangqing',
		params:{
		   id:666,
            title:'你好'
		}
	}"
>跳转</router-link>

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

7.7 路由的props配置

  • router/index.js中配置 作用:让路由组件更方便的收到参数
{
	name:'xiangqing',
	path:'detail/:id',
	component:Detail,

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

	//第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数(RestFul风格传参)通过props传给Detail组件
	// props:true
	
	//第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件
	props(route){
		return {
			id:route.query.id,
			title:route.query.title
		}
	}
}
  • 接收props
<template>
    <ul>
        <li>消息编号:{{$route.query.id}}</li>
        <li>消息详情:{{$route.query.title}}</li>
        <li>消息详情:{{id}}</li>
        <li>消息详情:{{title}}</li>
    </ul>
</template>

<script>
export default {
    name:"Detail",
    props:['id','title'],
    mounted(){
        console.log(this);
    }
}
</script>

7.8 编程式路由导航

  • 作用:不借助<router-link> 实现路由跳转,让路由跳转更加灵活
//$router的两个API
this.$router.push({
	name:'detail',
		params:{
			id:xxx,
			msg:xxx,
		}
})
//会覆盖上一次点击的记录
this.$router.replace({
	name:'detail',
		params:{
			id:xxx,
			msg:xxx,
		}
})
this.$router.forward() //前进
this.$router.back() //后退
this.$router.go() //可前进也可后退(正数代表向前走几次路径,负数代表向后退几次路径)

7.9 缓存路由组件

  • 作用:让不展示的路由组件保持挂载,不被销毁。
  • 编写:若include不写 默认router-view中所有呈现的组件都会保持挂载
<keep-alive include="组件名"> 
    <router-view></router-view>
</keep-alive>

7.10 两个新的生命周期钩子

  • 作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
  • 两个路由名字:
    1. activated路由组件被激活时触发。
    2. deactivated路由组件失活时触发。
<template>
  <ul>
    <li>news001 <input type="text"></li>
    <li>news002 <input type="text"></li>
    <li>news003 <input type="text"></li>
  </ul>
</template>

<script>
export default {
  name: "News",
  activated() {
    console.log("News组件被激活了");
  },
  deactivated(){
    console.log("News组件没有被激活");
  }
};
</script>

7.11 路由守卫

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

7.11.1 全局加守卫

//创建一个路由器
const router= new VueRouter({
    //路由
    routes:[
        {
            path:'/about',component:About,
            
        },
        {
            path:'/home',component:Home,       
            //配置子级路由
            children:[
                {
                    //此处不要加 /
                    path:"news",
                    component:News,
                },
                {
                    path:"message",
                    component:Message,
                    children:[
                        {
                            name:"detail",//给当前路由命名
                            //自定义属性必须放在meta中
                            meta:{a:true},
                            path:"detail",
                            component:Detail,
                        }
                    ]
                }
            ]
        },
    ]
})
//全局前置守卫:初始化时执行、每次路由切换前执行
router.beforeEach((to,from,next)=>{
	// 参数1:to 当前路由要去哪儿
	//参数2:from 当前路由从哪儿来
	//参数3:放行
	if(判断条件 或者 to.meta.a(自定义参数进行判断)){ //判断当前路由是否需要进行权限控制
			next() //放行
	}else{
		//不放行
	}
})

//全局后置守卫:初始化时执行、每次路由切换后执行
router.afterEach((to,from)=>{
	console.log('afterEach',to,from)
})
export default router

7.11.2 独享守卫

//创建一个路由器
const router= new VueRouter({
    //路由
    routes:[
        {
            path:'/about',component:About,
            
        },
        {
            path:'/home',component:Home,       
            //配置子级路由
            children:[
                {
                    //此处不要加 /
                    path:"news",
                    component:News,
                },
                {
                    path:"message",
                    meta:{a:true},
                    component:Message,
                    children:[
                        {
                            name:"detail",//给当前路由命名
                            path:"detail",
                            component:Detail,
                        }
                    ],
                    //独享路由守卫
                    beforeEnter(to,from,next){
                        console.log('beforeEnter',to,from)
                        if(to.meta.a){ //判断当前路由是否需要进行权限控制
                                next()
                        }
                    }
                }
            ]
        },
    ]
})

export default router

7.11.3 组件守卫

<template>
  <ul>
    <li>news001 <input type="text"></li>
    <li>news002 <input type="text"></li>
    <li>news003 <input type="text"></li>
  </ul>
</template>

<script>
export default {
  name: "News",
  activated() {
    console.log("News组件被激活了");
  },
  deactivated(){
    console.log("News组件没有被激活");
  },
  //进入守卫:通过路由规则,进入该组件时被调用
  beforeRouteEnter (to, from, next) {
  },
  //离开守卫:通过路由规则,离开该组件时被调用
  beforeRouteLeave (to, from, next) {
  }
};
</script>

7.12 路由的两种工作模式

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

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

  3. hash模式:

    1. 地址中永远带着#号,不美观 。
    2. 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
    3. 兼容性较好。
  4. history模式:

    1. 地址干净,美观 。
    2. 兼容性和hash模式相比略差。
    3. 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。

8、Element-UI组件库

官网


# 总结 提示:这里对文章进行总结: 例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。
  • 56
    点赞
  • 316
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值