Vue 基础学习总结

介绍

Vue.js 是什么

  • Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。

Vue.js 优点

image-20221111155204554

前端三要素

  • HTML + CSS + JavaScript

image-20221111155250639

CSS 预处理器

image-20221111155312763

JavaScript 框架

image-20221111155336107

UI 框架

image-20221111155357699

JavaScript 构建工具

image-20221111155415575

常用的 Vue UI 组件库

image-20221111155441602

vue-element-admin

  • 简述:vue-element-admin 是一个后台前端解决方案,它基于 vueelement-ui实现。它使用了最新的前端技术栈,内置了 i18 国际化解决方案,动态路由,权限验证,提炼了典型的业务模型,提供了丰富的功能组件,它可以帮助你快速搭建企业级中后台产品原型。相信不管你的需求是什么,本项目都能帮助到你。
  • 地址:https://panjiachen.github.io/vue-element-admin-site/zh/

MVVM 模式

image-20221111155521207

为什么使用 MVVM 模式

image-20221111155546079

第一个 Vue 程序

IDEA 安装插件

使用 IDEA 工具开发,可安装 Vue.js 插件!

在 IDEA 中安装插件后,可快速构建 vue 文件:

image-20221111155616655

PS:若安装插件后也没有出现快速构建 vue 文件的选项,可先手动创建 .vue 结尾的空文件,再次新建时,则可成功显示!

CDN 简述

  1. 智能 dns 让用户可以访问同线路最近的服务器

  2. cdn 的缓存机制可以加快访问速度,也可以缓解源站服务器压力(因为根本不会去访问源站)

  3. cdn 让大规模的用户请求架构变得简单

  4. cdn 性价比高,同带宽需求下 cdn 服务比增加带宽划算

作用:尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输得更快、更稳定。

安装

可使用多种方式进行安装,如直接下载对应类库、使用 CDN 引入、使用 NPM 安装等...

此处使用 CDN:

  • 压缩版:<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
  • 完整版:<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>

示例代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>first vue</title>
</head>
<body>
    <!--view层:模板-->
    <div id="app">
        <h2>{{message}}</h2>
    </div>

    <!--使用CDN方式导入Vue.js-->
    <script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
    <script>
        var vm = new Vue({
            el: "#app",
            //Model: 数据
            data: {
                message: "hello,vue!"
            }
        });
    </script>
</body>
</html>

相关指令

v-bind

  • 作用:与指定属性进行绑定

  • v-bind: 可简写为 :

  • 示例:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>test</title>
    </head>
    <body>
        <!--view层:模板-->
        <div id="app">
            <h2>{{message}}</h2>
            <span v-bind:title="message">
                鼠标悬浮几秒查看动态绑定的提示信息!
            </span>
            <!-- v-bind可简写 -->
            <input type='text' :value="str" />
        </div>
    
        <!--使用CDN方式导入Vue.js-->
        <script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
        <script>
            var vm = new Vue({
                el: "#app",
                //Model: 数据
                data: {
                    message: "hello,vue!",
                    str: "test str"
                }
            });
        </script>
    </body>
    </html>
    

v-if、v-else-if、v-else

  • 作用:判断

  • 示例:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>test3</title>
    
    </head>
    <body>
    
        <div id="app">
            <h1 v-if="ok">yes</h1>
            <h1 v-else>no</h1>
    
            <span v-if="type==='A'">A</span>
            <span v-else-if="type==='B'">B</span>
            <span v-else>D</span>
        </div>
    
        <!--  导入vue.js  -->
        <script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
        <script>
            var vm = new Vue({
                el: "#app",
                data: {
                    ok: true,
                    type: 'A'
                }
            });
        </script>
    
    </body>
    </html>
    

v-show

  • 作用:判断
  • 说明:从功能上讲,v-showv-if 作用是相同的,主要是他们的渲染过程有区别。

除了 v-if,还有一个可以按条件显示一个元素的指令是 v-show。其用法基本一样:

<h1 v-show="ok">Hello!</h1>

不同之处在于 v-show 会在 DOM 渲染中保留该元素;v-show 仅切换了该元素上名为 display 的 CSS 属性。

v-show 不支持在 <template> 元素上使用,也不能和 v-else 搭配使用。

v-if vs. v-show

v-if 是“真实的”按条件渲染,因为它确保了在切换时,条件区块内的事件监听器和子组件都会被销毁与重建。

v-if 也是惰性的:如果在初次渲染时条件值为 false,则不会做任何事。条件区块只有当条件首次变为 true 时才被渲染。

相比之下,v-show 简单许多,元素无论初始条件如何,始终会被渲染,只有 CSS display 属性会被切换。

总的来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要频繁切换,则使用 v-show 较好;如果在运行时绑定条件很少改变,则 v-if 会更合适。

v-for

  • 作用:循环

  • 示例:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>test4</title>
    
    </head>
    <body>
    
        <div id="app">
            <ul>编程语言
                <li v-for="item in items">
                    {{item.message}}
                </li>
            </ul>
    
            <ol>编程语言(显示下标)
                <li v-for="(item, index) in items">
                    {{item.message}} --> {{index}}
                </li>
            </ol>
        </div>
    
        <!--  导入vue.js  -->
        <script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
        <script>
            var vm = new Vue({
                el: "#app",
                data: {
                    items: [
                        {message: "java"},
                        {message: "python"},
                        {message: "go"}
                    ]
                }
            });
        </script>
    
    </body>
    </html>
    

v-on

  • 作用:事件监听

  • v-on:click 可简写为 @click

  • 示例:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>test5</title>
    
    </head>
    <body>
    
        <div id="app">
            <p>{{message}}</p>
            <button v-on:click="reverseMessage">反转消息</button>
        </div>
    
        <!--  导入vue.js  -->
        <script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
        <script>
            var vm = new Vue({
                el: "#app",
                data: { message: "Hello Vue.js!"},
                methods: {
                    reverseMessage: function () {
                        this.message = this.message.split('').reverse().join('');
                    }
                }
            });
        </script>
    
    </body>
    </html>
    

v-model

  • 作用:实现数据的双向绑定

  • 说明:使用该指令可在<input>、<textarea>、<select>等元素上创建双向数据绑定,会根据控件类型自动选取正确方法来更新元素。它负责监听用户的输入事件以更新数据,并对一些极端场景进行一些特殊处理。

  • 注意:v-model会忽略所有表单元素的 value、checked、selected 特性的初始值而总是将 Vue 实例的数据作为数据来源,所以开发者应该通过 JavaScript 在组件的 data 选项中声明初始值!

  • v-model 又称表单标签,主要作用就是实现表单标签的的双向绑定;

    它只能使用在表单输入标签,因为需要通过表单输入标签输入的内容,来改变其他地方的数据;

    v-model:value 可以简写为 v-model,需要明确它默认就是绑定的 value 属性。

  • 示例:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>test6</title>
    
    </head>
    <body>
    
        <div id="app">
    
            单行文本:
            <input type="text" v-model="message">
            {{message}}
    
            <br><br>
    
            文本域:
            <textarea v-model="texts"></textarea>
            {{texts}}
    
            <br><br>
    
            单选按钮:<br>
            性别:
            <input type="radio" name="sex" value="男" v-model="gender">男
            <input type="radio" name="sex" value="女" v-model="gender">女
            <br>
            <span>选中了【{{gender}}】</span>
    
            <br><br>
    
            下拉框:
            <select v-model="selected">
                <option value="" disabled>--请选择--</option>
                <option>A</option>
                <option>B</option>
                <option>C</option>
            </select>
            <span>value:{{selected}}</span>
    
        </div>
    
        <!--  导入vue.js  -->
        <script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
        <script>
            var vm = new Vue({
                el: "#app",
                data: {
                    selected: '',
                    message: "123",
                    texts: '',
                    gender: ''
                }
            });
        </script>
    
    </body>
    </html>
    

vue 实例

每个使用 vue 进行数据渲染的网页文档都需要创建一个 Vue 实例——ViewModel

Vue 实例的生命周期

vue 实例的生命周期:vue 实例从创建到销毁的过程

  • 创建 vue 实例:初始化 data,加载 el
  • 数据挂载:将 vue 实例 data 中数据渲染到网页 HTML 标签
  • 重新渲染:当 vue 的 data 数据发生变化,会重新渲染到 HTML 标签
  • 销毁实例

钩子函数

为便于开发者在 vue 实例生命周期不同阶段进行特定的操作,vue 在生命周期四个阶段的前后分别提供了一个函数,这个函数无须开发者调用,当 vue 实例到达生命周期的指定阶段,会自动进行相关函数的调用,这些函数称为钩子函数。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
	</head>
	<body>
		
		<div id="container">
			<label v-once>{{str}}</label><br />
			<label>{{str}}</label><br />
			<input type="text" v-model="str" />
		</div>
		
		<script type="text/javascript">
			var vm = new Vue({
				el: "#container",
				data: {
					str: "初始数据"
				},
				beforeCreate: function() {
					//1.data初始化之前执,不能操作data
					console.log("beforeCreate------->1");
				},
				created: function() {
					//2.data初始化之后执行,模板加载之前,可以修改/获取data中的值
					console.log(this.str);
					console.log("created------->2");
					//this.str = "data初始化之后执行";
				},
				beforeMount: function() {
					//3.模板加载之后,数据初始渲染(挂载)之前,可以修改/获取data中的值
					//this.str = "数据初始渲染(挂载)之前执行";
					console.log("beforeMount------->3");
				},
				mounted: function() {
					//4.数据初始渲染(挂载)之后,可以对data中的变量进行修改,但是不会影响v-once的渲染
					//this.str = "数据初始渲染(挂载)之后执行";
					console.log("mounted------->4");
				},
				beforeUpdate: function() {
					//5.数据渲染之后,当data中的数据变化触发重新渲染,渲染之前执行此函数
					// data数据被修改之后,重新渲染到html之前
					console.log("-----" + this.str);
					this.str = "数据被修改,重新被渲染到html之前";
					console.log("beforeUpdate------->5");
				},
				updated: function() {
					//6.data数据被修改之后,重新渲染到html之后
					//this.str = "数据被修改,重新渲染都html后";
					console.log("updated------->6");
				},
				beforeDestroy: function() {
					//7.实例销毁之前
					console.log("beforeDestroy------->7");
				},
				destroyed: function() {
					//8.实例销毁之后
					console.log("destroyed------->8");
				}
			});
		</script>
	</body>
</html>

计算属性

计算属性的重点突出在属性两个字上(属性是名词),首先它是个属性,其次,这个属性有计算的能力(计算是动词),这里的计算就是个函数;简单点说,他就是一个能够将计算结果缓存起来的属性(将行为转化成了静态的属性),仅此而已;也可以将其想象成缓存!

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>test9</title>
    <!--引入Vue.js-->
    <script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
</head>
<body>

    <div id="vue">
        <!--注意:一个是方法,一个是属性!-->
        <p>调用当前时间的方法:{{currentTime1()}}</p> <!--方法调用需要带括号-->
        <p>当前时间的计算属性:{{currentTime2}}</p> <!--属性调用不能带括号-->
    </div>

    <script type="text/javascript">
        var vm = new Vue({
            el: '#vue',
            data: {message: 'Hello Vue.js!'},
            // 注意:methods 和 computed 里的东西不能重名!
            methods: { //在此可定义方法,调用方法需要带()
                //currentTime1:这是一个方法!
                currentTime1: function () {
                    return Date.now();
                }
            },
            computed: { //在此可定义计算属性,调用属性不需要带()
                //currentTime2:这是一个属性,不是方法!
                currentTime2: function () {
                    this.message; //作用:通过改变该值,观察currentTime2属性值的变化
                    return Date.now();
                }
            }
        });
    </script>

</body>
</html>

测试结果:(F12 --》控制台)

vm.currentTime1()
1656988519767
vm.currentTime1()
1656988521888
vm.currentTime1()
1656988524916
结论:调用方法,每次都需要重新计算

vm.currentTime2()
Uncaught TypeError: vm.currentTime2 is not a function
    <anonymous> debugger eval code:1
debugger eval code:1:4
结论:计算属性是属性,调用时不能带括号

vm.currentTime2
1656988393581
vm.currentTime2
1656988393581
vm.currentTime2
1656988393581
结论:计算属性将不经常变化的计算结果缓存了起来,只有发生变化的时候才会重新计算

vm.message = 'new data';
"new data"
vm.currentTime2
1656988775105
vm.currentTime2
1656988775105 
结论:计算属性中的值被改变时,计算结果重新计算,并重新进行缓存

说明:如果计算属性中的值发生变化时,则缓存就会刷新,可在控制台使用vm.message = 'new data';,改变下数据的值,再次测试并观察效果!

结论:调用方法时,每次都需要重新计算,既然有计算过程,则必定会产生系统开销,如果这个结果是不经常变化的,则可以考虑将这个结果缓存起来,采用计算属性就可以很方便的做到这一点!计算属性的主要特性就是为了将不经常变化的计算结果进行缓存,以节约系统开销。

侦听器

