**需求:**如果页面中有多个一样结构的控件,比如
<div id="app">
<span>{
{count1}}span> <button @click="changeCount1">按钮button> <br>
<span>{
{count2}}span> <button @click="changeCount2">按钮button> <br>
<span>{
{count3}}span> <button @click="changeCount3">按钮button> <br>
<span>{
{count4}}span> <button @click="changeCount4">按钮button> <br>
<span>{
{count5}}span> <button @click="changeCount5">按钮button> <br>
div>
<script src="./vue.js">script>
<script>
new Vue({
el: '#app',
data: {
count1: 0,
count2: 0,
count3: 0,
count4: 0,
count5: 0
},
methods: {
changeCount1() {
this.count1++;
},
changeCount2() {
this.count2++;
},
changeCount3() {
this.count3++;
},
changeCount4() {
this.count4++;
},
changeCount5() {
this.count5++;
}
}
});
script>
问题:
- 代码重复 冗余
- 不利于维护
解决方案: 使用Vue中一个十分重要的特性-组件
体验组件的使用
<div id="app">
<span-btn>span-btn>
<span-btn>span-btn>
<span-btn>span-btn>
<span-btn>span-btn>
div>
<script src="./vue.js">script>
<script>
// 注册全局组件
Vue.component('span-btn', {
template: `
{
{count}}
`,
data() {
return {
count: 0
}
},
methods: {
changeCount() {
this.count++;
}
}
});
new Vue({
el: '#app'
});
script>
什么是组件:
组件系统是 Vue 的另一个重要概念,允许我们使用小型、独立和通常可复用的组件构建大型应用。
仔细想想,几乎任意类型的应用界面都可以抽象为一个组件树:
例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9SyzLoUV-1597388161652)(./assets/1533888610958.png)]
new Vue
接收相同的选项:例如 data
、computed
、watch
、methods
以及生命周期钩子等。el
这样根实例特有的选项建议: 在实际开发中,尽可能使用各种第三方组件
使用Vue.component(组件名,组件选项) 进行注册
组件名:推荐小写加减号的命名方式
用在其被注册之后的任何 (通过 new Vue
) 新创建的 (一个或者多个)Vue 实例
Vue.component('组件名', {
// 组件选项: data methods template等(没有el)
// data 的值是一个函数, 需要返回一个对象
});
<div id="app">
<span-btn>span-btn>
<span-btn>span-btn>
<span-btn>span-btn>
<span-btn>span-btn>
div>
<hr>
<div id="app1">
<span-btn>span-btn>
<My-Component>My-Component>
div>
<hr>
<div id="app2">
<span-btn>span-btn>
div>
<hr>
<div id="app3">
<span-btn>span-btn>
div>
<script src="./vue.js">script>
<script>
// 1. 注册组件
// Vue.component('组件名', {
// // 组件选项: data methods template等
// });
Vue.component('span-btn', {
// template: 页面字符串,有且仅有一个根元素
template: `
{
{count}}
`,
data() {
return {
count: 0
}
},
methods: {
changeCount() {
this.count++;
}
}
});
Vue.component('myComponent', {
template: `
{
{num}}
`,
style: './style.css',
data() {
return {
num: 0
}
},
methods: {
changeTitle() {
this.num++;
}
}
});
new Vue({
el: '#app'
});
new Vue({
el: '#app1'
});
new Vue({
el: '#app2'
});
new Vue({
el: '#app3'
});
script>
注意:
- 全局组件必须写在Vue实例创建之前,才在该根元素下面生效
- 在不同的Vue实例中可以使用多个不同的全局组件
- 每个组件有自己的作用域
components
对象中的每个属性来说,
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Documenttitle>
head>
<body>
<div id="app">
<com-A>com-A>
<com-B>com-B>
<com-C>com-C>
div>
<script src="./vue.js">script>
<script>
// 局部组件的选项
const comA = {
template: `{
{titleA}}`,
data() {
return {
titleA: 'comA中的data里的titleA'
}
}
};
const comB = {
template: `{
{titleB}}`,
data() {
return {
titleB: 'comB中的data里的titleB'
}
}
};
const comC = {
template: `{
{titleC}}`,
data() {
return {
titleC: 'comC中的data里的titleC'
}
}
};
new Vue({
el: '#app',
// 1. 在Vue实例中设置components选项{组件名:组件选项}
components: {
// 在页面中的组件名:组件选项
'comA': comA,
'comB': comB,
'comC': comC
}
});
script>
body>
html>
我们可以在new Vue()实例中使用自定义组件,
也可以在注册自定义组件时,嵌套另一个自定义组件,也就是父子组件的关系
<div id="app">
<parent-Com>parent-Com>
div>
<script src="./vue.js">script>
<script>
// 1. 注册全局组件
Vue.component('childCom', {
template: `
childCom全局组件
`
});
Vue.component('parentCom', {
// 在parentCom中嵌入childCom组件
// parentCom和childCom属于父子组件
// 父组件是parentCom
// 子组件是childCom
template: `
parentCom全局组件
`
});
new Vue({
el: '#app'
});
script>
<div id="app">
<parent-Com>parent-Com>
div>
<script src="./vue.js">script>
<script>
// 1. 局部组件的选项
const childCom = {
template: `
childCom局部组件
`
};
// 在parentCom组件选项中 使用components选项设置其子组件
// 在template中使用该子组件
const parentCom = {
template: `
parentCom局部组件
`,
components: {
'childCom': childCom
}
};
new Vue({
el: '#app',
components: {
'parentCom': parentCom
}
});
script>
父->子(在子组件中使用父组件数据) props : 不可修改 单向数据传递
子->父(在父组件中使用子组件数据) 自定义事件!
兄弟组件
组件让我们提高了代码的复用性,接下来考虑如何在不同的组件中进行传值
比如: 父组件有items数组 在子组件中使用父组件中的items数组去渲染列表
目的: 要在子组件中使用父组件中data中的属性值
关键点:通过Props给子组件传值
步骤:
- 在子组件中通过props声明自定义属性title
- 注册局部组件
- 使用子组件时,设置props选项, 通过自定义属性获取父组件的值
<div id="app">
<component-a :title="msg" :lists="items">component-a>
div>
<script src="./vue.js">script>
<script>
var ComponentA = {
// 1. 在子组件中通过props声明自定义属性title
template: `
{
{ title }}
-
{
{item.name}}
`,
// 用来接收外部传过来的数据
// 值的传递是单向的,内部不要修改props里变量的值
props: ['title', 'lists']
};
new Vue({
el: '#app',
// 目的: 要在子组件中使用父组件的msg的值
data: {
msg: 'hello heima',
items: [{
'id': 1,
'name': '小狗'
}, {
'id': 2,
'name': '小猫'
}, {
'id': 3,
'name': '小羊'
}
]
},
// 2. 注册局部组件
components: {
'component-a': ComponentA
}
});
script>
父子组件的传值有多种方法, 兄弟组件的通信也有自己的写法
避免混淆,这里我们先只讲父子组件通信的一种写法
会在后续的案例中会进行讲解
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2sCzMZBz-1597388161657)(C:/Users/liu99/Desktop/temp/vue7%E5%A4%A9/01-vue/%E7%AC%94%E8%AE%B0/media/b25efd3e8af188b5ab36ccb66baddd71_hd.jpg)]
生命周期是指Vue实例或者组件从诞生到消亡经历的每一个阶段,在这些阶段的前后可以设置一些函数当做事件来调用。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-toQ1aHyA-1597388161723)(assets/lifecycle.png)]
<body>
<div id="app">
<h1>{
{
message}}</h1>
</div>
</body>
<script>
var vm = new Vue({
el: '#app',
data: {
message: 'Vue的生命周期'
},
beforeCreate: function() {
console.group('------beforeCreate创建前状态------');
console.log("%c%s", "color:red" , "el : " + this.$el); //undefined
console.log("%c%s", "color:red","data : " + this.$data); //undefined
console.log("%c%s", "color:red","message: " + this.message)
},
created: function() {
console.group('------created创建完毕状态------');
console.log("%c%s", "color:red","el : " + this.$el); //undefined
console.log("%c%s", "color:red","data : " + this.$data); //已被初始化
console.log("%c%s", "color:red","message: " + this.message); //已被初始化
},
beforeMount: function() {
console.group('------beforeMount挂载前状态------');
console.log("%c%s", "color:red","el : " + (this.$el)); //已被初始化
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data); //已被初始化
console.log("%c%s", "color:red","message: " + this.message); //已被初始化
},
mounted: function() {
console.group('------mounted 挂载结束状态------');
console.log("%c%s", "color:red","el : " + this.$el); //已被初始化
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data); //已被初始化
console.log("%c%s", "color:red","message: " + this.message); //已被初始化
},
beforeUpdate: function () {
console.group('beforeUpdate 更新前状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
updated: function () {
console.group('updated 更新完成状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
beforeDestroy: function () {
console.group('beforeDestroy 销毁前状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message);
},
destroyed: function () {
console.group('destroyed 销毁完成状态===============》');
console.log("%c%s", "color:red","el : " + this.$el);
console.log(this.$el);
console.log("%c%s", "color:red","data : " + this.$data);
console.log("%c%s", "color:red","message: " + this.message)
}
})
</script>
</html>
单页应用(single page web application,SPA),是在一个页面完成所有的业务功能,浏览器一开始会加载必需的HTML、CSS和JavaScript,之后所有的操作都在这张页面完成,这一切都由JavaScript来控制。
前后端分离(后端专注于数据、前端专注于交互和可视化)+前端路由
Hash路由
利用URL上的hash,当hash改变不会引起页面刷新,所以可以利用 hash 值来做单页面应用的路由,
并且当 url 的 hash 发生变化的时候,可以触发相应 hashchange 回调函数。
模拟实现:
<a href="#/">首页</a>
<a href="#/users">用户管理</a>
<a href="#/rights">权限管理</a>
<a href="#/goods">商品管理</a>
<div id="box">
</div>
<script>
var box = document.getElementById('box');
window.onhashchange = function() {
// #/users
var hash = location.hash;
hash = hash.replace('#', '');
switch (hash) {
case '/':
box.innerHTML = '这是首页';
break;
case '/users':
box.innerHTML = '这是用户管理';
break;
case '/rights':
box.innerHTML = '这是权限管理';
break;
}
};
</script>
History路由
Vue-Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,让构建单页面应用变得易如反掌
实现根据不同的请求地址 而显示不同的组件
导入vue和vue-router
设置HTML中的内容
<router-link to="/users">用户管理router-link>
<router-view>router-view>
创建组件
// 创建组件
// 组件也可以放到单独的js文件中
var Home = {
template: '这是Home内容'
};
var Users = {
template: '这是用户管理内容'
};
配置路由规则
// 配置路由规则
var router = new VueRouter({
routes: [
{
name: 'home', path: '/', component: Home },
{
name: 'users', path: '/users', component: Users }
]
});
设置vue的路由选项
var vm = new Vue({
el: '#app',
router
});
场景: 不同的path对应同一个组件
注意: 变化的路由 改成 :参数
此时可以通过路由传参来实现,具体步骤如下:
路由规则中增加参数,在path最后增加 :id
{
name: 'users', path: '/users/:id', component: Users },
通过 传参,在路径上传入具体的值
<router-link to="/users/120">用户管理router-link>
在组件内部可以使用,this.$route 获取当前路由对象
var Users = {
template: '这是用户管理内容 {
{ $route.params.id }}',
mounted() {
console.log(this.$route.params.id);
}
};
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q714WmOd-1597388161727)(./assets/1536283239126.png)]
如果存在组件嵌套,就需要提供多个视图容器
同时,router-link和router-view 都可以添加类名、设定样式
<div id="app">
<nav>
<router-link to="/top">热点router-link>
<router-link to="/tech">教育router-link>
<router-link to="/soc">社会router-link>
<router-link to="/mus">音乐router-link>
<router-link to="/te">体育router-link>
nav>
<router-view class="box">
router-view>
div>
<script src="./vue.js">script>
<script src="./vue-router.js">script>
<script>
// 组件:
// 热点
var Top = {
template: 'Top
'
};
// 体育:带参数的二级路由
var Te = {
template: `
篮球
足球
好多球
`
};
// 教育:使用了data
var Tech = {
data: function() {
return {
name: "luck",
age: 10,
fn: function() {
alert(1);
}
}
},
template: `
{
{name}}
{
{age}}
`
}
// 社会
var Soc = {
template: 'soc
'
};
// 音乐:不带参数的二级路由
var Mus = {
// template: 'mus
'
template: `
流行
古典
摇滚
`
};
// 音乐:二级路由的视图
var Pop = {
template: 'mus下的pop模块
'
};
// 体育:二级路由的视图
var Ball = {
//路由参数 $route.params
template: "{
{$route.params}}
"
};
// 配置路由
var routes = [
// 热点
{
path: '/top',
component: Top
},
// 教育
{
path: '/tech',
component: Tech
},
// 社会
{
path: '/soc',
component: Soc
}, {
path: '/mus',
component: Mus,
//子路由配置
children: [{
path: 'pop',
component: Pop,
}]
},
// 体育
{
path: '/te',
component: Te,
children: [{
// /te/形参/10
path: ':cate/10',
component: Ball
}]
},
//重定向:默认或者404界面
{
path: '*',
redirect: '/top'
}
];
// 实例化路由
var router = new VueRouter({
// routes : routes
routes
});
// 实例化vue
var vue = new Vue({
el: '#app',
// router : router
router
});
script>
基本用法就是给我们需要动画的标签外面嵌套transition标签 ,并且设置name属性
Vue 在插入、更新或者移除 DOM 时,提供多种不同方式的应用过渡效果。
- 在 CSS 过渡和动画中自动应用 class
- 可以配合使用第三方 CSS 动画库,如 Animate.css
Vue 提供了 transition
的封装组件,在下列情形中,可以给任何元素和组件添加进入/离开过渡
// v要替换成transition组件的name属性值
v-enter:定义进入过渡的开始状态。
v-enter-active:定义进入过渡生效时的状态。
v-enter-to: 2.1.8版及以上 定义进入过渡的结束状态。
v-leave: 定义离开过渡的开始状态。
v-leave-active:定义离开过渡生效时的状态。
v-leave-to: 2.1.8版及以上 定义离开过渡的结束状态。
示例:
<style>
.box {
position: absolute;
left: 0;
top: 50px;
width: 100px;
height: 100px;
background-color: red;
}
.slide-enter, .slide-leave-to {
left: 200px;
opacity: 0;
}
.slide-enter-active, .slide-leave-active {
transition: all 2s;
}
.slide-enter-to, .slide-leave {
left: 0px;
opacity: 1;
}
style>
<button @click="isShow = !isShow">显示/隐藏button>
<transition name="slide">
<div v-show="isShow" class="box">div>
transition>
<script>
var vm = new Vue({
el: '#app',
data: {
isShow: true
}
});
script>
可以通过transition组件自定义过渡动画的类名,可以方便结合第三方的动画库使用,比如:animate.css
// transition组件的属性
enter-class
enter-active-class
enter-to-class (2.1.8+)
leave-class
leave-active-class
leave-to-class (2.1.8+)
示例:
<button @click="isShow = !isShow">togglebutton>
<transition
enter-active-class="animated fadeIn"
leave-active-class="animated fadeOut">
<div v-show="isShow">hellodiv>
transition>
<script>
var vm = new Vue({
el: '#app',
data: {
isShow: true
}
});
script>
可以快速创建vue项目结构,而不需要我们一点点的去创建/管理项目所需要的各种文件夹/文件
vue-cli是npm包
vue-cli 提供一个官方命令行工具,可用于快速搭建大型单页应用。
# 安装 Vue CLI 脚手架
# 如果已经安装过则不需要
# 这里安装的是最新版本 3版本
npm install -g @vue/cli
# 执行vue --verson查看是否安装成功,
# 显示vue的版本,就是安装成功了
vue -V
# 如果仍然要使用vue-cli 2版本的指令 需要安装一个桥接工具
npm install -g @vue/cli-init
# 使用脚手架工具初始化你的项目
# webpack-simple是一种工程模板
vue init webpack-simple 项目名称
# 进入你初始化好的项目
cd 项目路径
# 安装项目模板所需要的依赖
npm i
# 启动开发模式
# 或者 npm start
npm run dev
运行npm run dev后,会在浏览器中看到如下效果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9MofUzjp-1597388161730)(./assets/1534009067048.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MLL9nCag-1597388161732)(./assets/1534009729744.png)]
注意:
一个vue页面通常由三部分组成:模板(template)、js(script)、样式(style)
我们关心的重点是src中的文件夹
说明:
- *.vue 文件,是一个自定义的文件类型,用类似HTML的语法描述一个Vue组件。
- 每个.vue文件包含三种类型的顶级语言块 ,
export default {
// 这里写你的代码,如
el:,
data:,
props:
// 省略
};
就是针对我们的 template 里内容出现的 html 元素写一些样式
注意: vue-cli的作用就是让我们把精力放在业务编码上,一切准备的工作交给vue-cli去做
之后我们可以直接使用vue-cli去做案例或者项目
讲完了Vue基础知识和vue-cli工具
我们利用所讲知识完成一个简单的案例–英雄列表
目的:
- 熟悉vue-router的使用
- 熟悉单文件组件的使用
- 熟悉vue-cli的使用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3mqC1P2R-1597388161733)(./assets/1536664536268.png)]
利用脚手架vue-cli生成项目结构
# 安装 Vue CLI 脚手架
# 如果已经安装过则不需要!
npm i -g @vue/cli
# 使用脚手架工具初始化你的项目
vue init webpack-simple 项目名称
# 进入你初始化好的项目
cd 项目路径
#安装项目所需依赖
npm i
# 启动开发模式
# 或者 npm start
npm run dev
将vue-cli生成的文件中无用的代码进行删除
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YrDDwDGO-1597388161734)(./assets/1534220243520.png)]
main.js
import Vue from 'vue'
import App from './App.vue'
import "../node_modules/bootstrap/dist/css/bootstrap.css";
import "./assets/css/index.css";
new Vue({
el: '#app',
render: h => h(App)
})
{
test: /.(ttf|woff2|woff|eot)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
接下来我们用单文件组件的方式将页面文件提取为不同的组件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7vnrYJjq-1597388161735)(./assets/1534222080131.png)]
AppHeader.vue
<template>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">CRUD</a>
</div>
</div>
</nav>
</template>
<script>
export default {
}
</script>
<style>
</style>
App.vue
<template>
<div>
<!-- 3 使用AppHeader.vue组件 -->
<AppHeader></AppHeader>
<!--后面的标签结构 省略..-->
</div>
</template>
<script>
// 1. 导入AppHeader.vue组件
import AppHeader from './components/AppHeader';
export default {
name: 'app',
data () {
return {
}
},
// 2. 注册AppHeader组件
components:{
// 注意命名
AppHeader:AppHeader
}
}
</script>
<style lang="scss">
</style>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qS2Hm7UY-1597388161737)(./assets/1534223067628.png)]
新建AppList.vue,并将App.vue中的英雄列表的页面标签提取到AppList.vue中
使用 Vue-Router 实现页面导航管理
npm i vue-router
main.js
中加载...
import VueRouter from 'vue-router' // 加载路由模块
// 注册到 Vue 中才可以使用
Vue.use(VueRouter)
// ...
main.js
中 new
出 VueRouter
实例,并挂载到根实例的 router
选项中// ...
// 配置路由表
const appRouter = new VueRouter({
routes: [
]
})
// ...
new Vue({
el: '#app',
render: h => h(App),
// 配置实例选项 router 为你在上面 new 出来的 VueRouter 实例对象
router: appRouter
});
// ...
// 配置路由表
const appRouter = new VueRouter({
// routes 选项用来配置路由表
// 当请求 /xxx 的时候,渲染 xxx 组件
// routes 是一个数组,数组中存储一些固定格式的对象
// 对象 path 表示请求的路径
// 对象的 component 用来指定当你请求 path 路径的时候,渲染该组件
// 现在的问题是?匹配到 path 的时候,组件往哪里渲染?
// 在你的根组件预留一个路由的出口,用来告诉路由到匹配到某个 path 的时候,把该组件渲染到哪里
routes: [
{
path: '/foo',
component: {
template: `foo 组件啊`
}
},
{
path: '/bar',
component: {
template: `bar 组件啊`
}
}
]
});
// ...
src/App.vue
组件中设置路由出口(告诉路由往哪里渲染 path 匹配到的组件)<template>
<div id="app">
<AppHeader>AppHeader>
<div class="container-fluid">
<div class="row">
<AppSidebar>AppSidebar>
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<router-view>router-view>
div>
div>
div>
div>
template>
...
src/components/AppSidebar.vue
组件中 增加两个导航链接用来导航 foo
和 bar
<template>
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
<li class="active"><a href="#">英雄管理 <span class="sr-only">(current)span>a>li>
<li><a href="#">用户管理a>li>
<li><a href="#">商品管理a>li>
<li><a href="#">订单管理a>li>
<li><a href="#/foo">Go Fooa>li>
<li><a href="#/bar">Go Bara>li>
ul>
div>
template>
<script>script>
<style>style>
src/components/Foo.vue
:
<template>
<div>
Foo 组件
div>
template>
<script>script>
<style>style>
src/components/Bar.vue
:
<template>
<div>
Bar 组件
div>
template>
<script>script>
<style>style>
src/main.js
:
// ...
// ...
import Foo from './components/Foo'
import Bar from './components/Bar'
import HeroList from './components/HeroList'
// ...
// ...
// 配置路由表
const appRouter = new VueRouter({
routes: [
{
path: '/foo',
component: Foo
// component: {
// template: `foo 组件啊`
// }
},
{
path: '/bar',
component: Bar
},
{
path: '/heroes',
component: HeroList
}
]
});
// ...
将main.js中路由相关的代码提取到router.js中
新建router.js
import Vue from 'vue';
// 1. 导入路由
import VueRouter from 'vue-router';
// 导入组件
import AppList from './components/AppList.vue';
import Bar from './components/Bar.vue';
import Foo from './components/Foo.vue';
// 注册插件
// https://cn.vuejs.org/v2/guide/plugins.html
Vue.use(VueRouter);
// 2. 创建路由对象,配置路由规则
const router = new VueRouter({
routes: [
// { name: 'home', path: '/', redirect: '/heroes' },
{
name: 'home', path: '/', redirect: {
name: 'heroes' } },
// 路由规则
{
name: 'heroes', path: '/heroes', component: AppList },
{
name: 'bar', path: '/bar', component: Bar },
{
name: 'foo', path: '/foo', component: Foo }
]
});
// 3 导出模块
export default router;
main.js
import Vue from 'vue'
import App from './App.vue'
// import Foo from './components/Foo'
// import Bar from './components/Bar'
// import AppList from './components/AppList'
// import VueRouter from 'vue-router' // 加载路由模块
// // 注册到 Vue 中才可以使用
// Vue.use(VueRouter);
// 1 导入路由对象
import router from './router';
import "../node_modules/bootstrap/dist/css/bootstrap.css";
import "./assets/css/index.css";
new Vue({
el: '#app',
render: h => h(App),
// 配置实例选项 router 为你在上面 new 出来的 VueRouter 实例对象
// router: appRouter
router
});
将AppSilder.vue中的a标签改成router-link
AppSilder.vue
<template>
<div class="col-sm-3 col-md-2 sidebar">
<ul class="nav nav-sidebar">
<!-- <li class="active"><a href="#">Overview <span class="sr-only">(current)</span></a></li>
<li><a href="#/heroes">Reports</a></li>
<li><a href="#">Analytics</a></li>
<li><a href="#">Export</a></li>
<li><a href="#/foo">Go Foo</a></li>
<li><a href="#/bar">Go Bar</a></li> -->
<router-link tag="li" to="/heroes">
<a>英雄列表</a>
</router-link>
<router-link tag="li" to="/bar">
<a>武器列表</a>
</router-link>
<router-link tag="li" to="/foo">
<a>装备列表</a>
</router-link>
</ul>
</div>
</template>
<script>
export default {
}
</script>
<style>
</style>
接下来要实现具体的功能, 首先是英雄列表展示,其中的数据要来源于服务器
我们使用json-server快速启动api服务器 监听课程包中的db.json
可以使用postman测试接口
利用axios发送请求获取英雄列表的数据渲染到AppList.vue的template中
AppList.vue
<template>
<div>
<h2 class="sub-header">Hero Listh2>
<a class="btn btn-success" href="add.html">Adda>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>#th>
<th>名称th>
<th>性别th>
<th>操作th>
tr>
thead>
<tbody>
<tr :key="item.id" v-for="(item, index) in list">
<td>{
{ index + 1 }}td>
<td>{
{ item.name }}td>
<td>{
{ item.gender }}td>
<td>
<a href="edit.html">edita>
<a href="javascript:window.confirm('Are you sure?')">deletea> td>
tr>
tbody>
table>
div>
div>
template>
<script>
import axios from 'axios';
export default {
data(){
return {
list:[]
}
},
created(){
this.loadData();
},
methods:{
loadData(){
axios.get('http://localhost:3000/users')
.then((res)=>{
console.log(res);
const {
status,data} = res;
if (status == 200) {
this.list = data;
}
})
}
}
}
script>
<style>
style>
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rTVoAGow-1597388161738)(./assets/1534228452013.png)]
点击英雄列表中每个英雄信息后面的删除按钮,可以删除当前英雄数据
AppList.vue
<template>
<div>
<h2 class="sub-header">Hero Listh2>
<a class="btn btn-success" href="add.html">Adda>
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>#th>
<th>名称th>
<th>性别th>
<th>操作th>
tr>
thead>
<tbody>
<tr :key="item.id" v-for="(item, index) in list">
<td>{
{ index + 1 }}td>
<td>{
{ item.name }}td>
<td>{
{ item.gender }}td>
<td>
<a href="edit.html">edita>
<a href="#" @click.prevent="handleDelete(item.id)">deletea>
td>
tr>
tbody>
table>
div>
div>
template>
<script>
import axios from 'axios';
export default {
data(){
return {
list:[]
}
},
created(){
this.loadData();
},
methods:{
loadData(){
axios.get('http://localhost:3000/users')
.then((res)=>{
console.log(res);
const {
status,data} = res;
if (status == 200) {
this.list = data;
}
})
},
handleDelete(id) {
// 删除提示
if (!confirm('是否确认删除?')) {
return;
}
axios
.delete(`http://localhost:3000/users/${
id}`)
.then((res) => {
if (res.status === 200) {
// 删除成功,重新渲染列表
this.loadData();
} else {
alert('删除失败');
}
})
.catch((err) => {
console.log(err);
});
}
}
}
script>
<style>
style>
点击添加按钮 进入到添加的组件,输入新英雄信息,点击确定, 回到列表页渲染新数据
我们先让添加的页面显示出来
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iuhidUVo-1597388161740)(./assets/1534229426837.png)]
add.vue
<template>
<div>
<h2 class="sub-header">Add Heroh2>
<form>
<div class="form-group">
<label for="exampleInputEmail1">Email addresslabel>
<input type="email" class="form-control" id="exampleInputEmail1" placeholder="Email">
div>
<div class="form-group">
<label for="exampleInputPassword1">Passwordlabel>
<input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password">
div>
<div class="form-group">
<label for="exampleInputFile">File inputlabel>
<input type="file" id="exampleInputFile">
<p class="help-block">Example block-level help text here.p>
div>
<div class="checkbox">
<label>
<input type="checkbox"> Check me out
label>
div>
<button type="submit" class="btn btn-success">Submitbutton>
form>
div>
template>
<script>
export default {
}
script>
<style>
style>
router.js
import Vue from 'vue';
// 1. 导入路由
import VueRouter from 'vue-router';
// 导入组件
import AppList from './components/AppList.vue';
import Bar from './components/Bar.vue';
import Foo from './components/Foo.vue';
import Add from './components/add.vue';
// 注册插件
// https://cn.vuejs.org/v2/guide/plugins.html
Vue.use(VueRouter);
// 2. 创建路由对象,配置路由规则
const router = new VueRouter({
routes: [
// { name: 'home', path: '/', redirect: '/heroes' },
{
name: 'home', path: '/', redirect: {
name: 'heroes' } },
// 路由规则
{
name: 'heroes', path: '/heroes', component: AppList },
{
name: 'bar', path: '/bar', component: Bar },
{
name: 'foo', path: '/foo', component: Foo },
{
name: 'add', path: '/add', component: Add }
]
});
// 3 导出模块
export default router;
AppList
<template>
<div>
<h2 class="sub-header">Hero Listh2>
<router-link :to="{name:'add'}">添加router-link>
<div class="table-responsive">
div>
div>
template>
// 省略
add.vue
<template>
<div>
<div>
<h2 class="sub-header">Add Heroh2>
<form>
<div class="form-group">
<label for="name">英雄名称label>
<input type="text" class="form-control" id="name" placeholder="Name">
div>
<div class="form-group">
<label for="sex">英雄性别label>
<input type="text" class="form-control" id="sex" placeholder="Sex">
div>
<button type="submit" class="btn btn-success">Submitbutton>
form>
div>
div>
template>
有了页面,接下来我们实现添加的功能
add.vue
<template>
<div>
<h2 class="sub-header">Add Heroh2>
<form>
<div class="form-group">
<label for="name">英雄名称label>
<input v-model="formData.name" type="text" class="form-control" id="name" placeholder="Name">
div>
<div class="form-group">
<label for="sex">英雄性别label>
<input v-model="formData.gender" type="text" class="form-control" id="sex" placeholder="Sex">
div>
<button @click.prevent="handleAdd" type="submit" class="btn btn-success">Submitbutton>
form>
div>
template>
<script>
import axios from 'axios'
export default {
data() {
return {
// 绑定到表单元素
formData: {
name: '',
gender: ''
}
}
},
methods:{
handleAdd() {
axios
.post('http://localhost:3000/users', this.formData)
.then((res) => {
const {
status, data } = res;
if (status === 201) {
// 判断添加是否成功
// 添加成功,跳转到英雄列表
this.$router.push({
name: 'heroes' });
} else {
alert('添加失败');
}
})
}
}
}
script>
<style>
style>
编辑的页面和添加的页面很像
edit.vue
<template>
<div>
<h2 class="sub-header">Edit Heroh2>
<form>
<div class="form-group">
<label for="name">英雄名称label>
<input v-model="formData.name" type="text" class="form-control" id="name" placeholder="Name">
div>
<div class="form-group">
<label for="sex">英雄性别label>
<input v-model="formData.gender" type="text" class="form-control" id="sex" placeholder="Sex">
div>
<button type="submit" class="btn btn-success">Submitbutton>
form>
div>
template>
<script>
import axios from 'axios'
export default {
data() {
return {
// 绑定到表单元素
formData: {
name: '',
gender: ''
}
}
},
methods:{
}
}
script>
<style>
style>
router.js
import Vue from 'vue';
// 1. 导入路由
import VueRouter from 'vue-router';
// 导入组件
import AppList from './components/AppList.vue';
import Bar from './components/Bar.vue';
import Foo from './components/Foo.vue';
import Add from './components/add.vue';
import Edit from './components/edit.vue';
// 注册插件
// https://cn.vuejs.org/v2/guide/plugins.html
Vue.use(VueRouter);
// 2. 创建路由对象,配置路由规则
const router = new VueRouter({
routes: [
// { name: 'home', path: '/', redirect: '/heroes' },
{
name: 'home', path: '/', redirect: {
name: 'heroes' } },
// 路由规则
{
name: 'heroes', path: '/heroes', component: AppList },
{
name: 'bar', path: '/bar', component: Bar },
{
name: 'foo', path: '/foo', component: Foo },
{
name: 'add', path: '/add', component: Add },
{
name: 'edit', path: '/edit/:id', component: Edit }
]
});
// 3 导出模块
export default router;
AppList
<router-link :to="{name:'edit',params:{id:item.id}}">编辑router-link>
edit.vue
<template>
<div>
<h2 class="sub-header">Edit Heroh2>
<form>
<div class="form-group">
<label for="name">英雄名称label>
<input v-model="formData.name" type="text" class="form-control" id="name" placeholder="Name">
div>
<div class="form-group">
<label for="sex">英雄性别label>
<input v-model="formData.gender" type="text" class="form-control" id="sex" placeholder="Sex">
div>
<button @click.prevent="handleEdit" type="submit" class="btn btn-success">Submitbutton>
form>
div>
template>
<script>
import axios from 'axios';
// 1. 进入编辑页面,显示当前要编辑的英雄
// 1.1 获取url上的id,created()
// 1.2 发送请求获取数据
// 1.3 绑定文本框
// 2. 点击Submit按钮,实现更新功能
export default {
data() {
return {
formData: {
name: '',
gender: ''
},
// 获取url上的id,默认-1
heroId: -1
}
},
// 组件创建完毕
created() {
// 获取路由参数
this.heroId = this.$route.params.id;
console.log(this.heroId);
// 调用 获取英雄对象的方法
this.loadData();
},
methods: {
// 根据id,获取英雄对象
loadData() {
axios
.get(`http://localhost:3000/users/${
this.heroId}`)
.then((res) => {
if (res.status === 200) {
this.formData = res.data;
}
});
},
handleEdit() {
axios
.put(`http://localhost:3000/users/${
this.heroId}`, this.formData)
.then((res) => {
if (res.status === 200) {
this.$router.push({
name: 'heroes' });
} else {
alert('修改失败');
}
});
}
}
};
script>
<style>
style>
选中某个导航时,其样式和其他的不同, 为active的样式
参考文档
router.js
添加 linkActiveClass: ‘active’,全局配置
// 省略
const router = new VueRouter({
linkActiveClass: 'active',
routes: [
// { name: 'home', path: '/', redirect: '/heroes' },
{
name: 'home', path: '/', redirect: {
name: 'heroes' } },
// 路由规则
{
name: 'heroes', path: '/heroes', component: AppList },
{
name: 'bar', path: '/bar', component: Bar },
{
name: 'foo', path: '/foo', component: Foo },
{
name: 'add', path: '/add', component: Add },
{
name: 'edit', path: '/edit/:id', component: Edit }
]
});
// 省略
axios请求在多个组件中都要使用,
所以, 可以考虑给Vue实例添加axios选项,
这样 所有的组件都可以使用
main.js
// 省略--
// 导入axios
import axios from 'axios';
// 配置所有Vue的实例都具有$http这个成员
Vue.prototype.$http = axios;
new Vue({
el: '#app',
render: h => h(App),
// 配置实例选项 router 为你在上面 new 出来的 VueRouter 实例对象
// router: appRouter
router
});
将之前在组件中使用axios的位置改成
add.vue
<script>
// import axios from 'axios'
export default {
data() {
return {
// 绑定到表单元素
formData: {
name: '',
gender: ''
}
}
},
methods:{
handleAdd() {
this.$http
.post('http://localhost:3000/users', this.formData)
.then((res) => {
const {
status, data } = res;
if (status === 201) {
// 判断添加是否成功
// 添加成功,跳转到英雄列表
this.$router.push({
name: 'heroes' });
} else {
alert('添加失败');
}
})
}
}
}
</script>
请求的url中有一部分是一样的, 每次写很麻烦,
所以, 可以使用axios的API 配置baseURl
main.js
// 省略--
// 导入axios
import axios from 'axios';
// 设置baseURL
axios.defaults.baseURL = 'http://localhost:3000/';
// 省略--
在发起this.$http请求的位置, 简化原来的url
add.vue
<script>
// import axios from 'axios'
export default {
data() {
return {
// 绑定到表单元素
formData: {
name: '',
gender: ''
}
}
},
methods:{
handleAdd() {
this.$http
.post('users', this.formData)
.then((res) => {
const {
status, data } = res;
if (status === 201) {
// 判断添加是否成功
// 添加成功,跳转到英雄列表
this.$router.push({
name: 'heroes' });
} else {
alert('添加失败');
}
})
}
}
}
</script>