Vue.js学习
1、概念和特点
- 概念:Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式JavaScript框架。 与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合。发布时间为2014年2月。
- 特点
- 更加轻量20kb min + gzip
- 渐进式框架
- 响应式的更新机制
- 学习成本低
2、MVVM模式的实现者
-
Model:模型层,在这里表示avaScript对象
-
View:视图层,在这里表示DOM(HTML操作的元素)
-
ViewModel:连接视图和数据的中间件,Vue.js就是MVVM中ViewModel的实现者
在MVVM架构中,是不允许数据和视图直接通信的,只能通过ViewModel来通信,而ViewModel就是定义了一个Observer观察者 -
ViewModel能够视察到数据的变化,并对视图对应的内容进行更新
-
ViewModel能够监听到视图的变化,并能够通知数据发生改变
3、Vue基本语法
带有前缀v-的被称为指令,以表示它们是Vue提供的体术属性,它们会在渲染的DOM上应用特殊的响应式行为,该指令的意思是“将这个元素节点的title特性和Vue实例的message属性保持一致”
如果再次打开浏览器的JavaScript控制台,输入app.message="新消息",就会再一次看到这个绑定了title特性的HTML已经进行了更新。
- v-bind
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
{{message}}<br/>
<span v-bind:title="message">消息</span>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var vm = new Vue({
el:"#app",
data:{
message:"Hello Vue!!!"
}
});
</script>
</body>
</html>
- v-if和v-else
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<span v-if="status">成功</span>
<span v-else>失败</span>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var vm = new Vue({
el:"#app",
data:{
status:true
}
});
</script>
</body>
</html>
- v-for
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<div v-for="arr in arrs">
{{arr.message}}
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var vm = new Vue({
el:"#app",
data:{
arrs:[
{message:"啦啦啦"},
{message:"哈哈哈"}
]
}
});
</script>
</body>
</html>
4、Vue绑定事件(v-on)
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>绑定事件</title>
</head>
<body>
<div id="app">
<button v-on:click="alertMsg">点我</button>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var vm = new Vue({
el:"#app",
data:{
message:"hahaha"
},
methods:{
alertMsg:function (event) {
alert(this.message);
}
}
});
</script>
</body>
</html>
5、Vue双向绑定(v-model)
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>双向绑定</title>
</head>
<body>
<div id="app">
请输入内容:
<input type="text" v-model="message"/><br/>
输入的内容为:{{message}}
<br/><br/>
性别:<input type="radio" name="sex" value="男" v-model="checked"/>男
<input type="radio" name="sex" value="女" v-model="checked"/>女
<br/>
选择的性别为:{{checked}}
<br/><br/>
兴趣爱好:
<select v-model="selected">
<option value="" disabled>--请选择--</option>
<option>羽毛球</option>
<option>钢琴</option>
</select>
<br/>
选择的兴趣爱好为:{{selected}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var vm = new Vue({
el:"#app",
data:{
message:"121",
checked:"男",
selected:""
},
methods:{
}
});
</script>
</body>
</html>
注意:v-model会忽略所有表单元素的value、checked、selected特性的初始值,而总是将Vue实例的数据作为数据来源。你应该通过JavaScript在组件的data选项中声明初始值
6、Vue组件
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>组件</title>
</head>
<body>
<div id="app">
<my-component v-for="hobby in hobbys"></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
Vue.component("my-component",{
template:"<li>{{hobby}}</li>"
});
var vm = new Vue({
el:"#app",
data:{
hobbys:["钢琴","篮球","羽毛球"]
}
});
</script>
</body>
</html>
说明:
- Vue.component():注册组件
- my-component:自定义组件的名字
- template:组件的模板
- 使用props属性传递参数
向上面那样用组件没有任何意义,所以我们是需要传递参数到组件的,此时就需要使用props属性了。
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>组件</title>
</head>
<body>
<div id="app">
<my-component v-for="hobby in hobbys" v-bind:test="hobby"></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
Vue.component("my-component",{
props:["test"],
template:"<li>{{test}}</li>"
});
var vm = new Vue({
el:"#app",
data:{
hobbys:["钢琴","篮球","羽毛球"],
test:""
}
});
</script>
</body>
</html><!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>组件</title>
</head>
<body>
<div id="app">
<!--通过v-bind绑定一个变量,把hobyy变量对应的数据传递到自定义的组件,自定一的组件通过props来接收传过来的数据-->
<my-component v-for="hobby in hobbys" v-bind:test="hobby"></my-component>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
Vue.component("my-component",{
props:["test"],
template:"<li>{{test}}</li>"
});
var vm = new Vue({
el:"#app",
data:{
hobbys:["钢琴","篮球","羽毛球"],
test:""
}
});
</script>
</body>
</html>
7、Axios异步通信
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中,是基于ajax的异步通信。
特性:
- 从浏览器中创建 XMLHttpRequests
- 从 node.js 创建 http 请求
- 支持 Promise API
- 拦截请求和响应
- 转换请求数据和响应数据
- 取消请求
- 自动转换 JSON 数据
- 客户端支持防御 XSRF
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>组件</title>
</head>
<body>
<div id="app">
<div>{{info.name}}</div>
<div>{{info.address.street}}</div>
<a v-bind:href="info.link">点我</a>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
var vm = new Vue({
el:"#app",
data(){
//返回的只是数据的格式
return{
info:{
name:null
}
}
},
mounted(){//使用钩子函数
axios.get("../data.json").then(response=>(this.info=response.data))
}
});
</script>
</body>
</html>
8、计算属性
- 计算出来的结果,保存在属性中
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>组件</title>
</head>
<body>
<div id="app">
currentTime1:{{currentTime1()}}<br/>
currentTime2:{{currentTime2}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
var vm = new Vue({
el:"#app",
data:{
message:""
},
methods:{
currentTime1:function (event) {
return Date.now();
}
},
computed:{
currentTime2:function (event) {
return Date.now();
}
}
});
</script>
</body>
</html>
说明:
- methods:定义方法,调用方法使用currentTime1(),需要带括号
- computed:定义计算属性,调用属性使用currentTime2,不需要带括号;this.message是为了能够让currentTime2观察到数据变化而变化
- 如果在方法中的值发生了变化,则缓存就会刷新。可以在控制台使用vm.message="zixin",改变下数据的值,再次测试观察效果
结论:
调用方法时,每次都需要进行计算,既然有计算过程则必定产生系统开销,那如果这个结果是不经常变化的,此时就可以考虑将这个结果缓存起来,采用计算属性可以很方便的做到这一点,计算属性的主要特性就是为了将不经常变化的计算结果进行缓存,以节约我们的系统开销。
9、插槽slot
在Vue.js中我们使用<slot>
元素作为分发内容的出口,称为插槽,可以用用在组合组件的场景中。
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>slot插槽</title>
</head>
<body>
<!--将在父模板中定义的值通过插槽插入子模版中-->
<div id="app">
<father>
<son-title slot="son-title" v-bind:title="title"></son-title>
<son-item slot="son-item" v-for="it in items" v-bind:item="it"></son-item>
</father>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
//定义父模板
Vue.component("father",{
template:'<div>'+
'<slot name="son-title"></slot>' +
'<ul>'+
'<slot name="son-item"></slot>'+
'</ul>' +
'</div>'
});
//子模版:标题
Vue.component("son-title",{
props:["title"],
template:"<p>{{title}}</p>"
});
//子模版:列表
Vue.component("son-item",{
props:["item"],
template: "<li>{{item}}</li>"
});
var vm = new Vue({
el:"#app",
data:{
message:"",
title:"兴趣爱好",//标题
item:"",
items:["羽毛球","篮球","钢琴"]//列表数据
}
});
</script>
</body>
</html>
10、自定义事件内容分发
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>事件分发</title>
</head>
<body>
<div id="app">
<father>
<son-title slot="son-title" v-bind:title="title"></son-title>
<son-item slot="son-item" v-for="(it,index) in items" :item="it" :key="index" :index="index"></son-item>
</father>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
Vue.component("father",{
template:'<div>'+
'<slot name="son-title"></slot>' +
'<ul>'+
'<slot name="son-item"></slot>'+
'</ul>' +
'</div>'
});
Vue.component("son-title",{
props:["title"],
template:"<p>{{title}}</p>"
});
Vue.component("son-item",{
props:["item","index"],
template: "<li>{{item}}<button v-on:click='removeItem(index)'>删除</button></li>"
});
var vm = new Vue({
el:"#app",
data:{
message:"",
title:"兴趣爱好",
item:"",
items:["羽毛球","篮球","钢琴"]
},
methods:{
removeItem:function (index) {
console.log("要删除的为"+this.items[index]);
}
}
});
</script>
</body>
</html>
通过上面的代码不难发现,数据项在Vue的实例中,但删除操作要在组件中完成,那么组件如何才能删除Vue实例中的数据呢?此时就涉及到参数传递与事件分发了,Vue为我们提供了自定义事件的功能 ,很好地帮助了我们解决了这个问题:使用this.$emit('自定义事件名',参数),操作过程如下:
- 在Vue的实例中,增加了methods对象并定义了一个名为removeItem的方法
removeItem:function (index) {
console.log("要删除的为"+this.items[index]);
this.items.splice(index, 1);
}
- 修改son-item代办内容组件的代码,增加一个删除按钮,并绑定事件
template: "<li>{{item}}<button type='button' v-on:click='butClick(index)'>删除</button></li>",
- 修改son-item代办内容组件的HTML代码,增加一个自定义事件,比如叫butClick,可以和组件的方法绑定,然后绑定到Vue的方法中
methods:{
butClick:function (index) {
this.$emit('remove', index);
}
}
<son-item slot="son-item" v-for="(it,index) in items" v-bind:item="it" v-bind:key="index" v-bind:index="index" v-on:remove="removeItem(index)"></son-item>
全部代码:
<!DOCTYPE html>
<html lang="en" xmlns:v-bind="http://www.w3.org/1999/xhtml" xmlns:v-on="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>事件分发</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
</head>
<body>
<div id="app">
<father>
<son-title slot="son-title" v-bind:title="title"></son-title>
<son-item slot="son-item" v-for="(it,index) in items" v-bind:item="it" v-bind:key="index" v-bind:index="index" v-on:remove="removeItem(index)"></son-item>
</father>
</div>
<script>
Vue.component("father",{
template:'<div>'+
'<slot name="son-title"></slot>' +
'<ul>'+
'<slot name="son-item"></slot>'+
'</ul>' +
'</div>'
});
Vue.component("son-title",{
props:["title"],
template:"<p>{{title}}</p>"
});
Vue.component("son-item",{
props:["item","index"],
template: "<li>{{item}}<button type='button' v-on:click='butClick(index)'>删除</button></li>",
methods:{
butClick:function (index) {
this.$emit('remove', index);
}
}
});
var vm = new Vue({
el:"#app",
data:{
message:"",
title:"兴趣爱好",
item:"",
items:["羽毛球","篮球","钢琴"]
},
methods:{
removeItem:function (index) {
console.log("要删除的为"+this.items[index]);
this.items.splice(index, 1);
}
}
});
</script>
</body>
</html>
11、第一个vue-cli程序
准备工作
-
下载和安装Node.js
官网下载后打开文件,然后无脑下一步,即可安装完成。 -
检查Node.js是否安装成功
在控制台输入node -v与npm -v,若输出版本号表示安装成功 -
安装Node.js淘宝镜像加速器(cnpm)
Node.js有时候下载会很慢,下载淘宝加速器,下载会快很多
# -g 全局安装,在全局环境下都能使用
npm install cnpm -g
# 或每次需要用到淘宝加速器的时候手动添加如下语句解决npm速度慢的问题
npm install --registry=https://registry.npm.taobao.org
建议npm下载失败再用cnpm下载,因为cnpm下载的文件有时候会出问题
- 安装vue-cli
cnpm install vue-cli -g
#测试是否安装成功
#查看可以基于那些模块创建vue应用程序,通常我们选择webpack
vue list
创建项目步骤
-
创建一个Vue项目,我们随便建立一个空的文件夹在电脑上,我这里在F盘下新建一个目录
F:\ideaworkplace\vuestudy
-
创建一个基于webpack模板的vue应用程序
#这里的myvue时项目名称,可以根据自己的需求起名
vue init webpack myvue
一路都选择no即可
说明:
- Project name:项目名称,默认回车即可
- Project description:项目描述,默认回车即可
- Author:作者
- Vue build:vue构建方式
- Install vue-router:是否安装路由
- Use ESLint to lint your code:使用ESLint对代码进行规范
- Set up unit tests:是否设置单元测试
- Setup e2e tests with Nightwatch:是否使用Nightwatch设置e2e
- Should we run
npm install
for you after the project has been created? (recommended):是否在工程创建后就去跑 npm 安装依赖
创建好的项目目录
- 初始化项目并运行
cd myvue
npm install
npm run dev
-
先执行前面两个命令,下载依赖
-
执行完成后,目录多了很多依赖
-
再执行
npm run dev
运行项目
-
运行成功页面如下
12、webpack学习使用
- 安装
npm install webpack -g
npm install webpack-cli -g
- 测试是否安装成功
- webpack -v
- webpack-cli -v
- 配置
创建webpack.config.js
配置文件
- entry:入口文件,指定WebPack用那个文件作为项目的入口
- output:输出,指定WebPack把处理完成的文件防止到指定路径
- module:模块,用于处理各种类型的文件
- plugins:插件,如:热更新、代码重用等
- resovle:设置路径指向
- watch:监听,用于设置文件改动后直接打包
modules.exports = {
entry:"",
output:{
path:"",
filename:""
},
modules:{
loaders:{
{test:/\.js$/,loader:""}
}
},
plugins:{},
resolve:{},
watch:true
}
- 使用webpack
- 创建一个项目(空文件夹,用idea打开)
- 创建一个名为modules的目录,用于放置JS模块等资源文件
- 在modules下创建模块文件,如hello.js,用于编写JS模块相关代码
//暴露一个方法
exports.sayHi = function(){
document.write("<div>Hello WebPack!</div>")
}
- 在modules下创建一个名为main.js的入口文件,用于打包时设置entry属性
//require导入一个模块,就可以调用这个模块中的方法了
var hello = require("./hello");
hello.sayHi();
- 在项目目录下创建webpack.config.js配置文件
module.exports = {
entry:"./modules/main.js",
output:{
filename:"./js/bundle.js"
}
};
-
直接运行webpack命令打包
-
项目中多个一个dist文件夹,里面存放刚刚打包的js文件
-
编写一个index.html页面,同时引入刚刚打包好的js文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>测试引入打包后的js文件</title>
<script src="dist/js/bundle.js"></script>
</head>
<body>
</body>
</html>
- 运行index.html文件,看效果
13、vue-router路由
- 概念
Vue Router是Vue.js官方的路由管理器。它和Vue.js的核心深度集成,让构建单页面应用变得易如反掌,包含的功能有:
- 嵌套的路由/视图表
- 模块化的、基于组件的路由配置
- 路由参数、查询、通配符
- 基于Vue.js过渡系统的视图过度效果
- 细粒度的导航控制
- 带有自动激活的CSS class的链接
- HTML5历史模式或hash模式,在IE9中自动降级
- 自定义的滚动行为
- 安装
基于第一个vue-cli进行测试学习,先查看node_modules中是否存在vue-router
vue-router是一个插件包,所以需要用npm/cnpm来进行安装的。打开命令行工具,进入项目目录,输入下面命令。
npm install vue-router --save
此时遇到安装失败如下
原因是npm版本过高,此时需要降低npm的版本,执行执行下面命令
#安装低版本的npm
npm install npm@6.14.10 -g
注意:如果在一个模块化工程中使用它,必须要通过Vue.use()明确地安装路由功能
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter);
- 测试
- 先删除没有用的东西
- components目录下存放我们自己编写的组件
- 定义一个Content.vue组件
<template>
<div>
<h1>内容页</h1>
</div>
</template>
<script>
export default {
name:'Content'
}
</script>
<style scoped>
</style>
- 定义一个Main.vue组件
<template>
<div>
<h1>首页</h1>
</div>
</template>
<script>
export default {
name: "Main"
}
</script>
<style scoped>
</style>
- 安装路由,在src目录下,新建一个文件夹:router,专门存放路由,在下面创建一个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:[
{
//路由路径
path:'/content',
name:'content',
//跳转的组件
component:Content
},
{
path: '/main',
name:'main',
component: Main
},
]
});
- 在main.js中配置路由
import Vue from 'vue'
import App from './App'
//自动扫描里面的路由配置
import router from './router'
Vue.use(router);
new Vue({
el: '#app',
//配置路由
router,
render:h=>h(App)
});
- 在App.vue中使用路由
<template>
<div id="app">
<h1>路由首页</h1>
<router-link to="/main">首页</router-link>
<router-link to="/content">内容页</router-link>
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'App',
components: {
}
}
</script>
<style>
</style>
- 测试,发现了下面的错误
问题原因:安装了最新的vue-router,版本大概是4.0.12,我最开始安装vuecli没有指定版本
解决方法:降低vue-router的版本,这里我换成了3.0.1
#卸载新版本的vue-router
npm uninstall vue-router
#安装指定版本的vue-router
npm i vue-router@3.0.1
- 重新运行,得到如下运行成功的页面
14、vue+elementUI
创建工程(命令行都要使用管理员模式运行)
-
创建一个名为hellovue的工程
vue init webpack hellovue
-
安装依赖,我们需要安装vue-router、element-ui、sass-loader和node-sass四个插件
#进入工程目录
cd hellovue
#安装vue-router
npm install vue-router --save
#安装element-ui
npm i element-ui -S
#安装依赖
npm install
#安装sass加载器
cnpm install sass-loader node-sass --save-dev
#启动测试
npm run dev
- npm命令解释
npm install moduleName
:安装模块到项目目录下npm installl -g moduleName
:-g的意思是将模块安装到全局,具体安装到磁盘那个位置,要看npm config prefix的位置npm install -save moduleName
:--save的意思是将模块安装到项目目录下,并在package文件的dependencies节点写入依赖,-S为该命令的缩写npm install --save-dev moduleName
:--save-dev的意思是将模块安装到项目目录下,并在package文件的devDependencies节点写入依赖,-D为该命令的缩写
-
用idea打开项目,并删除多余的东西,重新使用
npm run dev
运行项目,运行结果如下
-
测试
- Login.vue
<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>
- 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>
<e1-menu-item-group>
<el-menu-item index="2-1">分类管理</el-menu-item>
<el-menu-item index="2-2">内容列表</el-menu-item>
</e1-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 lang="scss">
.el-header {
background-color: #048bd1;
color: #333;
line-height: 60px;
}
.el-aside {
color: #333;
}
</style>
- Profile.vue
<template>
<div>
<h1>个人信息</h1>
</div>
</template>
<script>
export default {
name: "Profile"
}
</script>
<style scoped>
</style>
- UserList.vue
<template>
<div>
<h1>用户列表</h1>
</div>
</template>
<script>
export default {
name: "UserList"
}
</script>
<style scoped>
</style>
- index.js
import Vue from 'vue'
import Router from 'vue-router'
//引入组件
import Main from "../components/Main";
import Login from "../components/Login";
import Profile from "../components/user/Profile";
import UserList from "../components/user/UserList";
//安装路由
Vue.use(Router);
let router = new Router({
routes:[
{
path:'/main',
name:'Main',
component:Main,
children:[
{
path:'/user/profile',
name:'Profile',
component:Profile,
},
{
path:'/user/list',
name:'UserList',
component:UserList,
}
]
},
{
path: '/login',
name:'Login',
component: Login
}
]
});
export default router
- main.js
import Vue from 'vue'
// import {createApp} from 'vue'
import App from './App'
//引入element-ui
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
//引入路由
import router from './router';
//
Vue.use(ElementUI);
Vue.use(router);
new Vue({
el: '#app',
router,
render: h => h(App)
});
- App.vue
<template>
<div id="app">
<router-view/>
</div>
</template>
<script>
export default {
name: 'App'
}
</script>
<style>
</style>
运行时遇到问题
原因:因为node-loader版本过高导致的问题,我们尝试将版本降低到@4.14.1
解决方法:直接使用命令:npm install sass-loader@4.14.1 --save-dev
降低版本号,再进行npm run dev即可运行
15、路由嵌套
- 如上面的Main.vue页面中代码,点击这些链接,右边显示对应的页面
<!--导航栏:用于在右边显示不同的页面->
<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-main>
<router-view/>
</el-main>
- 在router目录下的index.js中的routes数组,在component为Main中添加如下代码
children:[
{
path:'/user/profile',
name:'Profile',
component:Profile,
},
{
path:'/user/list',
name:'UserList',
component:UserList,
}
]
注意:必须要引入对应的组件
16、参数传递及重定向
- 参数传递
方式一
- 将Main.vue中的个人信息链接改成下面代码:
<!--有参数时,必须使用对象,同时to必须绑定-->
<router-link :to="{name:'Profile',params:{id:1}}">个人信息</router-link>
- index.js中Profile组件的代码修改为如下:
{
path:'/user/profile/:id',
name:'Profile',
component:Profile,
},
注意:参数名必须与传过来的一致
- 重新运行,运行结果与预期一致
方式二
- 在Login.vue中的onSubmit方法跳转到main页面时添加参数:
onSubmit(formName) {
//为表单绑定验证功能
this.$refs[formName].validate((valid) => {
if (valid) {
//使用vue-router路由到指定页面,该方式称之为编程式导航
this.$router.push("/main/"+this.form.username);
} else {
this.dialogVisible = true;
return false;
}
});
},
- 在路由主文件中的Main路由对象中,开启props,同时在path的后面添加/:name
{
path:'/main/:name',
name:'Main',
component:Main,
props:true,
children:[
{
path:'/user/profile/:id',
name:'Profile',
component:Profile,
},
{
path:'/user/list',
name:'UserList',
component:UserList,
},
{
path:'/goTop',
redirect:'/main'
}
]
},
{
path: '/login',
name:'Login',
component: Login
},
{
path: '*',
name:'NotFound',
component: NotFound
}
- 在Main.vue页面中接收参数
<script>
export default {
name: "Main",
props:["name"]
}
</script>
- 显示在页面中
<span>{{name}}</span>
- 重新运行,运行结果与预期一致
- 重定向
- 在Main.vue中添加一个子菜单栏
<el-submenu index="3">
<template slot="title"><i class="el-icon-caret-right"></i>系统管理</template>
<e1-menu-item-group>
<el-menu-item index="3-1">
<router-link to="/goTop">回到首页</router-link>
</el-menu-item>
</e1-menu-item-group>
</el-submenu>
- 在index.js中的children中添加如下代码
{
path:'/goTop',
redirect:'/main'
}
- 重新运行,点击回到首页链接,成功跳转
17、404和路由钩子
路由模式有两种
- hash:路径带#符号,http://localhost:8080/#/login
- history:路径不带#,http://localhost:8080/login
修改路由配置,代码如下:
export default new VueRouter({
mode:'history',
routes:[
]
})
处理404
- 在component文件夹下创建一个名为NotFound.vue的视图组件,代码如下:
<template>
<div>
页面不存在,请重试
</div>
</template>
<script>
export default {
name:'NotFound'
}
</script>
<style scoped>
</style>
- 在路由的主文件index.js中添加如入代码
{
path: '*',
name:'404',
component: NotFound
}
18.路由钩子与异步请求
- 路由钩子
beforeRouteEnter:在渲染该组件的第一营路由被confirm前调用,不能获取组件实例this
,因为当守卫执行前,组件实例还没被创建
beforeRouteLeave:导航离开该组件的对应路由时调用,可以访问组件实例this
-
to: Route: 即将要进入的目标路由对象
-
from: Route: 当前导航正要离开的路由
-
next:理由的控制参数
- next():跳入下一个页面
- next('/path'):改变路由的跳转方向,使其跳到另一个路由
- next(false):返回原来的页面
- next((vm)=>{})仅在beforeRouteEnter中可用,vm使组件实例
测试:
- 在Profile组件中添加两个钩子函数
<template>
<div>
<h1>个人信息</h1>
{{$route.params.id}}
</div>
</template>
<script>
export default {
name: "Profile",
beforeRouteEnter(to, from, next){
console.log("进入组件时路由调用");
next();
},
beforeRouteLeave(to, from, next){
console.log("离开组件时路由调用");
next();
}
}
</script>
- 运行测试
点击个人信息链接时执行beforeRouteEnter,点击其他链接时执行beforeRouteLeave
- 在钩子函数中使用异步请求
- 安装Axios
cnpm install axios --save
- 在main.js中引用Axios
import axios from 'axios'
// axios需要使用prototype将axios挂载到原型上 ,$后面是自己另起的名称,以后就可以使用该名称
Vue.prototype.axios = axios;
- 准备数据:只有我们的static目录下的文件是可以被访问到的,所以我们把静态文件放入该目录下
//静态数据存放的位置
static/jsondata/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/"
}
]
}
- 在Profile.vue页面中的methods{}中添加一个getData方法
methods:{
getData(){
this.axios({
method:'get',
url:'http://localhost:8080/static/jsondata/data.json'
}).then(response=>{
console.log(response);
})
}
}
- 在beforeRouteEnter中进行异步请求
beforeRouteEnter(to, from, next){
console.log("进入组件时路由调用");
next((vm)=>{
vm.getData();
});
},
- 运行测试,遇到下面的问题
原因是:将this.axios写成了this.$axios
修改后成功获取到数据