侦听器,就是 data 中属性的监听器,当 data 中的属性值发⽣变化就会触发侦听器函数的执⾏。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
	</head>
	<body>

		<div id="container">
			<input type="text" v-model="str1" /><br />
			<input type="text" v-model="str2" /><br />
			{{str3}}
		</div>
		<script type="text/javascript">
			var vm = new Vue({
				el: "#container",
				data: {
					str1: "江苏",
					str2: "苏州",
					str3: "江苏苏州"
				},
				watch: {
					str1: function() {
						this.str3 = this.str1 + this.str2;
					},
					str2: function() {
						this.str3 = this.str1 + this.str2;
					}
				}
			});
		</script>
	</body>
</html>

类与样式绑定

我们可以使⽤ mustache 语法将 vue 中 data 的数据绑定到 HTML 标签及标签的属性,如何将 data 中的值绑定到标签的 class 及 style 属性呢?下面就是需要介绍的类与样式绑定—— class 与 style 绑定。

class 绑定

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
		<style type="text/css">
			.mystyle1 {
				width: 200px;
				height: 100px;
				background: orange;
			}

			.mystyle3 {
				width: 200px;
				height: 100px;
				background: black;
			}

			.my-style2 {
				border-radius: 10px;
			}
		</style>
	</head>
	<body>

		<div id="container">
			<!--如果b1为true就加载 mystyle1;如果b2为true,则加载my-style2-->
			<!-- 注意:如果样式名中有特殊字符如横杠,需要添加单引号 -->
			<div :class="{mystyle1:b1,'my-style2':b2}"></div>
			<!--为class属性加载多个样式名 -->
			<div :class="[chooseStyle1,chooseStyle2]"></div>
			<!--如果b3为true,则class='mystyle3'; 否则class='mystyle1'
			如果在三目运算中使用样式名则需加单引号,不加单引号则表示从data变量中获取样式名-->
			<div :class="[b3 ? 'mystyle3' : 'mystyle1']"></div>
			<div :class="[b3 ? chooseStyle3 : chooseStyle1]"></div>
		</div>
		<script type="text/javascript">
			var vm = new Vue({
				el: "#container",
				data: {
					b1: true,
					b2: true,
					b3: false,
					chooseStyle1: "mystyle1",
					chooseStyle2: "my-style2",
					chooseStyle3: "mystyle3"
				}
			});
		</script>
	</body>
</html>

style 绑定

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
	</head>
	<body>

		<div id="container">
			
			<!--当使用v-bind绑定内联样式时:
			1. 使用{}定义style样式,才能获取data中的值,{}要遵循JSON格式
			2. {}中不再使用style样式属性名“font-size”,要使用对应的js属性名
			border-style-width ---》 borderStyleWidth(横杠连接变驼峰形式)
			-->
			<div v-bind:style="{color: colorname,fontSize: fontsize+'px'}">vue之style绑定</div>
		
			<!--我们可以直接为style属性绑定一个data中定义好的内联样式的字符串-->
			<div v-bind:style="mystyle1">vue之style绑定</div>
			
			<!--我们可以直接为style属性绑定一个data中定义好的内联样式的对象-->
			<div v-bind:style="mystyle2">vue之style绑定</div>
			
			<!--可以在同一个style上通过数组引用多个内联样式的对象-->
			<div v-bind:style="[mystyle2,mystyle3]">vue之style绑定</div>
			
		</div>
		<script type="text/javascript">
			var vm = new Vue({
				el: "#container",
				data: {
					colorname: "green",
					fontsize: 30,
					mystyle1: "color:orange;font-size:45px",
					mystyle2: {
						color: "blue",
						fontSize: "40px"
					},
					mystyle3: {
						textShadow: "orange 3px 3px 5px"
					}
				}
			});
		</script>
	</body>
</html>

事件处理

事件绑定传值的三种方式

在使⽤ vue 进⾏数据渲染时,如果使⽤原⽣ js 事件绑定(例如 onclick ),则需要获取 vue 实例中的数据,并传参,而且需要通过拼接来完成。

vue 提供了 v-on 指令⽤于绑定各种事件(v-on:click),简化了从 vue 取值的过程,但是触发的⽅法需要定义在 vue 实例的 methods 中,如下:

<button type="button" v-on:click="doDelete(s.stuNum,s.stuName)">删除</button>

<script type="text/javascript">
	var vm = new Vue({
     el:"#container",
     data:{},
     methods:{
         doDelete:function(snum,sname){
         	console.log("----delete:"+snum+" "+sname)
         }
     }
 });
</script>

PS:v-on:click 可以缩写为 @click

1. 使用 JS 函数传值(不建议)

<button type="button" v-on:click="doDelete(s.stuNum,s.stuName)">删除</button>

<script>
    var vm = new Vue({
        el:"#container",
        data:{};
        methods:{
            doDelete:function(snum,sname){
            	console.log("----delete:"+snum+" "+sname)
            }
        }
    });
</script>

2. 使⽤ dataset 对象传值(推荐)

说明:

推荐直接调用方法;

需要传递的参数使用 :data-xxx="数据" 格式进行传递;

参数获取通过方法定义时添加的 event 参数中获取;

<button type="button" @click="doUpdate" :data-snum="s.stuNum" :data-sname="s.stuName" :data-simg="s.stuImg">修改</button>

<script>
    var vm = new Vue({
        el:"#container",
        data:{};
        methods:{
            doUpdate:function(event){
                //如果v-on绑定的js函数没有参数,调⽤的时候可以省略(),同时可以给
                //js函数⼀个event参数(事件对象)
                // 1. event 表示触发当前函数的事件
                // 2. event.srcElement 表示发⽣事件的元素---修改按钮
                // 3. event.srcElement.dataset 表示按钮上绑定的数据集(data-开头的属性)
                console.log("-----update")
                var stu = event.srcElement.dataset;
            }
        }
    });
</script>

3. 混合使⽤传值

混合传值,方法参数中事件参数 event 需要注意,必须使用 $event

<button type="button" v-on:click="doDelete(s.stuNum,s.stuName,$event)":data-simg="s.stuImg">删除</button>

<script>
    var vm = new Vue({
        el:"#container",
        data:{};
        methods:{
            doDelete:function(snum,sname,event){
                console.log("----delete:"+snum+" "+sname)
                console.log(event.srcElement.dataset);
            }
        }
    });
</script>

事件修饰符

当使⽤ v-on 进⾏事件绑定的时候,可以添加特定后缀,设置事件触发的特性。

下面介绍常用的几个事件修饰符,更多参考官网:点击查看

  • .prevent:消除元素的默认事件
  • .stop:阻⽌事件冒泡(阻⽌⼦标签向上冒泡)
  • .self:设置只能⾃⼰触发事件(⼦标签不能触发)
  • .once:限定事件只触发⼀次

使用语法示例:

<button type="submit" @click.prevent="事件函数">测试</button> 

.prevent

作用:消除元素的默认事件

示例:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
	</head>
	<body>

		<div id="container">
			<form action="https://www.baidu.com">
				<button type="submit" class="btn btn-success btn-xs" @click.prevent="test">测试</button>
			</form>
		</div>
		
		<script type="text/javascript">
			var vm = new Vue({
				el: "#container",
				data: {},
				methods: {
					test: function() {
						console.log("---test");
					}
				}
			});
		</script>

	</body>
</html>

.stop.self

作用:

  • .stop:阻⽌事件冒泡(阻⽌⼦标签向上冒泡)
  • .self:设置只能⾃⼰触发事件(⼦标签不能触发)

示例:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
	</head>
	<body>

		<div id="container">
			<div style="width: 200px; height: 200px; background: red;" @click.self="method1">
				<div style="width: 150px; height: 150px; background: green;" @click="method2">
					<button type="button" @click.stop="method3">测试</button>
				</div>
			</div>
		</div>
		
		<script type="text/javascript">
			var vm = new Vue({
				el: "#container",
				data: {},
				methods: {
					method1: function() {
						alert("1");
					},
					method2: function() {
						alert("2");
					},
					method3: function() {
						alert("3");
					},
				}
			});
		</script>

	</body>
</html>

.once

作用:限定事件只触发⼀次

示例:略

按键修饰符

按键修饰符就是针对键盘事件的修饰符,限定哪个按键会触发事件。

示例说明:对于下列文本框,输入文字后,按下回车键并弹起时,会触发事件,调用 method4 方法。

<input type="text" @keyup.enter="method4"/> 

针对键盘操作的动作,除了 @keyup 还有:@keydown@keypress

Vue 为一些常用的按键提供了别名:

  • .enter
  • .tab
  • .delete (捕获“Delete”和“Backspace”两个按键)
  • .esc
  • .space
  • .up
  • .down
  • .left
  • .right

除了以上 vue 提供按钮的别名之外,我们还可以为按键⾃定义别名。

点击查看键盘码

示例:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
	</head>
	<body>

		<div id="container">
			<!--2.使用定义的按键别名aaa作为修饰符-->
			<input type="text" @keyup.aaa="method4" />
		</div>
		
		<script type="text/javascript">
			//1.为按键J定于别名为 aaa
			Vue.config.keyCodes.aaa = 74;
			var vm = new Vue({
				el: "#container",
				data: {},
				methods: {
					method4: function() {
						alert("4");
					}
				}
			});
		</script>

	</body>
</html>

系统修饰符

组合键

可使用以下系统按键修饰符来触发鼠标或键盘事件监听器,只有当按键被按下时才会触发:

  • .ctrl
  • .alt
  • .shift
  • .meta:windows 键

示例:Ctrl + J 触发事件

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
	</head>
	<body>

		<div id="container">
			<input type="text" @keyup.ctrl.j="method4" />
		</div>

		<script type="text/javascript">
			Vue.config.keyCodes.j = 74;
			var vm = new Vue({
				el: "#container",
				data: {},
				methods: {
					method4: function() {
						alert("4");
					}
				}
			});
		</script>

	</body>
</html>

表单输入绑定

表单输⼊绑定,即双向绑定,就是能够将 vue 实例的 data 数据渲染到表单输⼊视图(input\textarea\select 等),也能够将输⼊视图的数据同步更新到 vue 实例的 data 中。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
	</head>
	<body>

		<div id="container">
			
			<!--文本输入框、密码输入框-->
			<input type="text" v-model="text" /><br />
			<input type="password" v-model="pwd" /><br />
			
			<!--单选按钮-->
			<input type="radio" v-model="opt1" value="A" />A 3
			<input type="radio" v-model="opt1" value="B" />B 4
			<input type="radio" v-model="opt1" value="C" />C 5
			<input type="radio" v-model="opt1" value="D" />D 6 <br />
			
			<!--复选框,绑定的是一个数组-->
			<input type="checkbox" v-model="opt2" value="篮球" />篮球 <br />
			<input type="checkbox" v-model="opt2" value="足球" />足球 <br />
			<input type="checkbox" v-model="opt2" value="羽毛球" />羽毛球 <br />
			<input type="checkbox" v-model="opt2" value="乒乓球" />乒乓球 <br />
			
			<!--下拉菜单select:绑定一个字符串-->
			<select v-model="city">
				<option value="BJ">北京</option>
				<option value="SH">上海</option>
				<option value="GZ">广州</option>
				<option value="SZ">深圳</option>
			</select>
			<br />
			
			<!--下拉菜单select:如果有multiple表示可多选,需要绑定一个数组-->
			<select v-model="cities" multiple>
				<option value="BJ">北京</option>
				<option value="SH">上海</option>
				<option value="GZ">广州</option>
				<option value="SZ">深圳</option>
			</select>
			<br />
			
			<button type="button" @click="test">测试</button>
			
		</div>
		<script type="text/javascript">
			var vm = new Vue({
				el: "#container",
				data: {
					text: "aaa",
					pwd: "111111",
					opt1: "C",
					opt2: ["篮球", "羽毛球"],
					city: "SZ",
					cities: ["BJ", "SZ"]
				},
				methods: {
					test: function() {
						alert(vm.cities);
					}
				}
			});
		</script>

	</body>
</html>

组件化应用构建

组件系统是 Vue 的另一个重要概念,因为它是一种抽象,允许我们使用小型、独立和通常可复用的组件构建大型应用。仔细想想,几乎任意类型的应用界面都可以抽象为一个组件树:

image-20220711072248538

示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>test6</title>

</head>
<body>

    <div id="app">
        <ol>
            <!--构建一个组件模板:创建一个 todo-item 组件的实例,使用自定义的Vue组件,遍历数据,将数据传递给绑定的指定属性-->
            <todo-item v-for="item in todoList" v-bind:todo="item"></todo-item>
        </ol>
    </div>

    <!--  导入vue.js  -->
    <script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
    <script>

        //注册组件:定义名为 todo-item 的新组件
        Vue.component("todo-item", {
            props: ['todo'],
            template: '<li>{{todo.text}}</li>'
        });

        var vm = new Vue({
            el: "#app",
            data: {
                todoList: [
                    {id: 0, text: "学英语"},
                    {id: 1, text: "学技术"},
                    {id: 2, text: "学做饭"}
                ]
            }
        });
    </script>

</body>
</html>

组件

组件介绍及示例

组件,就是将通⽤的 HTML 模块进⾏封装——可复⽤

组件注册

将通⽤的 HTML 模块封装注册到 vue 中

Vue.component("header-bar",{
});

