1.设计模式
MVVM(Model-View-ViewModel)是一种软件设计模式,是一种简化用户界面的事件驱动编程方式。
MVVM源自于经典的MVC(Model-View-Controller)模式。MVVM的核心是ViewModel层,负责转换Model中的数据对象来让数据变得更容易管理和使用。其作用如下:
- 该层向上与视图层进行双向数据绑定
- 向下与Model层通过接口请求进行数据交互
- MVVM模式和MVC模式一样,主要目的是分离视图(View)和模型(Model)
View是视图层, 也就是用户界面
Model是指数据模型, 泛指后端进行的各种业务逻辑处理和数据操控, 主要围绕数据库系统展开。这里的难点主要在于需要和前端约定统一的接口规则.
ViewModel是由前端开发人员组织生成和维护的视图数据层。View Model所封装出来的数据模型包括视图的状态和行为两部分, 而Model层的数据模型是只包含状态的
实现了双向绑定, View Model的内容会实时展现在View层, 这是激动人心的, 因为前端开发者再也不必低效又麻烦地通过操纵DOM去更新视图。
Vue.js就是一个MV VM的实现者, 他的核心就是实现了DOM监听与数据绑定
2.vue
在idea中记得下载vue.js插件,这样新建的时候就有vue component选项
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--view层,模板-->
<div id="app">
{{message}}
</div>
<!--1.导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
/*Model:数据*/
data:{
message:"hello,vue!"
}
});
</script>
</body>
</html>
我们新建一个vue对象 var v = new Vue();然后在括号里面添加花括号就可以写东西了。
el:"",是与标签进行双向绑定;data是对象,所以要用花括号包括起来,然后我们可以在里面放数据,这样前端也可以自己有数据,而不用去后端拿。
2.1基本语法
2.1.1 v-bind
绑定元素特性
<!--view层,模板-->
<div id="app">
<span v-bind:title="message">
鼠标悬停几秒钟查看此处动态绑定的提示信息!
</span>
</div>
2.1.2 v-if v-else-if v-else
<div id="app">
<h1 v-if="type==='a'">A</h1>
<h1 v-else-if="type==='b'">B</h1>
<h1 v-else>K</h1>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
var vm = new Vue({
el:"#app",
data: {
type: 'a'
}
});
2.1.3 v-for
注意{{item}},引用即用双花括号包围起来,其中item是数组的单一元素,而items则是数组。
<div id="app">
<li v-for="(item,index) in items">
{{item.message}}---{{index}}
</li>
</div>
<!--1.导入Vue.js-->
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
/*Model:数据*/
data:{
items:[
{message:'狂神说Java'},
{message:'狂神说前端'},
{message:'狂神说运维'}
]
}
});
2.1.4 v-on
注意:this即表示这个对象,而且定义方法要用methods,然后用花括号括起来,之后就可以在里面写方法,即方法名:funtion(event){},记得在括号中加入响应事件event.
<div id="app">
<button v-on:click="sayHi">点我</button>
</div>
<script src="../js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
message:'Hello World'
},
methods:{
sayHi:function(event){
//'this'在方法里面指向当前Vue实例
alert(this.message);
}
}
});
2.1.5 v-model
数据双向绑定, 即当数据发生变化的时候, 视图也就发生变化, 当视图发生变化的时候,数据也会跟着同步变化。
v-model
会忽略所有表单元素的value
、checked
、selected
特性的初始值而总是将Vue
实例的数据作为数据来源。
v-model="";这里面填的即为data中的某个属性,之后就会与其双向绑定,并且可以调用
input标签中的type="radio"是单选框
<div id="app">
性别:
<input type="radio" v-model="sex" value="男" > 男
<input type="radio" v-model="sex" value="女"> 女
<br>
你的性别是:{{sex}}
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
var vm = new Vue({
el:"#app",
data: {
sex: ''
}
});
</script>
复选框
input标签中checkbox这类型说明是选择框,id则是与下面的label相关联,当我们勾选的时候,他就会将value值放入v-model相关量的data数据中去。
<div id="app">
多复选框:
<input type="checkbox" id="oneman" value="Jack" v-model="checkedNames">
<label for="oneman">Jack</label>
<br>
<span>选中的值:{{checkedNames}}</span>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
var vm = new Vue({
el:"#app",
data:{
checkedNames:[]
}
});
</script>
下拉框
<div id="app">
下拉框:
<select v-model="pan">
<option value="" disabled>---请选择---</option>
<option>A</option>
<option>B</option>
<option>C</option>
<option>D</option>
</select>
<span>value:{{pan}}</span>
</div>
<script src="../js/vue.js"></script>
<script type="text/javascript">
var vm = new Vue({
el:"#app",
data:{
pan:"A"
}
});
3.组件
3.1定义
组件是可复用的Vue
实例, 说白了就是一组可以重复使用的模板
组件一般也是写在script中,然后要先注册,类似于方法,前面是标签名,后面再花括号中添加template模板。
<body>
<div id="app">
<pan></pan>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
//先注册组件
Vue.component("pan",{
template:'<li>Hello</li>'
});
//实例话vue
var vm = new Vue({
el:"#app",
});
</script>
</body>
3.2往组件中传参数
<div id="app">
<pan v-for="item in items" v-bind:damage="item"></pan>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
//先注册组件
Vue.component("pan",{
props:['damage'],
template:'<li>{{damage}}</li>'
});
//实例话vue
var vm = new Vue({
el:"#app",
data: {
items: ["pig","dog","panda"]
}
});
组件没有办法直接从实例化vue中拿数据,故需要一个props:['']
v-for="item in items"这个是从data中获得数据,遍历Vue
实例中定义的名为items
的数组,并创建同等数量的组件
v-bind:damage="item" 这个中的damage实际是id,即是填在props:['']中的值
然后这个item是遍历出来的数据都与damage相关联,也可以理解为两者相等
将遍历的item
项绑定到组件中props
定义名为damage
属性上
4.Axios异步通信
Axios可以用在浏览器端和Node JS
的异步通信框架。
这里的data(),mounted()都是函数来着,而且在data函数中格式是一定的,即return{info{}}
mounted()中调用axios的get方法获取json文件中数据,再用then(response=>(this.info=response.data))
<body>
<div id="vue">
<div> address: {{info.address.country}}</div>
<a v-bind:href="info.links[2].url">跳转</a>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
var v = new Vue({
el: '#vue',
data(){
return {
info: {
name: null,
address: {
country: null,
city: null,
street: null
},
url: null
}
}
},
mounted(){//钩子函数
axios
.get('../date.json')
.then(response=>(this.info=response.data));
}
});
</script>
</body>
5.计算属性
可以理解为将不怎么变的值计算出来,最后赋值给属性,而且这是以内存的形式存储,相当于缓存的作用,这就给浏览器节约了很大的内存。
它就是一个能够将计算结果缓存起来的属性(将行为转化成了静态的属性)。
注意在computed中方法名在引用时不需要加入(),{{currentTime2}}
this.message是为了能够让currentTime2观察到数据变化而变化,这样我们在控制条刷新vm.message后就能看到时间戳的变化。
<div id="app">
time: <p>{{currentTime1()}}</p>
time2: <p>{{currentTime2}}</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
var vm = new Vue({
el:"#app",
methods: {
currentTime1: function (){
return Date.now();
}
},
computed: {
currentTime2: function (){
this.message;
return Date.now();
}
},
data: {
message: "damage"
}
});
6.插槽Slot
先编写一个组件,template:' ',单引号里面用来存放整体框架,然后记得要在动态的地方添加为插槽并命名,注意在每个标签后加上\就可以正常编写。
v-bind:item = "item"可以缩写为 :item = "item",前面可以理解为绑定id,引号中的是从data中拿出数据
todo-title和todo-items组件分别被分发到了todo组件的todo-title和todo-items插槽中
<body>
<div id="app">
<todo>
<todo-title slot="todo-title" :title="title"></todo-title>
<todo-items v-for="item in items" slot="todo-items" v-bind:item="item"></todo-items>
</todo>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.min.js"></script>
<script>
Vue.component("todo",{
template: '<div>\
<slot name="todo-title"></slot>>\
<ul>\
<slot name="todo-items"></slot>>\
</ul>\
</div>'
});
Vue.component('todo-title',{
props:['title'],
template:'<div>{{title}}</div>'
});
Vue.component("todo-items",{
props: ['item'],
template: '<li>{{item}}</li>'
})
var vm = new Vue({
el:"#app",
data: {
title:"计算机语言",
items: ["java","python","c++"]
}
});
</script>
7.自定义事件
在视图层中,一般通过vue的方法将组件还有实例化vue联系起来
①(v-bind:itme_p="item"),前面的item即与component中的props[‘’]相对应(props里的参数都得单引号),而后面的"item"既是从data获取。
②(v-on:remove="removeItems(index)"),remove是组件中自定义事件this.$emit("remove",index)
而removeItems(index)对应实例化的方法。
js中spice是对数组的操作,格式为spice(index,num,elm1,elm22)
index表从数组的哪个下标开始删除或增加,num表删除的个数,可以为0,elm1表增加的元素。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--view层,模板-->
<div id="vue">
<todo>
<todo-title slot="todo-title" :title="title_text"></todo-title>
<!--<todo-items slot="todo-items" v-for="(item,index) in todoItems" v-bind:item="item"></todo-items>-->
<!--如下为简写-->
<todo-items slot="todo-items" v-for="(item,index) in todoItems"
:item_p="item" :index_p="index" v-on:remove="removeItems(index)" :key="index"></todo-items>
</todo>
</div>
<!--1.导入Vue.js-->
<script src="../js/vue.js"></script>
<script type="text/javascript">
Vue.component('todo',{
template:'<div>\
<slot name="todo-title"></slot>\
<ul>\
<slot name="todo-items"></slot>\
</ul>\
</div>'
});
Vue.component('todo-title',{
props:['title'],
template:'<div>{{title}}</div>'
});
//这里的index,就是数组的下标,使用for循环遍历的时候,可以循环出来!
Vue.component("todo-items",{
props:["item_p","index_p"],
template:"<li>{{index_p+1}},{{item_p}} <button @click='remove_methods'>删除</button></li>",
methods:{
remove_methods:function (index) {
//this.$emit 自定义事件分发
this.$emit('remove',index);
}
}
});
var vm = new Vue({
el:"#vue",
data:{
title_text:"秦老师系列课程",
todoItems:['test1','test2','test3']
},
methods:{
removeItems:function(index){
console.log("删除了"+this.todoItems[index]+"OK");
this.todoItems.splice(index,1);
}
}
});
</script>
</body>
</html>
8.入门小结
核心:数据驱动,组件化
优点:借鉴了AngularJS的模块化开发和React的虚拟Dom,虚拟Dom就是把Demo操作放到内存中执行;
常用的属性:
- v-if
- v-else-if
- v-else
- v-for
- v-on绑定事件,简写@
- v-model数据双向绑定
- v-bind给组件绑定参数,简写:
组件化:
- 组合组件slot插槽
- 组件内部绑定事件需要使用到
this.$emit("事件名",参数);
- 计算属性的特色,缓存计算数据
遵循SoC关注度分离原则,Vue是纯粹的视图框架,并不包含,比如Ajax之类的通信功能,为了解决通信问题,我们需要使用Axios框架做异步通信;
9.第一个vue-li项目
9.1 nodejs安装
- cmd下输入
node -v
,查看是否能够正确打印出版本号即可! - cmd下输入
npm -v
,查看是否能够正确打印出版本号即可!
这个npm,就是一个软件包管理工具,就和linux下的apt软件安装差不多!
9.2镜像安装
- 安装Node.js淘宝镜像加速器(cnpm),用于快速下载(管理员身份运行:cmd,ctrl+shitf+enter)
-
# -g 就是全局安装
npm install cnpm -g# 或使用如下语句解决npm速度慢的问题
npm install --registry=https://registry.npm.taobao.org
9.3安装vue-cli
-
cnpm instal1 vue-cli-g
-
#查看可以基于哪些模板创建vue应用程序,通常我们vue list
9.4基于webpack的vue程序
1.创建一个Vue项目,我们随便建立一个空的文件夹在电脑上,我这里在D盘下新建一个目录
D:\Project\vue-study;
2.创建一个基于webpack模板的vue应用程序
#1、首先需要进入到对应的目录 cd D:\Project\vue-study
#2、这里的myvue是顶日名称,可以根据自己的需求起名
vue init webpack myvue
3.初始化并运行
cd myvue
npm install
npm run dev
9.5webpack安装
WebPack是一款模块加载器兼打包工具, 它能把各种资源, 如JS、JSX、ES 6、SASS、LESS、图片等都作为模块来处理和使用。
安装:
npm install webpack -g
npm install webpack-cli -g
测试安装成功
webpack -v
webpack-cli -v
10.webpack使用
- 创建空项目
- 创建一个名为modules的目录,用于放置JS模块等资源文件
- 在modules下创建模块文件,如hello.js,用于编写JS模块相关代码
注意exports.方法名 = function(){}
//暴露一个方法:sayHi
exports.sayHi = function(){
document.write("<div>Hello Webpack</div>");
}
- 在modules下创建一个名为main.js的入口文件,用于打包时设置entry属性
//require 导入一个模块,就可以调用这个模块中的方法了
var hello = require("./hello");
hello.sayHi();
- 在项目目录下创建webpack.config.js配置文件,在terminal中使用webpack命令打包
entry是项目入口文件,output是文件打包后的位置及命名
module.exports = {
entry:"./modules/main.js",
output:{
filename:"./js/bundle.js"
}
}
- 在项目目录下创建HTML页面,如index.html,导入webpack打包后的JS文件
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>狂神说Java</title>
</head>
<body>
<script src="dist/js/bundle.js"></script>
</body>
</html>
# 参数--watch 用于监听变化
webpack --watch,相当于热部署(即修改内容后会重新打包)
11.vue-router
11.1插入包
vue-router是一个插件包, 所以我们还是需要用npm/cn pm来进行安装的。
打开命令行工具,进入你的项目目录,输入下面命令。
npm install vue-router --save-dev
bug:在package.json中有对应的依赖版本号,我们需要通过修改与对应vue一致的版本。
如果在一个模块化工程中使用它,必须要通过Vue.use()来安装路由功能:
一般是在router目录下的index.js配置文件中来使用
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter);
11.2目录结构
定义一个Content.vue
的组件
template中存放html,script中是导出组件信息
<template>
<div>
<h1>内容页</h1>
</div>
</template>
<script>
export default {
name:"Content"
}
</script>
在src目录下,新建一个文件夹:router
,专门存放路由,添加一个路由配置文件index.js,然后在里面引用路由,接着再配置路由地址还有对应的组件 。
import Vue from'vue'
//导入路由插件
import Router from 'vue-router'
//导入上面定义的组件
import Content from '../components/Content'
import Main from '../components/Main'
//安装路由
Vue.use(Router) ;
//配置路由
export default new Router({
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.config.productionTip = false;
new Vue({
el:"#app",
//配置路由
router,
components:{App},
template:'<App/>'
});
6、在App.vue(主页面)
中使用路由
<template>
<div id="app">
<!--
router-link:默认会被渲染成一个<a>标签,to属性为指定链接
router-view:用于渲染路由匹配到的组件
-->
<router-link to="/">首页</router-link>
<router-link to="/content">内容</router-link>
<router-view></router-view>
</div>
</template>
<script>
export default{
name:'App'
}
</script>
<style></style>
12.实战上手
12.1环境准备
1、创建一个名为hello-vue的工程vue init webpack hello-vue
2、安装依赖, 我们需要安装vue-router(可在创建项目时勾选)、element-ui、sass-loader和node-sass四个插件
#进入工程目录
cd hello-vue
#安装vue-routern
npm install vue-router --save-dev
#安装element-ui
npm i element-ui -S
#安装依赖
npm install
# 安装SASS加载器
cnpm install sass-loader node-sass --save-dev
#启功测试
npm run dev
把没有用的初始化东西删掉!
在源码目录中创建如下结构:
- assets:用于存放资源文件
- components:用于存放Vue功能组件
- views:用于存放Vue视图组件
- router:用于存放vue-router配置
12.2代码实现
创建首页视图,在views目录下创建一个名为Main.vue的视图组件:
<template>
<div>首页</div>
</template>
<script>
export default {
name:"Main"
}
</script>
<style scoped>
</style>
创建登录页视图在views目录下创建名为Login.vue的视图组件,其中el-*的元素为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:"密码不可为空",tigger:"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>
创建路由,在router目录下创建一个名为index.js
的vue-router路由配置文件
//导入vue
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
},
]
})
APP.vue
<template>
<div id="app">
<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>
main.js
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
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.use(router)
Vue.use(ElementUI)
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
render:h=>h(App)
})
测试:在浏览器打开 http://localhost:8080/#/login
如果出现错误: 可能是因为sass-loader的版本过高导致的编译错误,当前最高版本是8.0.2,需要退回到7.3.1 ;
去package.json文件里面的 "sass-loader"的版本更换成7.3.1,然后重新cnpm install就可以了;
13.路由嵌套(child)
嵌套路由又称子路由,在实际应用中,通常由多层嵌套的组件组合而成。
demo
1、 创建用户信息组件,在 views/user 目录下创建一个名为 Profile.vue 的视图组件;
Profile.vue
<template>
<h1>个人信息</h1>
</template>
<script>
export default {
name: "UserProfile"
}
</script>
<style scoped>
</style>
2、在用户列表组件在 views/user 目录下创建一个名为 List.vue 的视图组件;
List.vue
<template>
<h1>用户列表</h1>
</template>
<script>
export default {
name: "UserList"
}
</script>
<style scoped>
</style>
3、 修改首页视图,我们修改 Main.vue 视图组件,此处使用了 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 lang="scss">
.el-header {
background-color: #B3C0D1;
color: #333;
line-height: 60px;
}
.el-aside {
color: #333;
}
</style>
4、 配置嵌套路由修改 router 目录下的 index.js 路由配置文件,使用children放入main中写入子模块,代码如下
index.js
//导入vue
import Vue from 'vue';
import VueRouter from 'vue-router';
//导入组件
import Main from "../views/Main";
import Login from "../views/Login";
//导入子模块
import UserList from "../views/user/List";
import UserProfile from "../views/user/Profile";
//使用
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
},
]
})
14.参数传递
第一种取值方式
1、 修改路由配置, 主要是router下的index.js中的 path 属性中增加了 :id 这样的占位符
{
path: '/user/profile/:id',
name:'UserProfile',
component: UserProfile
}
2、传递参数
此时我们在Main.vue中的route-link位置处 to 改为了 :to,是为了将这一属性当成对象使用,注意 router-link 中的 name 属性名称 一定要和 路由中的 name 属性名称 匹配,因为这样 Vue 才能找到对应的路由路径;
<!--name是组件的名字 params是传的参数 如果要传参数的话就需要用v:bind:来绑定-->
<router-link :to="{name:'UserProfile',params:{id:1}}">个人信息</router-link>
12
3、在要展示的组件Profile.vue中接收参数 使用 {{$route.params.id}}来接收
Profile.vue 部分代码
<template>
<!-- 所有的元素必须在根节点下-->
<div>
<h1>个人信息</h1>
{{$route.params.id}}
</div>
</template>
第二种取值方式 使用props 减少耦合
1、修改路由配置 , 主要在router下的index.js中的路由属性中增加了 props: true 属性
{
path: '/user/profile/:id',
name:'UserProfile',
component: UserProfile,
props: true
}
2、传递参数和之前一样 在Main.vue中修改route-link地址
<!--name是组件的名字 params是传的参数 如果要传参数的话就需要用v:bind:来绑定-->
<router-link :to="{name:'UserProfile',params:{id:1}}">个人信息</router-link>
3、在Profile.vue接收参数为目标组件增加 props 属性
Profile.vue
<template>
<div>
个人信息
{{ id }}
</div>
</template>
<script>
export default {
props: ['id'],
name: "UserProfile"
}
</script>
<style scoped>
</style>
12.5、组件重定向
重定向的意思大家都明白,但 Vue 中的重定向是作用在路径不同但组件相同的情况下,比如:
在router下面index.js的配置
{
path: '/main',
name: 'Main',
component: Main
},
{
path: '/goHome',
redirect: '/main'
}
说明:这里定义了两个路径,一个是 /main ,一个是 /goHome,其中 /goHome 重定向到了 /main 路径,由此可以看出重定向不需要定义组件;
使用的话,只需要在Main.vue设置对应路径即可;
<el-menu-item index="1-3">
<router-link to="/goHome">回到首页</router-link>
</el-menu-item>
15.路由模式与 404
路由模式有两种
- hash:路径带 # 符号,如 http://localhost/#/login
- history:路径不带 # 符号,如 http://localhost/login
修改路由配置,代码如下:
export default new Router({
mode: 'history',
routes: [
]
});
404 demo
1.创建一个NotFound.vue视图组件
NotFound.vue
<template>
<div>
<h1>404,你的页面走丢了</h1>
</div>
</template>
<script>
export default {
name: "NotFound"
}
</script>
<style scoped>
</style>
2.修改路由配置index.js
import NotFound from '../views/NotFound'
{
path: '*',
component: NotFound
}
3.效果图
路由钩子与异步请求
beforeRouteEnter:在进入路由前执行
beforeRouteLeave:在离开路由前执行
在Profile.vue中写
export default {
name: "UserProfile",
beforeRouteEnter: (to, from, next) => {
console.log("准备进入个人信息页");
next();
},
beforeRouteLeave: (to, from, next) => {
console.log("准备离开个人信息页");
next();
}
}
参数说明:
to:路由将要跳转的路径信息
from:路径跳转前的路径信息
next:路由的控制参数
next() 跳入下一个页面
next(’/path’) 改变路由的跳转方向,使其跳到另一个路由
next(false) 返回原来的页面
next((vm)=>{}) 仅在 beforeRouteEnter 中可用,vm 是组件实例
在钩子函数中使用异步请求
1、安装 Axios
cnpm install --save vue-axios
2、main.js引用 Axios
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)
3、准备数据 : 只有我们的 static 目录下的文件是可以被访问到的,所以我们就把静态文件放入该目录下。
数据和之前用的json数据一样 需要的去上述axios例子里
// 静态数据存放的位置
static/mock/data.json
4.在 beforeRouteEnter 中进行异步请求
Profile.vue
export default {
//第二种取值方式
// props:['id'],
name: "UserProfile",
//钩子函数 过滤器
beforeRouteEnter: (to, from, next) => {
//加载数据
console.log("进入路由之前")
next(vm => {
//进入路由之前执行getData方法
vm.getData()
});
},
beforeRouteLeave: (to, from, next) => {
console.log("离开路由之前")
next();
},
//axios
methods: {
getData: function () {
this.axios({
method: 'get',
url: 'http://localhost:8080/static/mock/data.json'
}).then(function (response) {
console.log(response)
})
}
}
}
5.路由钩子和axios结合图
前端:在component下新建一个组件之后就得在router下导入