Vue.js
本文基于vue@2.6.14
一、Vue概述
来看看官网的描述:
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。另一方面,当与现代化的工具链以及各种支持类库结合使用时,Vue 也完全能够为复杂的单页应用提供驱动。
后端开发,常用MVC模式。
前端开发,也有一些人把这个模式搬到了前端。
做一个Web应用,View 和 Model是必要的,后端给前端提供Model, 这个数据要这么渲染到视图上呢?于是,出现了MVVM模式。
这个VM就是ViewModel,也就是关于视图的数据。
而Vue就是VM的实现。
Vue的虚拟dom,比直接操作dom更快,加载页面更迅速,并且vue会自动响应数据的变化,我们不需要刷新页面也能让数据渲染到页面上。
二、Hello Vue
学习Vue最好的方式就是写代码,先来一个Hello Vue:
hello.html:
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>hello</title>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
{{ message }}
</div>
<script>
let vm = new Vue({
el:"#app",
data: {
message:"Hello Vue!"
}
});
</script>
</body>
</html>
创建一个Vue实例,安装到指定id上,然后就可以在其中用 {{}} 取出data中的值。
三、基础指令、语法
3.1 v-once、v-html
v-onece指令可以一次性的插值,当数据改变时,插值处的内容不会更新:
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>v-once指令</title>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<p v-once>{{ msg }}</p>
</div>
<script>
const vm = new Vue({
el:'#app',
data:{
msg:"666"
}
})
</script>
</body>
</html>
即使数据改变,视图也不会变:
v-html指令可以插入html,而不是纯文本:
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>v-html指令</title>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<p>{{ msg }}</p>
<p v-html="msg">}</p>
</div>
<script>
const vm = new Vue({
el:'#app',
data:{
msg:"<h1>v-html指令</h1>"
}
})
</script>
</body>
</html>
效果:
3.2 v-bind
对于html标签的属性,双大括号的语法已经不起作用,这个时候应该使用v-bind指令:
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>Title</title>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<span v-bind:title="message">鼠标在这悬停一下</span>
</div>
<script>
const vm = new Vue({
el:'#app',
data: {
message:"页面加载于" + new Date().toLocaleString()
}
});
</script>
</body>
</html>
效果:
<span v-bind:title="message">鼠标在这悬停一下</span>
<!-- 可缩写为 -->
<span :title="message">鼠标在这悬停一下</span>
3.3 v-if、v-else-if、v-else
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>判断</title>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<p v-if="ok === 1">OK!</p>
<p v-else-if="ok === 2">NO!</p>
<p v-else>ERROR!</p>
</div>
<script>
const vm = new Vue({
el : '#app',
data : {
ok : 1
}
})
</script>
</body>
</html>
和其他编程语言的判断是一样的道理。
3.4 v-for
可以遍历数组:
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>v-for指令</title>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<ul>
<li v-for="el in array">
{{el.text}}
</li>
</ul>
</div>
<script>
const vm = new Vue({
el : '#app',
data : {
array : [
{text : 'js'},
{text : 'vue'},
{text : 'java'}
]
}
});
</script>
</body>
</html>
"el in array"意思就是将data中的array中的每个元素取出来作为el。
效果:
3.5 v-on
v-on可以监听事件,从而调用某个函数做某些参数,例如单击按钮增加单击次数:
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>v-on事件监听</title>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<button v-on:click="count">
点击 {{ counts }} 次
</button>
</div>
<script>
const vm = new Vue({
el:'#app',
data:{
counts : 0
},
methods:{
count:function () {
this.counts++;
}
}
})
</script>
</body>
</html>
v-on也可以缩写:
<button @click="count">
点击 {{ counts }} 次
</button>
<!-- @ 就相当于 v-on: -->
3.6 v-model
v-model指令可以让视图和数据双向绑定:
例如我在文本框中输入内容,则data中的message就会改变,message改变,那么p标签的视图就会改变。
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>数据绑定</title>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="message">
<p> {{ message }} </p>
</div>
<script>
const vm = new Vue({
el:'#app',
data:{
message : "v-model双向绑定"
}
})
</script>
</body>
</html>
又或是多选框:
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>practise</title>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<label>
<input type="checkbox" name="hobbies" v-model="hobbies" value="篮球">
篮球
</label>
<label>
<input type="checkbox" name="hobbies" v-model="hobbies" value="健身">
健身
</label>
<label>
<input type="checkbox" name="hobbies" v-model="hobbies" value="数学">
数学
</label>
<p>你的爱好是: {{ hobbies }}</p>
</div>
<script>
const vm = new Vue({
el:'#app',
data:{
hobbies:[]
}
})
</script>
</body>
</html>
多选框的值改变,那么data中的hobbies会改变,Vue又将hobbies渲染到p标签内。
或是下拉列表:
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>practise</title>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<select v-model="checked">
<option value="" disabled selected>---- 请选择 ----</option>
<option>A</option>
<option>B</option>
<option>C</option>
<option>D</option>
</select>
<p>你的选择:{{ checked }}</p>
</div>
<script>
const vm = new Vue({
el:'#app',
data:{
checked:""
}
})
</script>
</body>
</html>
一样的道理。
四、组件
4.1 组件基础
组件是可复用的Vue实例。
先来个例子:
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>组件案例</title>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<click-test></click-test>
<click-test></click-test>
<click-test></click-test>
<click-test></click-test>
<click-test></click-test>
<click-test></click-test>
</div>
<script>
Vue.component('click-test', {
template:"<button @click='count++'>{{ count }}</button>",
data:function (){
return {count:0};
}
})
new Vue({ el:'#app' })
</script>
</body>
</html>
实现了组件复用,一个注意点就是,data要通过函数来返回数据,不然大家共享一个count就会造成很多错误,并且最后别忘了注册组件(new一个Vue)。
再来个稍微复杂点的例子:
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>综合</title>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<try v-for="item in items" :el="item"></try>
</div>
<script>
Vue.component('try', {
props:['el'],
template:`<ul>
<li>{{ el }}</li>
</ul>`
})
new Vue({
el:'#app',
data:{
items : ["vue", 666, '组件']
}
})
</script>
</body>
</html>
props给组件增加属性,在这个例子中相当于要接收的参数,我们将item传给它。
4.2 插槽
在第一个例子中,能记录鼠标点击的次数。但是只有一个数字,假如我们要在数字之前插入数据,这样写是不行的:
<click-test>click times:</click-test>
这个时候,我们应该给这些数据留个插槽(<slot></slot>标签):
Vue.component('click-test', {
template:"<button @click='count++'><slot></slot>{{ count }}</button>",
data:function (){
return {count:0};
}
})
效果:
后备内容:
就是给slot赋一个默认值,如:
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>组件案例</title>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<click-test></click-test>
</div>
<script>
Vue.component('click-test', {
template:"<button @click='count++'><slot>hello:</slot>{{ count }}</button>",
data:function (){
return {count:0};
}
})
new Vue({ el:'#app' })
</script>
</body>
</html>
效果:
如果改成:
<click-test>click times:</click-test>
效果:
具名插槽:
假如现在想在 次数后面添加东西,也就是再加一个插槽,我们可以通过给插槽取名字来区别插槽:
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>组件案例</title>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<click-test>
<template v-slot:pre>
click times:
</template>
<template v-slot:next>
次
</template>
</click-test>
</div>
<script>
Vue.component('click-test', {
template:"<button @click='count++'><slot name='pre'>hello:</slot>{{ count }}<slot name='next'>hi</slot></button>",
data:function (){
return {count:0};
}
})
new Vue({ el:'#app' })
</script>
</body>
</html>
用name给插槽取名字后,在template标签中使用v-slot指令来指定插入哪里。
综合案例:
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>综合</title>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<todo>
<template v-slot:todo-title>
<my-title></my-title>
</template>
<template v-slot:list-items>
<my-list v-for="item in items" :item="item"></my-list>
</template>
</todo>
</div>
<script>
Vue.component('todo', {
template:`<div>
<slot name="todo-title"></slot>
<ul>
<slot name="list-items"></slot>
</ul>
</div>`
});
Vue.component('my-title', {
template: `<h3>Vue如此简单</h3>`
})
Vue.component('my-list', {
props:['item'],
template:`<li> {{ item }} </li>`
})
Vue.component('')
const vm = new Vue({
el:'#app',
data() {
return {
items:["Vue", "js", "simple"]
}
}
});
</script>
</body>
</html>
效果:
v-slot也有简写,可以将v-slot:简写为#:
<div id="app">
<todo>
<template #todo-title>
<my-title></my-title>
</template>
<template #list-items>
<my-list v-for="item in items" :item="item"></my-list>
</template>
</todo>
</div>
五、生命周期
每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
来试试在created和updated的时候添加代码:
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>lifecycle</title>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<button @click="msg++">{{ msg }}</button>
</div>
<script>
new Vue({
el:'#app',
data:{
msg:0
},
created:function () {
alert("Vue实例创建了!")
},
updated:function () {
alert("数据变化了")
}
})
</script>
</body>
</html>
我们在进入页面的时候会弹出:
单击按钮,会弹出:
六、Axios
Axios 是一个基于 promise 网络请求库,作用于
node.js
和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.jshttp
模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。
因为Vue的作者(尤雨溪)注重SoC(关注点分离)原则,关注点在视图层,所以Vue不包含ajax通信功能。官方建议使用axios来通信。
axios有以下特性:
- 从浏览器创建 XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求和响应数据
- 取消请求
- 自动转换JSON数据
- 客户端支持防御XSRF
理论生涩,直接敲码:
现在有这么一个Json文件(模拟向后端请求后返回的数据):
{
"name":"狂神说java",
"url": "http://baidu.com",
"page": 1,
"isNonProfit":true,
"address": {
"street": "含光门",
"city":"陕西西安",
"country": "中国"
},
"links": [
{
"name": "B站",
"url": "https://www.bilibili.com/"
},
{
"name": "4399",
"url": "https://www.4399.com/"
},
{
"name": "百度",
"url": "https://www.baidu.com/"
}
]
}
html:
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>Title</title>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<li v-for="item in message.links">{{ item }}</li>
</div>
<script>
const vm = new Vue({
el:'#app',
data:{
message:null
},
created:function () {
axios.get('/data.json').then(response=>(this.message = response.data))
}
})
</script>
</body>
</html>
我们在Vue实例创建时向/data.json发送一个GET请求,成功后接收返回信息response,通过response.data取出数据并赋值到message中。
data(){return(message:null)} 和 data:{message:null}的区别:
第一种大家都调用同一个函数,但返回的对象是不同的对象。
第二种大家都公用这一个对象,可能造成数据污染。
效果:
七、计算属性
模板内可以写逻辑,比如:
<div id="example">
{{ message.split('').reverse().join('') }}
</div>
一处两处还好,如果大量使用,则难以维护,于是,Vue提供了计算属性。
我将计算属性理解为一个名词,可以被计算的属性,这个属性的值通过函数的返回值赋予:
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>computed</title>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="message">
<p>{{ reverseMessage }}</p>
</div>
<script>
const vm = new Vue({
el:'#app',
data() {
return {
message:"hello"
}
},
computed:{
reverseMessage:function () {
return this.message.split("").reverse().join("");
}
}
})
</script>
</body>
</html>
细节:
计算属性名和methods名不能重复,不然计算属性无效,和data中也不能重复。
计算属性被赋值后,值就会被保存在缓存中,只有在相关的data改变时,它才会改变。
计算属性看起来很像methods,但methods无论是否有相关的data变化,只要data变化,就会重新调用,在某些时候浪费内存。
如:
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>和methods的区别</title>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<input type="text" v-model="message">
<p>{{ time1() }}</p>
<p>{{ time2 }}</p>
</div>
<script>
const vm = new Vue({
el:'#app',
data() {
return {
message:"methods and computed"
}
},
methods:{
time1:function () {
return Date.now();
}
},
computed:{
time2:function () {
// this.message;
return Date.now();
}
}
})
</script>
</body>
</html>
我们将第30行左右的 this.message 注释掉,无论message如何变化,time2始终不变,而time1却一直在变,如果将它打开,那么time1和time2都会在message变化时变化。
八、自定义事件
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>综合</title>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<todo>
<template #todo-title>
<my-title :title="title"></my-title>
</template>
<template #list-items>
<my-list v-for="(item, index) in items" :item="item" :index="index" @delete="remove(index)"></my-list>
</template>
</todo>
</div>
<script>
Vue.component('todo', {
template:`<div>
<slot name="todo-title"></slot>
<ul>
<slot name="list-items"></slot>
</ul>
</div>`
});
Vue.component('my-title', {
props: ['title'],
template: `<h3>{{ title }}</h3>`
})
Vue.component('my-list', {
props:{
item:null,
index:null
},
template:`<li> {{ index }} === {{ item }} <button>remove</button></li>`,
methods: {
}
})
Vue.component('')
const vm = new Vue({
el:'#app',
data() {
return {
items:["Vue", "js", "simple"],
title:"Vue如此简单"
}
},
methods:{
}
});
</script>
</body>
</html>
现在有这么一个组件化的Vue页面,我们如何才能删除其中的元素呢?
都想的到,给remove按钮增加一个事件,然后调用methods里面的方法删除元素。
但是,组件里的方法怎么才能删掉Vue实例里面的data呢?
这个时候自定义事件就有用了:
<!DOCTYPE html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title>综合</title>
<script src="https://unpkg.com/vue@2.6.14/dist/vue.js"></script>
</head>
<body>
<div id="app">
<todo>
<template #todo-title>
<my-title :title="title"></my-title>
</template>
<template #list-items>
<my-list v-for="(item, index) in items" :item="item" :index="index" @delete="remove(index)"></my-list>
</template>
</todo>
</div>
<script>
Vue.component('todo', {
template:`<div>
<slot name="todo-title"></slot>
<ul>
<slot name="list-items"></slot>
</ul>
</div>`
});
Vue.component('my-title', {
props: ['title'],
template: `<h3>{{ title }}</h3>`
})
Vue.component('my-list', {
props:{
item:null,
index:null
},
template:`<li> {{ index }} === {{ item }} <button @click="event">remove</button></li>`,
methods: {
event:function () {
this.$emit('delete')
}
}
})
Vue.component('')
const vm = new Vue({
el:'#app',
data() {
return {
items:["Vue", "js", "simple"],
title:"Vue如此简单"
}
},
methods:{
remove:function (index){
this.items.splice(index, 1);
}
}
});
</script>
</body>
</html>
我们通过this.$emit('delete')
定义一个名为delete的事件并触发,在鼠标点击按钮时,调用event方法创建这个事件,并触发。
触发了前端的delete事件后,调用Vue实例的remove方法,就删除了该数据。
九、Vue-cli
Vue-cli是一个Vue.js的标准开发工具。
9.1 第一个Vue-cli程序
首先需要node环境,可以去node官网下载。
有了node的环境后,就可以把vue-cli下载下来:
npm install vue-cli -g
可以通过vue list命令查看可以选择的模板:
然后在想要创建的目录下输入以下命令(基于webpack模板):
vue init webpack myvue
表示创建一个名为myvue的项目。
接下来他会提示我们设置项目的名字,描述等等,一些选择我选择no,因为想要体验自己创建的感觉。
然后 cd 到刚刚创建的项目下:
npm install
依赖安装完成后,就可以运行了:
npm run dev
然后就可以访问这个url进入项目:
这就是我们的第一个vue-cli程序:
十、 webpack
webpack是一款模块加载器兼打包工具,能把各种资源(JS、JSX、ES6、SASS、LESS、Jpg……)作为模块来处理使用。
10.1 安装webpack
# 安装webpack
npm install webpack -g
# 安装webpack客户端
npm install webpack-cli -g
安装完成后可以用webpack -v来检查是否安装成功。
10.2 使用webpack
-
创建一个项目(创建一个文件夹)
-
在项目中创建一个modules文件夹
-
modules中写几个js文件:
-
hello.js:
exports.sayHi = function () { document.write("<h1>hello world!</h1>>") }
表示暴露这个方法,在其他文件里面可以引入此方法
-
main.js:
var say = require("./hello"); say.sayHi();
引入hello模块,然后就可以调用刚刚暴露的方法。
-
-
根目录下创建webpack配置文件
webpack.config.js:
module.exports = { entry:'./modules/main.js', output:{ filename:"./js/bundle.js" } }
-
在终端执行webpack命令打包项目
-
创建一个index.html测试:
<!DOCTYPE html> <html lang = "en"> <head> <meta charset = "UTF-8"> <title>Title</title> <script src="dist/js/bundle.js"></script> </head> <body> </body> </html>
效果:
十一、vue-router
Vue Router 是 Vue.js 的官方路由。它与 Vue.js 核心深度集成,让用 Vue.js 构建单页应用变得轻而易举。功能包括:
- 嵌套路由映射
- 动态路由选择
- 模块化、基于组件的路由配置
- 路由参数、查询、通配符
- 展示由 Vue.js 的过渡系统提供的过渡效果
- 细致的导航控制
- 自动激活 CSS 类的链接
- HTML5 history 模式或 hash 模式
- 可定制的滚动行为
- URL 的正确编码
说起来吓人,我们先来看看基础用法:
先用vue-cli创建一个vue项目,如果没有安装vue-router的话,就安装:
npm install vue-router@3
因为是vue2.x版本所以对应vue-router3.x版本。
然后就可以开始了:
-
在components下写个组件:
<template> <h2>终于搞懂路由了</h2> </template> <script> export default { name: "yang" } </script> <style scoped> </style>
-
在src目录下创建router目录,在router目录下创建路由配置文件index.js:
import Vue from 'vue'; import VueRouter from "vue-router"; import yang from "../components/yang"; Vue.use(VueRouter); export default new VueRouter({ routes: [ { path:'/yang', component:yang } ] });
关键:引入vue、vue-router以及需要路由到的组件。
-
到main.js中引入配置文件:
import Vue from 'vue' import App from './App' import router from "./router"; Vue.config.productionTip = false new Vue({ el: '#app', router, components: { App }, template: '<App/>' })
导入文件夹就可以了,会自动扫描配置文件。
-
到App.vue中使用:
<template> <div id="app"> <h1>Vue-router</h1> <router-link to="/yang">点我</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>
router-link和router-view缺一不可,router-link表示跳转到哪个组件,router-view表示这个组件的视图显示的位置。
-
效果:
当然,还可以配置多个路由,只需要添加组件、在index.js中配置路由、在App.vue中使用就完事了。
十二、Element UI
Element-UI和Vue配合可以快速写出好看的页面。
-
创建vue项目
-
安装依赖
npm install
-
安装vue-router
npm install vue-router
-
安装element-ui
npm i element-ui -S
-
安装sass
npm install sass-loader node-sass
准备完毕,就可以开始使用了:
-
创建首页的组件Main
<template> <h1>首页</h1> </template> <script> export default { name: "Main" } </script> <style scoped> </style>
-
到element-ui中复制一个登录组件稍作修改:
<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>
-
在src下创建router目录,在router下创建index.js配置文件:
import Vue from 'vue'; import VueRouter from "vue-router"; import Main from "../components/Main"; import Login from "../components/Login"; Vue.use(VueRouter); export default new VueRouter({ routes:[ { path:'/main', component:Main }, { path:'/login', component:Login } ] })
-
在main.js中引入需要使用的模块:
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) })
-
在App.vue中使用:
<template> <div id="app"> <router-view></router-view> </div> </template> <script> export default { name: 'App' } </script> <style> </style>
-
启动项目,访问/login:
npm run dev
可以尝试输入点什么或是不输入,有不同的提示哦。
十三、参数传递、重定向
13.1 接收参数两种方式
传递参数有多种方式,这里说两种。
- 第一种,通过绑定to,to传递参数对象给组件,组件取出参数:
Main.vue中的关键改动:
<router-link :to="{name:'UserProfile', params:{id: 1}}">
<el-menu-item index="1-1">
个人信息
</el-menu-item>
</router-link>
index.js:
{
path:'/user/profile/:id',
name:'UserProfile',
component:UserProfile
}
profile.vue取值:
<template>
<div>
<h1>个人信息</h1>
{{ $route.params.id }}
</div>
</template>
<script>
export default {
name: "UserProfile"
}
</script>
<style scoped>
</style>
-
传递是一样的,这次可以通过props取值,不用再{{ $route.params.id }}这种方式
只需要更改一下配置:
{ path:'/user/profile/:id', name:'UserProfile', component:UserProfile, props:true }
然后再profile中这样取值:
<template> <div> <h1>个人信息</h1> {{ id }} </div> </template> <script> export default { props:['id'], name: "UserProfile" } </script> <style scoped> </style>
效果都是一样的:
13.2 重定向
配置一下redirect到哪就完事了:
增加一个返回首页的按钮:
<router-link to="/goHome">
<el-menu-item index="1-3">返回首页</el-menu-item>
</router-link>
配置 /goHome 重定向到 /main
{
path:'/goHome',
redirect:'/main'
}
成功
十四、添加404页面、路由钩子
-
添加404页面:
也就是添加一个404的组件,然后在访问不存在的地址的时候展示:
404.vue:
<template> <div> <h1>404 not found</h1> <hr/> </div> </template> <script> export default { name: 'NotFound' } </script> <style scoped> div { text-align: center; } </style>
配置:
{ path:'/*', component:NotFound }
这样就可以在访问一些不存在的页面的时候展示404页面。
我们可以注意到url上始终有个#号,我们只需要在配置中加上mode:"history"就ok:
index.js
export default new VueRouter({ mode:"history", routes:[ { path:'/main/:name', props:true, component:Main, children:[ { path:'/user/profile/:id', name:'UserProfile', component:UserProfile, props:true }, { path:'/user/list', component:UserList }, { path:'/goHome', redirect:'/main' } ] }, { path:'/', component:Login }, { path:'/*', component:NotFound } ] })
-
路由钩子
之前我们学习了很多生命周期钩子,路由也有钩子,我们可以在进入路由前或是离开路由前等等情况下添加操作,比如进入路由前使用axios请求数据:
我们先模拟一个数据,放在static/mock下:
data.json:
{ "name":"狂神说java", "url": "http://baidu.com", "page": 1, "isNonProfit":true, "address": { "street": "含光门", "city":"陕西西安", "country": "中国" }, "links": [ { "name": "B站", "url": "https://www.bilibili.com/" }, { "name": "4399", "url": "https://www.4399.com/" }, { "name": "百度", "url": "https://www.baidu.com/" } ] }
然后
写一个axios请求该数据,并且输出在控制台的方法,然后在路由钩子中调用它:
<template> <div> <h1>个人信息</h1> {{ id }} </div> </template> <script> import axios from "axios"; export default { props:['id'], name: "UserProfile", beforeRouteEnter:function (to, from, next) { console.log("进入路由前") next(vm => (vm.getData())) }, beforeRouteLeave:function (to, from, next) { console.log("离开路由前") next() }, methods:{ getData:function () { axios.get("http://localhost:8080/static/mock/data.json").then(response=>(console.log(response.data))) } } } </script> <style scoped> </style>
测试成功。
既然能够在控制台输出,自然也能展示到页面上等等。