组件引用

  • 定义组件需要依赖 vue.js,在引⽤⾃定义组件的 js ⽂件之前要先引⽤ vue.js
  • 组件的引⽤必须在 vue 实例 el 指定的容器中
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>

		<div id="container">
			<header-bar></header-bar>
		</div>
		
		<script type="text/javascript" src="js/vue.js"></script>
		<script type="text/javascript" src="js/my-components.js"></script>
		<script type="text/javascript">
			var vm = new Vue({
				el: "#container",
			});
		</script>

	</body>
</html>

组件注册

自定义组件的结构

  • data 定义组件的模板渲染的数据
  • template 组件的 HTML 模块(HTML标签\css样式)
  • methods 定义组件中的标签事件绑定的 JS 函数
Vue.component("header-bar", {
	data: function() {
		//组件中的data是通过函数返回的对象
		return {
			title: "Java电商平台"
		};
	},
	template: `<div style="width: 100%; height: 80px; background: lightyellow;">
			<table width="100%">
				<tr>
					<td width="200" align="right" valign="middle">
						<img src="img/logo.png" height="80">
					</td>
					<td>
						<label style="color: deepskyblue;font-size:32px; font-family: 华文行楷; margin-left: 30px;">
							{{title}}
						</label>
					</td>
					<td>
						<button @click="test">组件中的按钮</button>
					</td>
				</tr>
			</table>
		</div>`,
	methods: {
		test: function() {
			alert("组件中定义的函数");
		}
	}
});

组件的封装

  • 将模版中的 css 样式提出取来,单独定义到 css ⽂件存储在 css ⽬录
  • 将模版中的图⽚存在 img ⽬录
  • 将定义组件的 js ⽂件和 vue 的⽂件存放到 js ⽬录

image-20221112195116442

组件的复用

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title></title>
		<link rel="stylesheet" href="css/my-components.css" />
	</head>
	<body>
		
		<div id="container">
			<header-bar></header-bar>
		</div>
		
		<script type="text/javascript" src="js/vue.js"></script>
		<script type="text/javascript" src="js/my-components.js"></script>
		<script type="text/javascript">
			var vm = new Vue({
				el: "#container"
			});
		</script>
	</body>
</html>

组件通信

vue 实例本身就是⼀个组件(模板就是 el 指定容器,data 就是组件数据,methods 就是组件的事件函数)

在 vue 实例指定的 el 容器中引⽤的组件称为⼦组件 ,当前 vue 实例就是⽗组件

父传子

vue 实例引⽤组件的时候,传递数据到引⽤的组件中

image-20221112195558292

子传父

通过⼦组件的按钮“调⽤”⽗组件的函数,通过函数传值

image-20221112195709788

组件插槽

当我们⾃定义 vue 组件时,允许组件中的部分内容在调⽤组件时进⾏定义——插槽

插槽的使用

在⾃定义组件时通过 slot 标签在组件的模版中定义插槽

Vue.component("header-bar", {
	data: function() {
		//组件中的data是通过函数返回的对象
		return {
			str2: "子组件中的数据"
		};
	},
	template: '<div class="divStyle">
			<table class="tableStyle">
				<tr>
					<td width="200" align="right" valign="middle">
						<img src="img/logo.png" class="logoImg">
					</td>
					<td>
						<label class="titleStyle">
							{{title}}
						</label>
					</td>
					<td>
						<slot></slot>
					</td>
					<td>
						<button @click="childMethod">子组件中的按钮</button>
					</td>
				</tr>
			</table>
		</div>',
	props: ["title"],
	methods: {
		childMethod: function() {
			this.$emit("my-event", this.str2);
		}
	}
});

在⽗组件中调⽤此组件时,指定插槽填充的模版

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<link rel="stylesheet" href="css/bootstrap.css" />
		<link rel="stylesheet" href="css/my-components.css" />
		<script type="text/javascript" src="js/jquery-3.4.1.min.js"></script>
		<script type="text/javascript" src="js/bootstrap.js"></script>
		<script type="text/javascript" src="js/vue.js"></script>
	</head>
	<body>
		
		<div id="container">
			<header-bar :title="sss">
				<!--组件标签包含的HTML默认为填充到插槽的模版-->
				<input /><button>搜索</button>
			</header-bar>
		</div>
		
		<script type="text/javascript" src="js/my-components.js"></script>
		<script type="text/javascript">
			var vm = new Vue({
				el: "#container",
				data: {
					sss: "自定义标题"
				}
			});
		</script>
	</body>
</html>

具名插槽

当组件中的插槽数量 > 1 时,需要给组件中的 slot 标签添加 name 属性指定插槽的名字

定义组件

Vue.component("page-frame", {
	template: '<div>
			<div id="header" style="width:100%;
		height:100px;background:pink">
				<slot name="s1"></slot>
			</div>
			<div style="width:100%; height:580px">
				<slot name="s2"></slot>
			</div>
			<div id="footer" style="width:100%;
		height:40px;background:lightgray">{{cr}}</div>
		</div>',
	props: ["title", "cr"]
});

引用组件

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>

		<div id="container">
			<page-frame title="标题" cr="vue学习">
				
				<!--定义一个模版,填充到组件的name=s1的 插槽-->
				<template slot="s1">
					<input type="text" placeholder="歌曲名、歌手" />
					<button type="button" @click="doSearch">搜索</button>
				</template>
				
				<!--定义一个模版,填充到组件的name=s2的 插槽-->
				<template slot="s2">
					<table class="table table-bordered table-condensed">
						<tr>
							<th>序号</th>
							<th>歌曲ID</th>
							<th>歌曲名</th>
							<th>歌手</th>
							<th>专辑</th>
							<th>时长</th>
							<th>操作</th>
						</tr>
					</table>
				</template>
				
			</page-frame>
		</div>
	</body>
</html>

插槽作用域

定义组件时,将组件中的数据绑定到 slot 标签

Vue.component("page-frame", {
	template: '<div>
			<div id="header" style="width:100%;height:100px;background:pink">
				<slot name="s1"></slot>
			</div>
			<div style="width:100%; height:580px">
				<slot name="s2" v-bind:musics="songs"></slot>
			</div>
			<div id="footer" style="width:100%;height:40px;background:lightgray">{{cr}}</div>
		</div>',
	props: ["title", "cr"],
	data: function() {
		return {
			songs: [{}, {}]
		};
	}
});

引⽤组件时,在填充插槽的模版上使⽤ slot-scope 属性获取插槽绑定的值

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
	</head>
	<body>

		<div id="container">
			<page-frame title="标题" cr="vue学习">
				
				<template slot="s1">
					<input type="text" placeholder="歌曲名、歌手" />
					<button type="button" @click="doSearch">搜索</button>
				</template>
				
				<!--在使用模版填充组件插槽时,可以使用slot-scope属性获取组件插槽绑定的数据的集合 -->
				<template slot="s2" slot-scope="res">
					<table class="table table-bordered table-condensed">
						<tr>
							<th>序号</th>
							<th>歌曲ID</th>
							<th>歌曲名</th>
							<th>歌手</th>
							<th>专辑</th>
							<th>时长</th>
							<th>操作</th>
						</tr>
						<tr v-for="song,index in res.musics">
							<!--遍历省略-->
						</tr>
					</table>
				</template>
				
			</page-frame>
		</div>

	</body>
</html>

插槽 slot 补充

内容分发:在Vue.js中我们使用<slot>元素作为承载分发内容的出口,作者称其为插槽,可应用在组合组件的场景中。

测试:如准备一个待办事项组件(to-do),该组件由待办标题(to-do-title)和待办事项(to-do-items)组成,但这三个组件又相互独立,该如何操作?

代码示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>插槽slot</title>
    <!--引入Vue.js-->
    <script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
</head>
<body>

    <div id="app10">
        <to-do>
            <to-do-title slot="to-do-title" v-bind:title="toDoTitle"></to-do-title>
            <to-do-items slot="to-do-items" v-for="item in toDoList" v-bind:item="item"></to-do-items>
        </to-do>
    </div>

    <script type="text/javascript">

        Vue.component("to-do", {
            // template: '<div>' +
            //             '<slot></slot>' +
            //             '<ul>' +
            //                 '<slot></slot>' +
            //             '</ul>' +
            //           '</div>'
            // 使用折行转义字符,使多行html模板更简洁
            template: '<div>\
                        <slot name="to-do-title"></slot>\
                        <ul>\
                            <slot name="to-do-items"></slot>\
                        </ul>\
                      </div>'
        });
        Vue.component("to-do-title", {
            props: ['title'],
            template: '<p>{{title}}</p>'
        });
        Vue.component("to-do-items", {
            props: ['item'],
            template: '<li>{{item}}</li>'
        });

        var vm = new Vue({
            el: "#app10",
            data: {
                toDoTitle: "待办事项",
                toDoList: ['起床', '洗漱', '工作']
            }
        });
    </script>

</body>
</html>

Vue 中使用 Element-UI 组件

element-ui 官网链接:https://element.eleme.cn/#/zh-CN/component/table

vue2.x 链接:https://v2.cn.vuejs.org/v2/guide/installation.html

下面是在 Vue 中使用 Element-UI 表单组件示例:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>vue + element-ui 组件使用示例</title>
		
		<!-- 第一步:引入样式和组件库 -->		
		<!-- 引入element-ui的样式 -->
		<link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css">
		<!-- 引入vue2.0的组件库,element-ui的组件库是基于vue的,需要提前引入 -->
		<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10"></script>
		<!-- 引入element-ui的组件库 -->
		<script src="https://unpkg.com/element-ui/lib/index.js"></script>

	</head>
	<body>

		<div id="container">
			
			<!-- 第二步:在vue容器中复制进指定element-ui组件的模板代码 -->
			<template>
				<el-table :data="tableData" border style="width: 100%">
					<el-table-column prop="date" label="日期" width="180">
					</el-table-column>
					<el-table-column prop="name" label="姓名" width="180">
					</el-table-column>
					<el-table-column prop="address" label="地址">
					</el-table-column>
				</el-table>
			</template>

		</div>

		<script type="text/javascript">
			var vm = new Vue({
				el: "#container",
				// 第三步:引入示例数据
				data: {
					tableData: [{
						date: '2016-05-02',
						name: '王小虎',
						address: '上海市普陀区金沙江路 1518 弄'
					}, {
						date: '2016-05-04',
						name: '王小虎',
						address: '上海市普陀区金沙江路 1517 弄'
					}, {
						date: '2016-05-01',
						name: '王小虎',
						address: '上海市普陀区金沙江路 1519 弄'
					}, {
						date: '2016-05-03',
						name: '王小虎',
						address: '上海市普陀区金沙江路 1516 弄'
					}]
				}
			});
		</script>

	</body>
</html>

自定义事件内容分发

  • 通过组件无法直接操作 Vue 对象的数据,可以通过组件调前端,通过前端操作 Vue 对象的数据,实现组件操作 Vue 对象数据。
  • 核心:自定义事件this.$emit('myEvent')
  • 例如:在组件中添加一个删除按钮,要求点击删除,将指定列表数据删除

示例:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>插槽slot之自定义事件分发</title>
    <!--引入Vue.js-->
    <script src="https://cdn.bootcss.com/vue/2.5.16/vue.min.js"></script>
</head>
<body>

    <div id="app10">
        <to-do>
            <to-do-title slot="to-do-title" v-bind:title="toDoTitle"></to-do-title>
            <to-do-items slot="to-do-items"
                         v-for="(luis, index) in toDoList"
                         v-bind:item="luis"
                         v-bind:index="index"
                         v-on:rm="removeItem(index)"></to-do-items><!--绑定自定义事件-->
        </to-do>
    </div>

    <script type="text/javascript">

        Vue.component("to-do", {
            // template: '<div>' +
            //             '<slot></slot>' +
            //             '<ul>' +
            //                 '<slot></slot>' +
            //             '</ul>' +
            //           '</div>'
            // 使用折行转义字符,使多行html模板更简洁
            template: '<div>\
                        <slot name="to-do-title"></slot>\
                        <ul>\
                            <slot name="to-do-items"></slot>\
                        </ul>\
                      </div>'
        });
        Vue.component("to-do-title", {
            props: ['title'],
            template: '<p>{{title}}</p>'
        });
        Vue.component("to-do-items", {
            props: ['item', 'index'],
            // template: '<li>{{item}} <button @click="remove">删除</button></li>',
            template: '<li>{{index}}---{{item}} <button v-on:click="remove">删除</button></li>',
            methods: {
                remove: function (index) {
                    //自定义事件分发
                    //不能直接通过组件控制Vue对象中的方法;可通过组件调前端,再通过前端来控制Vue对象
                    this.$emit("rm", index);
                }
            }

        });

        var vm = new Vue({
            el: "#app10",
            data: {
                toDoTitle: "待办事项",
                toDoList: ['起床', '洗漱', '工作']
            },
            methods: {
                removeItem: function (index) {
                    //删除指定数组下标处指定个数的元素
                    this.toDoList.splice(index, 1);
                }
            }
        });
    </script>

</body>
</html>

Vue 入门小结

核心:数据驱动,组件化

优点:借鉴了 AngularJS 的模块化开发和 React 的虚拟 Dom;虚拟 Dom 就是把 Dom 的操作放到内存中执行。

常用属性:

  • v-if
  • v-else-if
  • v-else
  • v-for
  • v-on绑定事件,简写@
  • v-model数据双向绑定
  • v-bind给组件绑定参数,简写:

组件化:

  • 组合组件 slot 插槽
  • 组件内部绑定事件需要使用到this.$emit("事件名", 参数);
  • 计算属性的特色,缓存计算数据

遵循 SoC 关注度分离原则,Vue 是纯粹的视图框架,并不包含如 Ajax 之类的通信功能,为了解决通信问题,我们需要使用 Axios 框架做异步通信。

说明:

  • 以上属于 Vue 的基础语法,包括示例都是为了演示语法的使用,实际开发不会采用此方式!
  • Vue 的开发都是要基于 NodeJS,实际开发都是采用的 vue-cli 脚手架,vue-router 实现路由(跳转),vuex 实现状态管理(会话管理),Vue UI 界面,一般使用 ElementUI(饿了么出品),或使用 ICE(阿里巴巴出品)来快速搭建前端项目!

Axios 异步通信

vue 可以实现数据的渲染,但是如何获取数据呢?

vue 本身不具备通信能力,通常结合 axios(一个专注于异步通信的 js 框架)来使用。

如果使用 IDEA 写代码需要保证设置中 JavaScript 规范为 ECS 6+,如下:

image-20221111093532258

什么是 Axios

  • Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中,其主要作用就是实现 AJAX 异步通信。

为什么使用 Axios

  • 由于Vue.js是一个视图层框架,并且其开发者(尤雨溪)严格遵守 SOC(关注度分离原则),所以Vue.js并不包含 AJAX 的通信功能,为了解决通信问题,作者单独开发了一个名为 vue-resource 的插件,不过在进入 2.0 版本以后,其停止了对该插件的维护并推荐了 Axios 框架。建议少用 jQuery,因为它操作 DOM 太频繁。
  • 对于异步通信:
    • 原生 ajax:实现步骤复杂
    • jQuery:笨重
    • Axios:简洁高效,对 RESTful 支持良好

安装

可使用 npm、bower、cdn 等,此处选择使用 cdn:

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

使用案例

异步请求

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<!-- vue -->
		<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10"></script>
		<!-- axios -->
		<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

	</head>
	<body>
		
		<div id="container">
			<button type="button" @click="test1">测试1</button>
		</div>
		
		<script type="text/javascript">
			var vm = new Vue({
				el: "#container",
				methods: {
					test1: function() {
						//发送异步请求
						// axios.get(url).then(fn);
						// axios.get(url,{}).then(fn)
						axios.get("http://localhost:9999/music/detail", {
								params: {
									id: "25640392"
								}
							})
							.then(function(res) {
								console.log(res);
							});
					}
				}
			});
		</script>
	</body>
</html>

Axios 提供了多种异步请求方法,实现对 RESTful 风格的支持。

get 请求

  • 无参传递:axios.get(url).then(fn);

  • 有参传递:axios.get(url,{}).then(fn)

    //使⽤axios的get请求传递参数,需要将参数设置在params下
    axios.get("http://localhost:9999/music/detail",{
        params:{
        	id:"25640392"
        }
    })
        .then(function(res){
        console.log(res);
    });
    

post 请求

  • axios.post(url,{}).then(fn)

    axios.post("http://localhost:9999/music/search",{s:"阿***"})
        .then(function(res){
        console.log(res);
    });
    

自定义请求:自定义请求方式、请求参数、请求头、请求体(post)

axios({
    url:"http://localhost:9999/music/search",
    method:"post",
    params:{
        //设置请求⾏传值
        s:"成都",
        limit:15
    },
    headers:{
        //设置请求头
    },
    data:{
        //设置请求体(post/put)
    }
}).then(function(res){
    console.log(res)
});

其他

  • delete
  • put
  • option

并发请求

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<!-- vue -->
		<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10"></script>
		<!-- axios -->
		<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

	</head>
	<body>

		<div id="container">
			<button type="button" @click="test1">测试1</button>
		</div>
		
		<script type="text/javascript">
			var vm = new Vue({
				el: "#container",
				methods: {
					test1: function() {
						//发送异步请求
						axios.all([listMusics(), getMusicDetail()]).then(axios.spread(function(r1, r2) {
							// 两个请求现在都执行完成
							console.log(r1);
							console.log(r2);
						}));
					}
				}
			});

			function listMusics() {
				return axios.get('http://localhost:9999/music/search?s=成都');
			}

			function getMusicDetail() {
				return axios.get('http://localhost:9999/music/detail?id=25640392');
			}
				
		</script>
	</body>
</html>

箭头函数

箭头函数是一种语法,需要明白其使用格式。

先要注意:axios 的回调函数的参数 res,并不是接口返回的数据,而是表示一个响应对象;res.data 才表示接口响应回来的数据。

此知识点学习目标:需要明白这种用法的意义,还有要看得懂!

案例需求

需求:将接口返回的数据设置到 vue 中

方式一

直接通过 vue 对象设置(简单名了,但用的人少)

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<!-- vue -->
		<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10"></script>
		<!-- axios -->
		<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

	</head>
	<body>

		<div id="container">
			<button type="button" @click="test1">测试1</button>
		</div>

		<script type="text/javascript">
			var vm = new Vue({
				el: "#container",
				data: {
					song: {}
				},
				methods: {
					test1: function() {
						//发送异步请求
						axios.get("http://localhost:9999/music/detail", {
							params: {
								id = 25640392
							}
						})
						.then(function(res) {
							// res并不是接口返回的数据,而是表示一个响应对象;res.data才表示接口响应的数据
							if (res.data.code == 200) {
								// 直接通过vm实例设置
								vm.song = res.data.songs[0];
							}
						});
					}
				}
			});
		</script>

	</body>
</html>
方式二

通过定义属性,在指定位置使用(用的多)

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<!-- vue -->
		<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10"></script>
		<!-- axios -->
		<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

	</head>
	<body>

		<div id="container">
			<button type="button" @click="test1">测试1</button>
		</div>

		<script type="text/javascript">
			var vm = new Vue({
				el: "#container",
				data: {
					song: {}
				},
				methods: {
					test1: function() {
						
						// 定义一个变量,将当前vue实例赋值给它
						var _this = this;
						
						//发送异步请求
						axios.get("http://localhost:9999/music/detail", {
							params: {
								id = 25640392
							}
						})
						.then(function(res) {
							// res并不是接口返回的数据,而是表示一个响应对象;res.data才表示接口响应的数据
							if (res.data.code == 200) {
								// 如果这里直接写this,则代表的是回调函数的对象,不是vm对象!
								// this.song = res.data.songs[0];
								// 通过外面定义的变量设置数据
								_this.song = res.data.songs[0];
							}
						});
					}
				}
			});
		</script>

	</body>
</html>
方式三

使用箭头函数(需要看得懂)

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title></title>
		<!-- vue -->
		<script src="https://cdn.jsdelivr.net/npm/vue@2.7.10"></script>
		<!-- axios -->
		<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

	</head>
	<body>

		<div id="container">
			<button type="button" @click="test1">测试1</button>
		</div>

		<script type="text/javascript">
			var vm = new Vue({
				el: "#container",
				data: {
					song: {}
				},
				methods: {
					test1: function() {
						//发送异步请求
						axios.get("http://localhost:9999/music/detail", {
								params: {
									id = "25640392"
								}
							})
							.then((res) => {
								// res并不是接口返回的数据,而是表示一个响应对象;res.data才表示接口响应的数据
								if (res.data.code == 200) {
									this.song = res.data.songs[0];
								}
							});
					}
				}
			});
		</script>

	</body>
</html>

router 路由(新)

router 是由 vue 官方提供的,用于组件跳转的插件。

官方文档:https://router.vuejs.org/zh/introduction.html

1. 路由插件的引用

离线模式示例:(复制并转到 CDN 中地址,保存就是对应的 js 库文件)

<script type="text/javascript" src="js/vue.js" ></script>
<script type="text/javascript" src="js/vue-router.js"></script>

在线 CDN:(vue-router 需要依赖 vue 才能使用)【注意:使用高版本可能会报错】

<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
<!-- 低版本,也可以使用 -->
<!-- <script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script> -->
<script src="https://cdn.jsdelivr.net/npm/vue-router@3.5.1/dist/vue-router.min.js"></script>

2. 路由使用案例

步骤简述:

  1. 引入 vue 和 vue-router 的 js 文件
  2. 定义 vue 实例和对应的基础 vue 容器标签
  3. 在容器中使用路由专用链接和路由页面展示标签
  4. 在 js 中定义路由链接跳转的模板
  5. 在 js 中定义路由跳转的规则(在创建的 VueRouter 中定义跳转规则)
  6. vue 实例中配置路由对象,即引用路由

代码示例:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>01</title>
		<style type="text/css">
			body {
				padding: 0px;
				margin: 0px;
			}

			ul {
				list-style: none;
			}

			ul li {
				display: inline;
				float: left;
				margin-left: 15px;
				margin- bottom: 15px;
			}

			ul li a {
				text-decoration: none;
				color: white;
				font-size: 18px;
				font-weight: bold;
			}

			ul li a:hover {
				color: yellow;
			}
		</style>
		
		<!-- 引入vue -->
		<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
		<!-- 引入vue-router -->
		<!-- 低版本,也可以使用 -->
		<!-- <script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script> -->
		<script src="https://cdn.jsdelivr.net/npm/vue-router@3.5.1/dist/vue-router.min.js"></script>


	</head>
	<body>
		<div id="container">
			<div style="width: 100%; height: 70px; background: #00BFFF;">
				<table>
					<tr>
						<td>
							<p>logo</p>
						</td>
						<td>
							<ul>
								<!-- 使用路由专用链接 -->
								<li>
									<router-link to="/a">首页</router-link>
								</li>
								<li>
									<router-link to="/b">Java</router-link>
								</li>
								<li>
									<router-link to="/c">HTML5</router-link>
								</li>
								<li>
									<router-link to="/d">Python</router-link>
								</li>
							</ul>
						</td>
					</tr>
				</table>
			</div>
			<div style="width: 100%; height: 680px; background:lemonchiffon;">
				<!-- 在此处展示路由跳转的页面 -->
				<router-view></router-view>
			</div>
		</div>
		<script type="text/javascript">
			
			// vue的路由旨在为单页面应用开发提供便捷
			
			//1.定义链接跳转的模板(组件)
			//使用const声明;var和const声明的区别是const一旦赋值不可改变
			const t1 = {
				template: `<p>index</p>`
			};
			const t2 = {
				template: `<p>Java</p>`
			};
			const t3 = {
				template: `<p>HTML5</p>`
			};
			const t4 = {
				template: `<p>PYTHON</p>`
			};
			
			//2.定义路由规则
			const myrouter = new VueRouter({
				routes: [{
						path: "/a",
						component: t1
					},
					{
						path: "/b",
						component: t2
					},
					{
						path: "/c",
						component: t3
					},
					{
						path: "/d",
						component: t4
					}
				]
			});
			
			// 3.vue实例中配置路由对象,即引用路由
			var vm = new Vue({
				el: "#container",
				router: myrouter
			});
		</script>
	</body>
</html>

3. 动态路由匹配

通配符

通过使用通配符 * 实现,* 可以匹配任意路径。

例如:

  • /user-* 匹配所有以 user- 开头的任意路径
  • /* 匹配所有路径

注意:如果使用通配符定义路径,需要注意路由声明的顺序!

const myrouter = new VueRouter({
    routes:[
        {path:"/user-*",component:xxx},
        {path:"/*",component:xxx}
    ]
});

路由参数

  • /a/:参数名 可以匹配/a/ 开头的路径
  • {{$route.params.参数名}} 获取数据
<div id="container">
    <li><router-link to="/a/101">⾸⻚</router-link></li>
    <router-view></router-view>
</div>

<script type="text/javascript">
    
    const t1 = {template:`<p>index:{{$route.params.id}}</p>`};
    
    const myrouter = new VueRouter({
        routes:[
        {path:"/a/:id",component:t1}
        ]
    });
    
    var vm = new Vue({
        el:"#container",
        router:myrouter
    });
</script>

优先级

如果一个路径匹配了多个路由,则按照路由的配置顺序:路由定义的越早,优先级别就越高。

4. 嵌套路由

在一级路由的组件中显示二级路由

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>嵌套路由</title>

		<!-- 引入vue -->
		<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
		<!-- 引入vue-router -->
		<!-- 低版本,也可以使用 -->
		<!-- <script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script> -->
		<script src="https://cdn.jsdelivr.net/npm/vue-router@3.5.1/dist/vue-router.min.js"></script>

	</head>
	<body>
		<div id="container">
			
			<router-link to="/a">首页</router-link>
			<router-link to="/a/c2">首页-c2</router-link>
			<router-link to="/a/c3">首页-c3</router-link>
			
			<router-view></router-view>
			
		</div>

		<script type="text/javascript">
			
			const t1 = {
				template: `<div style="width: 400px; height: 200px; border: skyblue 1px solid;">
								index
								<hr/>
								<router-view></router-view>
							</div>`
			};
			
			const t2 = {template: '<div>t2</div>'};
			const t3 = {template: '<div>t3</div>'};

			const myrouter = new VueRouter({
				routes: [{
					path: "/a",
					component: t1,
					children: [
						{
							path:"c2",
							component: t2
						},
						{
							path:"c3",
							component: t3
						}
					]
				}]
			});

			var vm = new Vue({
				el: "#container",
				router: myrouter
			});
		</script>
	</body>
</html>

5. 编程式导航

学习目标:掌握不使用路由标签链接,通过 js 代码进行路由跳转的方式。

push()

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>luis</title>

		<!-- 引入vue -->
		<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
		<!-- 引入vue-router -->
		<!-- 低版本,也可以使用 -->
		<!-- <script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script> -->
		<script src="https://cdn.jsdelivr.net/npm/vue-router@3.5.1/dist/vue-router.min.js"></script>

	</head>
	<body>
		<div id="container">
			
			<!-- 舍弃下面通过超链接跳转 -->
			<!-- <router-link to="/index">首页</router-link> -->
			<!-- 改用通过按钮进行跳转 -->
			<button type="button" @click="btnClick">首页跳转</button>
			<router-view></router-view>
			
		</div>

		<script type="text/javascript">
			
			const t1 = {
				template: `<div style="width: 400px; height: 200px; border: skyblue 1px solid;">
								index
							</div>`
			};

			const myrouter = new VueRouter({
				routes: [{
					path: "/index",
					component: t1
				}]
			});

			var vm = new Vue({
				el: "#container",
				router: myrouter,
				methods:{
					btnClick:function() {
						//js代码实现路由跳转,编程式导航
						myrouter.push("/index");
					}
				}
			});
		</script>
	</body>
</html>

push() 参数

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>luis</title>

		<!-- 引入vue -->
		<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
		<!-- 引入vue-router -->
		<!-- 低版本,也可以使用 -->
		<!-- <script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script> -->
		<script src="https://cdn.jsdelivr.net/npm/vue-router@3.5.1/dist/vue-router.min.js"></script>

	</head>
	<body>
		<div id="container">
			
			<!-- 舍弃下面通过超链接跳转 -->
			<!-- <router-link to="/index">首页</router-link> -->
			<!-- 改用通过按钮进行跳转 -->
			<button type="button" @click="btnClick">首页跳转</button>
			<router-view></router-view>
			
		</div>

		<script type="text/javascript">
			
			const t1 = {
				template: `<div style="width: 400px; height: 200px; border: skyblue 1px solid;">
								index:{{$route.params.id}}
							</div>`
			};

			const myrouter = new VueRouter({
				routes: [{
					path: "/index",
					name: "r1",
					component: t1
				}]
			});

			var vm = new Vue({
				el: "#container",
				router: myrouter,
				methods:{
					btnClick:function() {
						//js代码实现路由跳转,编程式导航
						
						//方式一:字符串
						// myrouter.push("/index");
						
						//方式二:对象
						// myrouter.push({path:"/index"})
						// myrouter.push({path:"/index", params:{id:121}});
						//如果要使用组件传值,可以在定义路由路径时指定如:path:'index/:id',然后下方传值
						// myrouter.push({path:"/index/111"});
						
						//方式三:命名的路由,需要定义路由名字name
						// myrouter.push({name:"r1", params:{id:121}});
						
						//方式四,url传参,并非组件传值,相当于/index?id=101
						// myrouter.push({path:"/index", query:{id:101}});
					}
				}
			});
		</script>
	</body>
</html>

replace()

replace() 和 push() 功能一致,只是 replace() 不会向 history 添加新的浏览记录(即页面没有前进后退记录)

go()

用法:路由对象.go(-1);

参数为⼀个整数,表示在浏览器历史记录中前后/后退多少步,相当于 window.history.go(-1) 的作⽤;

参数为负整数,则表示后退多少步;参数为正整数,则表示前进多少步。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>luis</title>

		<!-- 引入vue -->
		<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
		<!-- 引入vue-router -->
		<!-- 低版本,也可以使用 -->
		<!-- <script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script> -->
		<script src="https://cdn.jsdelivr.net/npm/vue-router@3.5.1/dist/vue-router.min.js"></script>

	</head>
	<body>
		<div id="container">
			
			<!-- 舍弃下面通过超链接跳转 -->
			<!-- <router-link to="/index">首页</router-link> -->
			<!-- 改用通过按钮进行跳转 -->
			<button type="button" @click="btnClick">首页跳转</button>
			<button type="button" @click="back">后退</button>
			<router-view></router-view>
			
		</div>

		<script type="text/javascript">
			
			const t1 = {
				template: `<div style="width: 400px; height: 200px; border: skyblue 1px solid;">
								index:{{$route.params.id}}
							</div>`
			};

			const myrouter = new VueRouter({
				routes: [{
					path: "/index",
					name: "r1",
					component: t1
				}]
			});

			var vm = new Vue({
				el: "#container",
				router: myrouter,
				methods:{
					btnClick:function() {
						//js代码实现路由跳转,编程式导航
						myrouter.push("/index");
					},
					back:function() {
						myrouter.go(-1);
					}
				}
			});
		</script>
	</body>
</html>

6. 命名路由

命名路由:在定义路由的时候可以给路由指定 name,我们在进⾏路由导航时可以通过路由的名字导航

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>luis</title>

		<!-- 引入vue -->
		<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
		<!-- 引入vue-router -->
		<!-- 低版本,也可以使用 -->
		<!-- <script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script> -->
		<script src="https://cdn.jsdelivr.net/npm/vue-router@3.5.1/dist/vue-router.min.js"></script>

	</head>
	<body>
		<div id="container">
			
			<!-- 使用路由的name进行链接跳转,注意to属性需要进行绑定,需要加冒号 -->
			<router-link :to="{name:'r1'}">name链接跳转</router-link>
			<!-- js代码进行路由跳转 -->
			<button type="button" @click="btnClick">按钮跳转</button>
			<router-view></router-view>
			
		</div>

		<script type="text/javascript">
			
			const t1 = {
				template: `<div style="width: 400px; height: 200px; border: skyblue 1px solid;">
								index:t1 skyblue
							</div>`
			};
			const t2 = {
				template: `<div style="width: 400px; height: 200px; border: red 1px solid;">
								index:t2 red
							</div>`
			};

			const myrouter = new VueRouter({
				routes: [
					{
						path: "/a",
						name: "r1",
						component: t1
					},
					{
						path: "/b",
						name: "r2",
						component: t2
					}
				]
			});

			var vm = new Vue({
				el: "#container",
				router: myrouter,
				methods:{
					btnClick:function() {
						//js代码实现路由跳转,编程式导航
						myrouter.push({name:"r2"});
					}
				}
			});
		</script>
	</body>
</html>

7. 命名路由视图

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>luis</title>

		<!-- 引入vue -->
		<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
		<!-- 引入vue-router -->
		<!-- 低版本,也可以使用 -->
		<!-- <script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script> -->
		<script src="https://cdn.jsdelivr.net/npm/vue-router@3.5.1/dist/vue-router.min.js"></script>

	</head>
	<body>
		<div id="container">
			
			<!-- 多个模板放在多个视图中展示 -->
			
			<router-link to="/a">a链接跳转</router-link>
			<router-link to="/b">b链接跳转</router-link>
			
			<!-- 命名路由视图 -->
			<!--
			如果在HTML中有一个以上的路由视图router-view,需要给router-view指定name,
			在路由中使用components映射多个组件根据name设置组件与router-view绑定关系
			-->
			<router-view name="v1"></router-view>
			<router-view name="v2"></router-view>
			
		</div>

		<script type="text/javascript">
			
			const t11 = {
				template: `<div style="width: 400px; height: 200px; border: skyblue 1px solid;">
								index:t11 skyblue
							</div>`
			};
			const t12 = {
				template: `<div style="width: 400px; height: 200px; border: yellow 1px solid;">
								index:t12 yellow
							</div>`
			};
			const t21 = {
				template: `<div style="width: 400px; height: 200px; border: skyblue 1px solid;">
								index:t21 skyblue
							</div>`
			};
			const t22 = {
				template: `<div style="width: 400px; height: 200px; border: yellow 1px solid;">
								index:t22 yellow
							</div>`
			};
			

			const myrouter = new VueRouter({
				routes: [
					{
						path: "/a",
						name: "r1",
						components: {
							v1: t11,
							v2: t12
						}
					},
					{
						path: "/b",
						name: "r2",
						components: {
							v1: t21,
							v2: t22
						}
					}
				]
			});

			var vm = new Vue({
				el: "#container",
				router: myrouter
			});
		</script>
	</body>
</html>

8. 重定向和别名

重定向

访问 /b,重定向到 /a

  • 根据路径重定向
  • 根据路由命名重定向
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>luis</title>

		<!-- 引入vue -->
		<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
		<!-- 引入vue-router -->
		<!-- 低版本,也可以使用 -->
		<!-- <script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script> -->
		<script src="https://cdn.jsdelivr.net/npm/vue-router@3.5.1/dist/vue-router.min.js"></script>

	</head>
	<body>
		<div id="container">
			
			<router-link to="/a">路径a</router-link>
			<router-link to="/b">路径b</router-link>
			<router-view ></router-view>
			
		</div>

		<script type="text/javascript">
			
			const t1 = {
				template: `<div style="width: 400px; height: 200px; border: skyblue 1px solid;">
								index:t11 skyblue
							</div>`
			};

			const myrouter = new VueRouter({
				routes: [
					{
						path: "/a",
						name: "r1",
						component: t1
					},
					{
						path: "/b",
						//根据路径重定向
						// redirect: "/a"
						//根据路由命名重定向
						redirect: {name: "r1"}
					}
				]
			});

			var vm = new Vue({
				el: "#container",
				router: myrouter
			});
		</script>
	</body>
</html>

路由别名

给路由路径起别名,可以通过别名访问,隐藏真实路径。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>luis</title>

		<!-- 引入vue -->
		<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
		<!-- 引入vue-router -->
		<!-- 低版本,也可以使用 -->
		<!-- <script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script> -->
		<script src="https://cdn.jsdelivr.net/npm/vue-router@3.5.1/dist/vue-router.min.js"></script>

	</head>
	<body>
		<div id="container">
			
			<router-link to="/a">路径a</router-link>
			<router-link to="/haha">路径a的别名haha</router-link>
			<router-link to="/b">路径b</router-link>
			<router-view ></router-view>
			
		</div>

		<script type="text/javascript">
			
			const t1 = {
				template: `<div style="width: 400px; height: 200px; border: skyblue 1px solid;">
								index:t11 skyblue
							</div>`
			};

			const myrouter = new VueRouter({
				routes: [
					{
						path: "/a",
						alias: "/haha", //起别名
						name: "r1",
						component: t1
					},
					{
						path: "/b",
						//根据路径重定向
						// redirect: "/a"
						//根据路由命名重定向
						redirect: {name: "r1"}
						
					}
				]
			});

			var vm = new Vue({
				el: "#container",
				router: myrouter
			});
		</script>
	</body>
</html>

9. 路由组件传参

方式一:可以通过 /url/:attr ⽅式实现通过路由传值给组件(耦合度较高)

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>luis</title>

		<!-- 引入vue -->
		<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
		<!-- 引入vue-router -->
		<!-- 低版本,也可以使用 -->
		<!-- <script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script> -->
		<script src="https://cdn.jsdelivr.net/npm/vue-router@3.5.1/dist/vue-router.min.js"></script>

	</head>
	<body>
		<div id="container">
			
			<router-link to="/a/111">路径a</router-link>
			<router-view ></router-view>
			
		</div>

		<script type="text/javascript">
			
			const t1 = {
				template: `<div style="width: 400px; height: 200px; border: skyblue 1px solid;">
								参数:{{$route.params.id}}
							</div>`
			};

			const myrouter = new VueRouter({
				routes: [
					{
						path: "/a/:id",
						component: t1
					}
				]
			});

			var vm = new Vue({
				el: "#container",
				router: myrouter
			});
		</script>
	</body>
</html>

方式二:通过 props 传参(常用,解耦)

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>luis</title>

		<!-- 引入vue -->
		<script src="https://cdn.staticfile.org/vue/2.4.2/vue.min.js"></script>
		<!-- 引入vue-router -->
		<!-- 低版本,也可以使用 -->
		<!-- <script src="https://cdn.staticfile.org/vue-router/2.7.0/vue-router.min.js"></script> -->
		<script src="https://cdn.jsdelivr.net/npm/vue-router@3.5.1/dist/vue-router.min.js"></script>

	</head>
	<body>
		<div id="container">
			
			<router-link to="/a/333">路径a</router-link>
			<router-view ></router-view>
			
		</div>

		<script type="text/javascript">
			
			const t1 = {
				props: ["id"], //设置属性
				template: `<div style="width: 400px; height: 200px; border: skyblue 1px solid;">
								参数:{{id}}
							</div>`
			};

			const myrouter = new VueRouter({
				routes: [
					{
						path: "/a/:id",
						props: true, //开启属性
						component: t1
					}
				]
			});

			var vm = new Vue({
				el: "#container",
				router: myrouter
			});
		</script>
	</body>
</html>

PS:以上是路由一些基础的使用,其他内容或详细的使用参考官方文档。

第一个 vue-cli 程序

什么是 vue-cli

  • vue-cli 是官方提供的一个脚手架,用于快速生成一个 vue 的项目模板
  • 预先定义好的目录结构以及基础代码,就好比咱们在创建 Maven 项目时可以选择创建一个骨架项目,这个骨架项目就是脚手架,使我们的开发更加的便捷。

主要的功能:

  • 统一的目录结构
  • 本地调试
  • 热部署
  • 单元测试
  • 集成打包上线

需要的环境

1、安装 Node.js

确认 Node.js 安装成功:

  • cmd 下 输入node -v,查看版本号打印信息

  • cmd 下 输入npm -v,查看版本号打印信息

    npm:软件包管理工具,类似 Linux 中 apt 软件安装。

2、安装 cnpm

安装 Node.js 淘宝镜像加速器(cnpm),解决 npm 速度慢的问题:

# -g 就是全局安装(推荐)
npm install cnpm -g

注意:建议优先使用 npm 下载,若 npm 下载缓慢,再考虑 使用 cnpm!(通过淘宝下载的偶尔可能出现问题)

查看安装情况:查看路径C:\Users\linwe\AppData\Roaming\npm\node_modules

3、安装 vue-cli

# 使用 cnpm 选择全局安装的方式安装 vue-cli
cnpm install vue-cli -g

# 测试是否安装成功
# 查看可以基于哪些模板创建 vue 程序,通常使用 webpack
vue list

查看安装情况:查看路径C:\Users\linwe\AppData\Roaming\npm\node_modules

第一个 vue-cli 程序创建

  1. 电脑上手动创建一个空目录,如D:\1a-Projects\vue-projects

  2. 在该目录下,使用 cmd 命令,进入 DOS 窗口,初始化项目:vue init webpack myvue

    依据以下模板,进行项目的创建:(一路都选择 no 即可)

    D:\1a-Projects\vue-projects>vue init webpack myvue
    
    # 项目名,默认,回车,即可
    ? Project name myvue
    # 项目描述,默认,回车,即可
    ? Project description A Vue.js project
    # 项目作者,默认,回车,即可
    ? Author luis
    # 选择第一种 build 方式
    ? Vue build standalone
    # 不安装 vue-router,选择 n,后续需要再手动添加
    ? Install vue-router? No
    # 是否使用 ESLint 做代码检查,选择 n,后续需要再手动添加
    ? Use ESLint to lint your code? No
    # 单元测试相关,选择 n,后续需要再手动添加
    ? Set up unit tests No
    # 单元测试相关,选择 n,后续需要再手动添加
    ? Setup e2e tests with Nightwatch? No
    # 是否创建完成后直接初始化,选择 n,我们手动执行,运行结果!
    ? Should we run `npm install` for you after the project has been created? (recommended) no
    
       vue-cli · Generated "myvue".
    
    # Project initialization finished!
    # ========================
    
    To get started:
    
      cd myvue
      npm install (or if using yarn: yarn)
      npm run dev
    
    Documentation can be found at https://vuejs-templates.github.io/webpack
    

    视频参考:https://www.bilibili.com/video/BV18E411a7mC?p=13&spm_id_from=pageDriver&vd_source=4b96cdd8ce60c65ca7e8639e7e9d672a

  3. 初始化并运行(可使用IDEA打开该项目,查看相关目录结构)

    cd myvue # 进入myvue目录
    npm install # 安装依赖环境
    npm run dev # 运行项目(运行成功后,可在浏览器输入地址访问)
    

    PS:可使用 Ctrl + C 终止项目

webpack 学习使用

webpack 简介

  • webpack 主要作用是打包,其核心存在两个部分,入口和出口,可以把 webpack 想象成香肠加工厂,就是活猪进去,香肠出来的那种,但是如果每次加工都需要员工亲力亲为,那多麻烦,所以我们考虑到了自动化配置。webpack 存在功能类似的配置文件,让 webpack 通过配置,全自动的执行我们需要的编译操作。
  • webpack 分成四个部分,其中最核心的就是入口和出口,当然在入口和出口配置的同时我们还需要一些加载器和插件,这就是我们所谓的 webpack 配置文件,这个配置文件我们习惯把其命名为 webpack.config.js,还有 webpackfile.js。
  • webpack 是一种模块化的解决方案,其工作方式是:把你的项目当做一个整体,通过一个给定的主文件(如:index.js),webpack 将从这个文件开始找到你的项目的所有依赖文件,使用 loaders 处理它们,最后打包为一个(或多个)浏览器可识别的 JavaScript 文件。
  • webpack 使用 ES6 模块语法

总结一下,webpack 共分为四个部分:入口、出口、加载器、插件。

什么是 webpack

  • webpack 可以看做是模块打包机:分析你的项目结构,找到 JavaScript 模块以及其它的一些浏览器不能直接运行的拓展语言(如 Scss,TypeScript 等),并将其转换和打包为合适的格式供浏览器使用。

webpack 能干什么

  • 根据入口文件的依赖,加载所有模块 js,然后合并成一个 js
  • 标准且纯粹的模块化打包工具
  • 依赖一个文件入口,打包所有依赖为当前浏览器可用的代码

安装

npm install webpack -g # 安装打包工具
npm install webpack-cli -g # 安装客户端

webpack -v # 查看安装的版本(是否安装成功)

相关配置参数(了解)

创建webpack.config.js配置文件

  • entry:入口文件,指定 webpack 用哪个文件作为项目的入口
  • output:输出,指定 webpack 把处理完成的文件放置到指定路径
  • module:模块,用于处理各种类型的文件
  • plugins:插件,如:热更新、代码复用等
  • resolve:设置路径指向
  • watch:监听,用于设置文件改动后直接打包

使用 webpack

目录结构预览:

image-20220711143856082

  1. D:\1a-Projects\vue-projects下创建名为webpack-study的空目录(自定义),作为示例项目,使用 IDEA 打开

  2. 在项目目录下,创建 modules 目录,用于存放 JS 模块等资源文件

  3. 在 modules 目录下,创建模块文件,如 hello.js,编写 JS 模块相关代码,如:

    hello.js

    // 暴露一个方法 sayHi1
    exports.sayHi1 = function () {
        document.write("<h1>luis1 learns ES6</h1>")
    };
    // 暴露一个方法 sayHi2
    exports.sayHi2 = function () {
        document.write("<h2>luis2 learns ES6</h2>")
    };
    // 暴露一个方法 sayHi3
    exports.sayHi3 = function () {
        document.write("<h3>luis3 learns ES6</h3>")
    };
    
  4. 在 modules 目录下,创建一个名为 main.js 的入口文件,用于打包时设置 entry 属性,如:

    main.js

    // require 导入一个模块,就可以调用这个模块中的方法了
    var hello = require("./hello");
    hello.sayHi1();
    hello.sayHi2();
    hello.sayHi3();
    
  5. 在项目目录下,创建 webpack.config.js 配置文件,用于配置相关参数

    webpack.config.js

    module.exports = {
        entry: './modules/main.js',
        output: {
            filename: "./js.bundle.js"
        }
    }
    
  6. 在项目目录下,地址栏输入 cmd 进入 DOS 窗口,输入webpack命令进行打包;

    打包完成后,在指定的输出路径下就可看到打包压缩后的 js,后面如需使用,则直接引入该 js 即可,不用再使用打包前的那些 js。

    D:\1a-Projects\vue-projects\webpack-study>webpack
    
  7. 引入打包压缩后的 js:在项目目录下,创建 index.html,在其中直接引入打包压缩后的 js,浏览器打开即可

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        <!--前端的模块化开发-->
        <script src="dist/js.bundle.js"></script>
    </body>
    </html>
    

image-20220711143856082

总结:

  • vue.js 是一个前端 js 框架,是一套构建用户界面的渐进式框架
  • 前端的模块化开发:将 js 写好,使用 webpack 打包后,直接在前端引入即可

vue-router 路由(旧)

Tips:学习的时候,尽量打开官方文档。

认识 vue-router

目前前端流行的三大框架,都有自己的路由实现:

  • Angular 的 ngRouter
  • React 的 ReactRouter
  • Vue 的 vue-router

vue-router 是 Vue.js 官方的路由插件,它和 vue.js 是深度集成的,适合用于构建单页面应用。可访问其官方网站对其进行学习:https://router.vuejs.org/zh/

vue-router 是基于路由和组件的

  • 路由用户设定访问路径,将路径和组件映射起来。
  • 在 vue-router 的单页面应用中,页面路径的改变就是组件的切换。

SPA(single page application):单一页面应用程序,只有一个完整的页面;它在加载页面时,不会加载整个页面,而是只更新某个指定的容器中内容。单页面应用(SPA)的核心之一是:更新视图而不重新请求页面;vue-router 在实现单页面前端路由时,提供了两种方式:Hash 模式和 History 模式。

功能

vue-router 是 Vue.js 官方的路由管理器,它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌,包含的功能有:

  • 嵌套的路由/视图表
  • 模块化的、基于组件的路由配置
  • 路由参数、查询、通配符
  • 基于 Vue.js 过渡系统的视图过渡效果
  • 细粒度的导航控制
  • 带有自动激活的 CSS class 的链接
  • HTML5 历史模式或 hash 模式,在 IE9 中自动降级
  • 自定义的滚动条行为

安装

基于第一个 vue-cli 程序进行测试学习,先查看 node_modules 中是否存在 vue-router(之前创建第一个 vue-cli 程序时可选择是否安装 rue-router)

vue-router 是一个插件包,所以我们还是需要用 npm/cnpm 进行安装!

在第一个 vue-cli 项目目录地址栏输入 cmd 命令,进入 DOS 窗口,输入以下命令,进行安装:

# 方式一:建议使用!(使用 cnpm 方式,安装低版本的 vue-router;经测试,高版本的使用有问题!)
cnpm install vue-router@3.1.3 --save-dev

# 方式二
npm install vue-router --save-dev

# 方式三:若以上方式安装都有问题,就使用此种 cnpm 安装
cnpm install vue-router --save-dev

安装完成后,在 node_modules 目录中就会出现 vue-router 的 js 库,需要使用的地方,导入即可使用!

使用 vue-router

PS:删除无用东西,如初始的 HelloWorld 组件相关

最终目录结构预览:(基于之前创建的第一个 vue-cli 程序)

image-20220711173031480

  1. components 目录下新建两个自定义的组件,用于路由组件跳转测试;

    Main.vue

    <template>
      <h2>首页</h2>
    </template>
    
    <script>
    export default {
      name: "Main"
    }
    </script>
    
    <style scoped>
    
    </style>
    

    Content.vue

    <template>
      <h1>内容页</h1>
    </template>
    
    <script>
    export default {
      name: "Content"
    }
    </script>
    
    <style scoped>
    
    </style>
    
  2. 在 src 目录下,新建 router 目录,专门存放路由;在 router 目录下,新建 index.js,用来导入、安装并配置路由;

    index.js

    import Vue from "vue";
    import VueRouter from "vue-router";
    
    import Content from "../components/Content";
    import Main from "../components/Main";
    
    
    //安装路由
    Vue.use(VueRouter);
    
    //配置路由
    export default new VueRouter({
      routes: [
        {
          //路由路径 相当于@RequestMapping
          path: '/content',
          name: 'content',
          //跳转的组件
          component: Content
        },
        {
          //路由路径
          path: '/main',
          name: 'main',
          //跳转的组件
          component: Main
        }
      ]
    });
    
  3. 在 main.js 中配置路由

    main.js

    import Vue from 'vue'
    import App from './App'
    //导入之前创建的路由配置目录
    import router from './router'
    
    Vue.config.productionTip = false 
    
    /* eslint-disable no-new */
    new Vue({
      el: '#app',
      //配置路由
      router,
      components: { App },
      template: '<App/>'
    })
    
  4. 在 App.vue 中使用路由

    App.vue

    <template>
      <div id="app">
    
        <h2>路由跳转测试</h2>
        <h2>Vue-Router</h2>
        <router-link to="/main">首页</router-link>
        <router-link to="/content">内容页</router-link>
        <!--用来展示路由跳转的页面-->
        <router-view></router-view>
    
      </div>
    </template>
    
    <script>
    
    
    export default {
      name: 'App'
    
    }
    </script>
    
    <style>
    #app {
      font-family: 'Avenir', Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-align: center;
      color: #2c3e50;
      margin-top: 60px;
    }
    </style>
    
  5. 在项目目录,在其地址栏输入 cmd 命令,进入 dos 窗口(或直接在 IDEA 终端中)运行项目:npm run dev

  6. 浏览器输入相关地址,进行访问测试

Tips:后续需要添加组件跳转,只需要以下三步即可!

  1. 在 components 目录下创建自定义组件
  2. 在 router 目录的 index.js 中配置路由
  3. 在 App.vue 中使用路由

Vue+ ElementUI

说明:结合之前所学 + 使用 ElementUI 组件库,进行实战训练

Element UI官网:https://element.eleme.cn/#/zh-CN/component/installation

准备

  • 创建一个目录如vue-projects,用来存放后续创建的 vue 工程,如D:\1a-Projects\vue-projects

  • 以管理员权限打开命令行,并切换到该vue-projects目录下

    操作:点击搜索框,输入 cmd,右击以管理员方式运行命令提示符;先切换到 d 盘d:,再使用 cd 命令切换到指定目录即可!

步骤

  1. vue-projects目录下创建名为 hi-vue 的工程:

    D:\1a-Projects\vue-projects>vue init webpack hi-vue
    

    安装过程:项目名、描述、作者默认即可;编译环境选第一个;后续一路 no;npm install 选第三个,手动安装!

    以上,项目初始化完成!

  2. 进入到 hi-vue 项目目录下,安装依赖和插件:

    Tips:如果使用国外 npm 方式下载有问题,可尝试换国内淘宝 cnpm 方式下载!

    Tips:如果安装过程中无 ERR(即错误),则可视为正常,继续后续操作即可!

    Tips:如果最后启动失败,找不出原因,可重新新建工程、初始化项目、重新安装!

    # 进入工程目录
    cd hi-vue
    
    # 安装 vue-router
    # 优选方案(使用 cnpm 方式,安装低版本的 vue-router;经测试,高版本的使用有问题!)
    cnpm install vue-router@3.1.3 --save-dev
    # 备选方案
    # cnpm install vue-router --save-dev
    
    # 安装 element-ui(官网推荐使用npm方式安装)(如果安装有问题,就换 cnpm 方式安装!)
    npm i element-ui -S
    
    # 安装依赖
    npm install
    
    # 安装 SASS 加载器
    cnpm install sass-loader node-sass --save-dev
    
    # 启动测试
    npm run dev
    

Npm 命令解释

  • npm install moduleName:安装模块到项目目录下
  • npm install -g moduleName-g 的意思是将模块安装到全局,具体安装到磁盘哪个位置,要看 npm config prefix 的位置
  • npm install --save moduleName--save 的意思是将模块安装到项目目录下,并在 package 文件的 dependencies 节点写入依赖,-S为该命令的缩写
  • npm install --save-dev moduleName--save-dev的意思是将模块安装到项目目录下,并在 package 文件的 devDependencies 节点写入依赖,-D为该命令的缩写
  1. 启动成功并在浏览器成功访问后;IDEA 打开项目,删除 assets 中图片,删除 components 中 HelloWorld.vue 组件,删除 App.vue 中无用的图片引入和 HelloWorld 组件相关内容;至此,基础工程有了!

  2. 在 src 目录下,新建 router 目录,存放路由相关;新建 views 目录,存放视图相关(组件);

    目录说明:components(放功能性相关组件)、router(放路由相关组件)、views(放视图相关组件)

  3. views 下新建 Main.vue(首页)和Login.vue(登陆页)作为视图展示页

    Main.vue

    <template>
      <h1>首页</h1>
    </template>
    
    <script>
    export default {
      name: "Main"
    }
    </script>
    
    <style scoped>
    
    </style>
    

    Login.vue(此登陆模板直接从 ElementUI 官网表单组件库中复制即可)

    <template>
      <div>
        <el-form ref="loginForm" :model="form" :rules="rules" label-width="80px" class="login-box">
          <h3 class="login-title">欢迎登录</h3>
          <el-form-item label="账号" prop="username">
            <el-input type="text" placeholder="请输入账号" v-model="form.username"/>
          </el-form-item>
          <el-form-item label="密码" prop="password">
            <el-input type="password" placeholder="请输入密码" v-model="form.password"/>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" v-on:click="onSubmit( 'loginForm' )">登录</el-button>
          </el-form-item>
        </el-form>
    
        <el-dialog
          title="温馨提示"
          :visible.sync="dialogVisible"
          width="30%"
          :before-close="handLeClose">
          <span>请输入账号和密码</span>
          <span slot="footer" class="dialog- footer">
            <el-button type="primary" @click="dialogVisible = false">确定</el-button>
          </span>
        </el-dialog>
      </div>
    </template>
    
    <script>
    export default {
      name: "Login",
      data() {
        return {
          form: {
            username: '',
            password: ''
          },
          //表单验证,需要在el-form-item 元素中增加prop 属性
          rules: {
            username: [
              {required: true, message: " 账号不可为空", trigger: 'blur'}
            ],
            password: [
              {required: true, message: " 密码不可为空 ", trigger: 'blur'}
            ]
          },
          //对话框显示和隐藏
          dialogVisible: false
        }
      },
      methods: {
        onSubmit(formName) {
          //为表单绑定验证功能
          this.$refs[formName].validate((valid) => {
            if (valid) {
              //使用vue-router路由到指定页面,该方式称之为编程式导航
              this.$router.push("/main");
            } else {
              this.dialogVisible = true;
              return false;
            }
          });
        }
      }
    }
    </script>
    
    <style lang="scss" scoped>
    .login-box {
      border: 1px solid #DCDFE6;
      width: 350px;
      margin: 180px auto;
      padding: 35px 35px 15px 35px;
      border-radius: 5px;
      -webkit-border-radius: 5px;
      -moz-border-radius: 5px;
      box-shadow: 0 0 25px #909399;
    }
    
    .login-title {
      text-align: center;
      margin: 0 auto 40px auto;
      color: #303133;
    }
    </style>
    
  4. router 目录下新建index.js,在其中配置路由

    index.js

    import Vue from 'vue'
    import VueRouter from 'vue-router'
    import Main from "../views/Main";
    import Login from "../views/Login";
    
    //安装路由
    Vue.use(VueRouter);
    
    //配置路由
    export default new VueRouter({
      routes: [
        {
          path: '/main',
          component: Main
        },
        {
          path: '/login',
          component: Login
        }
      ]
    });
    
  5. main.js 中引入 ElementUI 和 router

    import Vue from 'vue'
    import App from './App'
    
    import router from './router'
    
    import ElementUI from 'element-ui';
    import 'element-ui/lib/theme-chalk/index.css';
    
    Vue.config.productionTip = false
    
    Vue.use(router);
    Vue.use(ElementUI);
    
    new Vue({
      el: '#app',
      router,
      render: h => h(App)
      // components: { App },
      // template: '<App/>'
    })
    
  6. App.vue中展示使用

    App.vue

    <template>
      <div id="app">
        <router-link to="/main">首页</router-link>
        <router-link to="/login">登陆</router-link>
        <router-view></router-view>
      </div>
    </template>
    
    <script>
    
    export default {
      name: 'App'
    }
    </script>
    
  7. 终端输入npm run dev运行,浏览器访问测试

    http://localhost:8080

    http://localhost:8080/#/main

    http://localhost:8080/#/login

可能遇到的问题

  • 安装的 sass-loader版本太高?

    解决:package.json 中将 sass-loader 版本改到指定低版本如 4.0.0;终端执行npm install,不行就cnpm install,重新npm run dev启动即可。

  • vue-router 版本太高,导致路由声明无效,找不到?

    解决:安装低版本的 vue-router,执行cnpm install vue-router@3.1.3 --save-dev,重新npm run dev启动即可。

小结

vue + element-ui 使用要点:

  1. main.js 中引入 Element
  2. views 或 components 中创建组件文件,在合适的位置复制进需使用的组件代码
  3. 在如App.vue中使用

路由嵌套

  • 路由嵌套又称子路由,在实际应用中,通常由多层嵌套的组件组合而成。同样地,URL 中各段动态路径也按某种结构对应嵌套的各层组件,如 /user/foo/profile/user/foo/posts

基于前面 hi-vue 继续举例学习:

  1. 在 views 目录下新建 user 目录,在 user 目录下创建 List.vueProfile.vue作为用户列表和个人信息展示

    List.vue

    <template>
      <h2>用户列表</h2>
    </template>
    
    <script>
    export default {
      name: "UserList"
    }
    </script>
    
    <style scoped>
    
    </style>
    

    Profile.vue

    <template>
      <h2>个人信息</h2>
    </template>
    
    <script>
    export default {
      name: "UserProfile"
    }
    </script>
    
    <style scoped>
    
    </style>
    
  2. 在 router 目录的 index.js 中导入新组件,在 Main 中嵌套子路由

    index.js

    import Vue from 'vue'
    
    import VueRouter from 'vue-router'
    
    import Main from "../views/Main";
    import Login from "../views/Login";
    
    import UserProfile from "../views/user/Profile";
    import UserList from "../views/user/List";
    
    import CheckPwd from "../views/CheckPwd";
    import Button from "../views/Button";
    
    //安装路由
    Vue.use(VueRouter);
    
    //配置路由
    export default new VueRouter({
      routes: [
        {
          path: '/main',
          component: Main,
          children: [ //路由嵌套(嵌套子路由)
            {
              path: '/user/profile',
              component: UserProfile
            },
            {
              path: '/user/list',
              component: UserList
            }
          ]
        },
        {
          path: '/login',
          component: Login
        }
      ]
    });
    
  3. 在 Main.vue 中添加侧边栏组件,实现路由嵌套(在 main 路由中嵌套子路由)的效果(侧边栏代码来自 ElementUI)

    Main.vue

    <template>
      <div>
        <el-container>
    
          <!--侧边栏-->
          <el-aside width="200px">
            <el-menu :default-openeds="['1']">
              <el-submenu index="1">
                <template slot="title"><i class="el-icon-caret-right"></i>用户管理</template>
                <el-menu-item-group>
                  <el-menu-item index="1-1">
                    <!--路由跳转-->
                    <router-link to="/user/profile">个人信息</router-link>
                  </el-menu-item>
                  <el-menu-item index="1-2">
                    <!--路由跳转-->
                    <router-link to="/user/list">用户列表</router-link>
                  </el-menu-item>
                </el-menu-item-group>
              </el-submenu>
              <el-submenu index="2">
                <template slot="title"><i class="el-icon-caret-right"></i>内容管理</template>
                <el-menu-item-group>
                  <el-menu-item index="2-1">分类管理</el-menu-item>
                  <el-menu-item index="2-2">内容列表</el-menu-item>
                </el-menu-item-group>
              </el-submenu>
            </el-menu>
          </el-aside>
    
          <!--顶栏-->
          <el-container>
            <el-header style="text-align: right; font-size: 12px">
              <el-dropdown>
                <i class="el-icon-setting" style="margin-right:15px"></i>
                <el-dropdown-menu slot="dropdown">
                  <el-dropdown-item>个人信息</el-dropdown-item>
                  <el-dropdown-item>退出登录</el-dropdown-item>
                </el-dropdown-menu>
              </el-dropdown>
            </el-header>
    
            <!--主显示页-->
            <el-main>
              <!--这里展示路由跳转的组件样式-->
              <router-view/>
            </el-main>
          </el-container>
    
        </el-container>
      </div>
    
    </template>
    
    <script>
    export default {
      name: "Main"
    }
    </script>
    
    <style scoped>
    .el-header {
      background-color: #048bd1;
      color: #333;
      line-height: 60px;
    }
    
    .el-aside {
      color: #333;
    }
    </style>
    
  4. 终端输入npm run dev启动项目,并在浏览器访问http://localhost:8080/#/main测试

参数传递以及重定向

参数传递

例子1:(整页代码示例)

  1. 在路由跳转时,不仅仅需要路径,还需要定义参数;

    在 Main.vue 中,修改需传参的路由跳转方式:使用 v-bind,以对象形式进行传参,显示声明 name 和 params 属性

    Main.vue

    <template>
      <div>
        <el-container>
    
          <!--侧边栏-->
          <el-aside width="200px">
            <el-menu :default-openeds="['1']">
              <el-submenu index="1">
                <template slot="title"><i class="el-icon-caret-right"></i>用户管理</template>
                <el-menu-item-group>
                  <el-menu-item index="1-1">
                    <!--路由跳转-->
                    <!--<router-link to="/user/profile">个人信息</router-link>-->
                    <!--前端传参,需要对象,使用v-bind,name和路由配置中name一致 (v-bind:xx 可简写为 :xx)-->
                    <router-link v-bind:to="{name: 'UserProfile', params: {id: 1}}">个人信息</router-link>
                  </el-menu-item>
                  <el-menu-item index="1-2">
                    <!--路由跳转-->
                    <router-link to="/user/list">用户列表</router-link>
                  </el-menu-item>
                  <el-menu-item index="1-3">
                    <!--路由跳转(重定向)-->
                    <router-link to="/goHome">回到首页</router-link>
                  </el-menu-item>
                </el-menu-item-group>
              </el-submenu>
              <el-submenu index="2">
                <template slot="title"><i class="el-icon-caret-right"></i>内容管理</template>
                <el-menu-item-group>
                  <el-menu-item index="2-1">分类管理</el-menu-item>
                  <el-menu-item index="2-2">内容列表</el-menu-item>
                </el-menu-item-group>
              </el-submenu>
            </el-menu>
          </el-aside>
    
          <!--顶栏-->
          <el-container>
            <el-header style="text-align: right; font-size: 12px">
              <el-dropdown>
                <i class="el-icon-setting" style="margin-right:15px"></i>
                <el-dropdown-menu slot="dropdown">
                  <el-dropdown-item>个人信息</el-dropdown-item>
                  <el-dropdown-item>退出登录</el-dropdown-item>
                </el-dropdown-menu>
              </el-dropdown>
            </el-header>
    
            <!--主显示页-->
            <el-main>
              <!--这里展示路由跳转的组件样式-->
              <router-view/>
            </el-main>
          </el-container>
    
        </el-container>
      </div>
    
    </template>
    
    <script>
    export default {
      name: "Main"
    }
    </script>
    
    <style scoped>
    .el-header {
      background-color: #048bd1;
      color: #333;
      line-height: 60px;
    }
    
    .el-aside {
      color: #333;
    }
    </style>
    
  2. 在 router 的 index.js 中,修改需接参路由的路径格式 path,并定义 name 和 props 属性

    index.js

    import Vue from 'vue'
    
    import VueRouter from 'vue-router'
    
    import Main from "../views/Main";
    import Login from "../views/Login";
    
    import UserProfile from "../views/user/Profile";
    import UserList from "../views/user/List";
    
    import CheckPwd from "../views/CheckPwd";
    import Button from "../views/Button";
    
    //安装路由
    Vue.use(VueRouter);
    
    //配置路由
    export default new VueRouter({
      routes: [
        {
          path: '/main',
          component: Main,
          children: [ //路由嵌套(嵌套子路由)
            {
              // path: '/user/profile',
              path: '/user/profile/:id', //接参
              name: 'UserProfile', //可定义name属性
              component: UserProfile,
              props: true //通过声明props解耦,在任何地方都可使用该组件
            },
            {
              path: '/user/list',
              component: UserList
            }
          ]
        },
        {
          path: '/login',
          component: Login
        },
        {
          path: '/goHome',
          redirect: '/main' //实现重定向
        }
      ]
    });
    
  3. 取参展示:在 Profile.vue中获取传递的参数,并进行展示

    下面列举两种方式:{{$route.params.id}} 方式获取;{{id}} 方式是在index.jsProfile.vue均声明 props 后可用!

    Profile.vue

    <template>
      <!-- 所有元素,不能直接暴露在根节点下!!! -->
      <div>
        <h2>个人信息</h2>
        {{$route.params.id}}
        <br/><br/>
        {{id}}
      </div>
    </template>
    
    <script>
    export default {
      props: ['id'], //可通过组件取参,在上面就可以直接用了
      name: "UserProfile"
    }
    </script>
    
    <style scoped>
    
    </style>
    
  4. 终端输入npm run dev启动项目,并在浏览器访问http://localhost:8080/#/main测试

例子2:(局部代码示例)

  1. 前端页面跳转时传递用户填写的参数(如下的用户填写的姓名参数)

    Login.vue

    <script>
    export default {
      name: "Login",
      data() {
        return {
          form: {
            username: '',
            password: ''
          },
          //表单验证,需要在el-form-item 元素中增加prop 属性
          rules: {
            username: [
              {required: true, message: " 账号不可为空", trigger: 'blur'}
            ],
            password: [
              {required: true, message: " 密码不可为空 ", trigger: 'blur'}
            ]
          },
          //对话框显示和隐藏
          dialogVisible: false
        }
      },
      methods: {
        onSubmit(formName) {
          //为表单绑定验证功能
          this.$refs[formName].validate((valid) => {
            if (valid) {
              //使用vue-router路由到指定页面,该方式称之为编程式导航
              //跳转并且传递参数(将用户填的姓名传递过去)
              this.$router.push("/main/" + this.form.username);
            } else {
              this.dialogVisible = true;
              return false;
            }
          });
        }
      }
    }
    </script>
    
  2. 路由配置中,配置接参路径,以及 props 属性的声明

    index.js

    //配置路由
    export default new VueRouter({
      routes: [
        {
          path: '/main/:name', //接参
          props: true, //声明为true,方便前端页面获取参数
          component: Main,
          children: [ //路由嵌套(嵌套子路由)
            {
              // path: '/user/profile',
              path: '/user/profile/:id', //接参
              name: 'UserProfile', //可定义name属性
              component: UserProfile,
              props: true //通过声明props解耦,在任何地方都可使用该组件
            },
            {
              path: '/user/list',
              component: UserList
            }
          ]
        },
        {
          path: '/login',
          component: Login
        },
        {
          path: '/goHome',
          redirect: '/main' //实现重定向
        }
      ]
    });
    
  3. 页面展示,声明 props 属性,并接参展示数据

    Main.vue

    <script>
    export default {
      props: ['name'], //接参
      name: "Main"
    }
    </script>
    
    -------------------
    
    <!--顶栏-->
    <el-container>
        <el-header style="text-align: right; font-size: 12px">
            <el-dropdown>
                <i class="el-icon-setting" style="margin-right:15px"></i>
                <el-dropdown-menu slot="dropdown">
                    <el-dropdown-item>个人信息</el-dropdown-item>
                    <el-dropdown-item>退出登录</el-dropdown-item>
                </el-dropdown-menu>
            </el-dropdown>
            <!--显示用户名-->
            <span>{{name}}</span>
        </el-header>
    
        <!--主显示页-->
        <el-main>
            <!--这里展示路由跳转的组件样式-->
            <router-view/>
        </el-main>
    </el-container>
    

重定向

以下简述实现方式:

  1. 在路由配置中使用 redirect进行路由重定向,如:

    index.js

    {
        path: '/goHome',
    	redirect: '/main' //实现重定向
    },
    
  2. 使用指定路径,以重定向方式进行跳转,如:

    Main.vue

    <el-menu-item index="1-3">
        <!--路由跳转(重定向)-->
        <router-link to="/goHome">回到首页</router-link>
    </el-menu-item>
    

注意

所有元素,不能直接暴露在根节点下!!!

Profile.vue说明举例:

错误用法:直接暴露在了<template>中,程序报错!

<template>
  <!-- 所有元素,不能直接暴露在根节点下!!! -->
  <button></button>
  <a></a>
  <p></p>

  <div>
    <h2>个人信息</h2>
    {{$route.params.id}}
    <br/><br/>
    {{id}}
  </div>
</template>

<script>
export default {
  props: ['id'], //可通过组件取参,在上面就可以直接用了
  name: "UserProfile"
}
</script>

<style scoped>

</style>

正确用法:元素建议套在<div>中使用!

<template>
  <!-- 所有元素,不能直接暴露在根节点下!!! -->
  <div>
    <button></button>
    <a></a>
    <p></p>
    
    <h2>个人信息</h2>
    {{$route.params.id}}
    <br/><br/>
    {{id}}
  </div>
</template>

<script>
export default {
  props: ['id'], //可通过组件取参,在上面就可以直接用了
  name: "UserProfile"
}
</script>

<style scoped>

</style>

路由模式、404 和路由钩子

路由模式

默认情况下,如,我们在地址栏中输入地址http://localhost:8080进行访问,回车后,该地址栏中地址会自动带上#号,变为http://localhost:8080/#/,这就是一种默认的路由模式!

路由模式有两种:hash 和 history

  • hash:路径带#符号,如http://localhost:8080/#/login
  • history:路径不带#符号,如http://localhost:8080/login

路由模式设置:(不设置的话默认是 hash 模式,带#

路由模式在路由配置中设置,一般通过在 router 目录的 index.js中设置 mode 属性,如下:

import Vue from 'vue'

import VueRouter from 'vue-router'

import Main from "../views/Main";
import Login from "../views/Login";

import UserProfile from "../views/user/Profile";
import UserList from "../views/user/List";

import CheckPwd from "../views/CheckPwd";
import Button from "../views/Button";

//安装路由
Vue.use(VueRouter);

//配置路由
export default new VueRouter({
  //设置路由模式(默认hash,带#号;history,则不带#号)
  mode: 'history',
  routes: [
    {
      path: '/main/:name', //接参
      props: true, //声明为true,方便前端页面获取参数
      component: Main,
      children: [ //路由嵌套(嵌套子路由)
        {
          // path: '/user/profile',
          path: '/user/profile/:id', //接参
          name: 'UserProfile', //可定义name属性
          component: UserProfile,
          props: true //通过声明props解耦,在任何地方都可使用该组件
        },
        {
          path: '/user/list',
          component: UserList
        }
      ]
    },
    {
      path: '/login',
      component: Login
    },
    {
      path: '/goHome',
      redirect: '/main' //实现重定向
    },
    {
      path: '/checkPwd',
      component: CheckPwd
    },
    {
      path: '/button',
      component: Button
    }
  ]
});

404

一般情况下,地址栏输入错误的访问地址,应该给出一个 404 提示页面,而不是什么都不显示!

步骤:

  1. views 下创建一个名为NotFound.vue的视图组件,如下:

    NotFoung.vue

    <template>
      <div>
        404~ 你的页面走丢了...
      </div>
    </template>
    
    <script>
    export default {
      name: "NotFound"
    }
    </script>
    
    <style scoped>
    
    </style>
    
  2. 路由配置(router 目录下 index.js

    import Vue from 'vue'
    
    import VueRouter from 'vue-router'
    
    import Main from "../views/Main";
    import Login from "../views/Login";
    
    import UserProfile from "../views/user/Profile";
    import UserList from "../views/user/List";
    
    import CheckPwd from "../views/CheckPwd";
    import Button from "../views/Button";
    
    import NotFound from "../views/NotFound";
    
    //安装路由
    Vue.use(VueRouter);
    
    //配置路由
    export default new VueRouter({
      //设置路由模式(默认hash,带#号;history,则不带#号)
      mode: 'history',
      routes: [
        {
          path: '/main/:name', //接参
          props: true, //声明为true,方便前端页面获取参数
          component: Main,
          children: [ //路由嵌套(嵌套子路由)
            {
              // path: '/user/profile',
              path: '/user/profile/:id', //接参
              name: 'UserProfile', //可定义name属性
              component: UserProfile,
              props: true //通过声明props解耦,在任何地方都可使用该组件
            },
            {
              path: '/user/list',
              component: UserList
            }
          ]
        },
        {
          path: '/login',
          component: Login
        },
        {
          path: '/goHome',
          redirect: '/main' //实现重定向
        },
        {
          path: '/checkPwd',
          component: CheckPwd
        },
        {
          path: '/button',
          component: Button
        },
        {
          path: '*', //匹配不到才走*
          component: NotFound
        }
      ]
    });
    
    
  3. npm run dev启动,浏览器输入规定内的不存在地址如http://localhost:8080/aa,则会展示 404 视图组件内容

路由钩子与异步请求

钩子函数

  • beforeRouteEnter:在进入路由前执行

  • beforeRouteLeave:在离开路由前执行

使用示例:

如在Profile.vue

<template>
  <!-- 所有元素,不能直接暴露在根节点下!!! -->
  <div>
    <h2>个人信息</h2>
    {{$route.params.id}}
    <br/><br/>
    {{id}}
  </div>
</template>

<script>
export default {
  props: ['id'], //可通过组件取参,在上面就可以直接用了
  name: "UserProfile",
  //路由钩子函数,类似于拦截器,在一些特殊时机自动执行!
  beforeRouteEnter: (to, from, next)=>{
    console.log("---》进入路由之前执行的!");
    next();
  },
  beforeRouteLeave: (to, from, next)=>{
    console.log("离开路由之前执行的!《===");
    next();
  }
}
</script>

<style scoped>

</style>

参数说明:

  • to:路由将要跳转的路径信息
  • from:路由跳转前的路径信息
  • next:路由的控制参数
    • next():跳入下一个页面
    • next('/path'):改变路由的跳转方向,使其跳到另一个路由
    • next(false):返回原来的页面
    • next((vm)=>{}):仅在beforeRouteEnter中可用,vm是组件实例

钩子函数中使用异步请求

  1. 安装 Axios:cnpm install --save axios vue-axios

  2. main.js中引用 Axios

    import Vue from 'vue'
    import App from './App'
    
    import router from './router'
    
    import ElementUI from 'element-ui';
    import 'element-ui/lib/theme-chalk/index.css';
    
    import axios from 'axios' //导入axios
    import VueAxios from 'vue-axios' //导入axios
    
    Vue.config.productionTip = false
    
    Vue.use(router);
    Vue.use(ElementUI);
    Vue.use(VueAxios, axios) //使用axios
    
    new Vue({
      el: '#app',
      router,
      render: h => h(App)
      // components: { App },
      // template: '<App/>'
    })
    
  3. 在 static 目录下新建 mock 目录,在 mock 目录下创建 data.json作为测试数据(static 目录下数据,地址栏可直接访问获取)

    data.json

    {
      "name": "luis",
      "url": "https://www.baidu.com",
      "page": 1,
      "isNonProfit": true,
      "address": {
        "street": "广建路",
        "city": "江苏苏州",
        "country": "中国"
      }
    }
    
  4. Profile.vue中,演示钩子函数与异步请求的使用

    Profile.vue

    <template>
      <!-- 所有元素,不能直接暴露在根节点下!!! -->
      <div>
        <h2>个人信息</h2>
        {{$route.params.id}}
        <br/><br/>
        {{id}}
      </div>
    </template>
    
    <script>
    export default {
      props: ['id'], //可通过组件取参,在上面就可以直接用了
      name: "UserProfile",
      //路由钩子函数,类似于拦截器,在一些特殊时机自动执行!
      beforeRouteEnter: (to, from, next)=>{
        console.log("---》进入路由之前执行的!");
        next((vm)=>{
          vm.getData(); //利用组件实例调组件方法,获取数据
        });
      },
      beforeRouteLeave: (to, from, next)=>{
        console.log("离开路由之前执行的!《===");
        next();
      },
      methods: {
        getData: function () {
          this.axios({ //使用Axios异步通信
            method: 'get',
            url: 'http://localhost:8080/static/mock/data.json' //请求的地址
          }).then(function (response) {
            console.log(response.data); //返回的数据
          });
        }
      }
    }
    </script>
    
    <style scoped>
    
    </style>
    
  5. npm run dev启动,浏览器 F12 打开调试,输入localhost:8080/main/luis进入首页,点击个人信息链接,观察路由跳转以及控制台打印数据信息,查看是否可成功获取数据。

posted @ 2022-11-16 15:25  luis林  阅读(639)  评论(0编辑  收藏  举报