vue基础
一、vue初识
1、Vue.js 是什么?
是一套构建用户界面的渐进式的自底向上增量开发MVVM框架,Vue 的核心库只关注视图层,它不仅易于上手,还便于与第三方库或既有项目整合。通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件;
vue的特点:
轻量级、高效率、上手快、简单易学、文档全面而简洁
2、 对于Vue是一套渐进式框架的理解
1)每个框架都会有自己的一些特点,会对开发者有一定的要求,这些要求就是主张,主张有强有弱,它的强势程度会影响在业务开发中的使用方式。
2)可以在原有大系统的上面,把一两个组件改用vue实现,也可以整个用vue全家桶开发不会做职责之外的事。
3. 对于Vue自底向上增量开发的设计的理解
先写一个基础的页面,把基础的东西写好,再逐一去添加功能和效果,由简单到繁琐的这么一个过程。
4.Vue.js 目的
Vue.js的产生核心是为了解决如下三个问题
1)解决数据绑定问题。
2)Vue.js主要的目的是为了开发大型单页面应用。
3)支持组件化,也就是可以把页面封装成为若干个组件,把组件进行拼装,这样是让页面的复用性达到最高。
5. vue.js的核心思想
vue.js的核心思想包括:数据驱动和组件化
。
6. Vue.js 优势
1)简洁:HTML 模板 + Vue 实例 + JSON 数据
2)轻量:17kb,性能好
3)设计思想:视图与数据分离,无需操作DOM
4)社区:大量的中文资料和开源案例
7.vue.js概念
Vue.js 是 MVVM 结构的前端框架
8.vue.js特点
简洁、轻量、性能好、社区活跃
二、MVC框架
1.什么是框架
封装与业务无关的重复代码,形成框架
2.框架的优势
使用框架提升开发效率(虽然使用框架要遵循框架的语法但是使用框架可以大大提高对于业务逻辑的操作)
3.MVC - 表示软件可分成三部分
1)模型(Model)数据的储存和处理,再传递给视图层相应或者展示
2)视图(View)前端的数据展示
3)控制器(Controller)对数据的接收和触发事件的接收和传递
4.为什么要使用MVC
1) MVC 是一种专注业务逻辑,而非显示的设计思想
2)MVC 中没有DOM操作
3)将数据独立出来,方便管理
4)业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。
模型——数据
视图——页面(html)
控制器——他俩之间的那个
5.mvc思想
大家会发现使用MVC的思想的方式完成大家会发现方便很多因为MVC更关注业务数据,不关注页面实现的表象(独立数据,不用操作DOM)
6.Vue.js是一套构建用户界面的MVVM框架
MVVM分为三个部分:分别是M(Model,模型层 ),V(View,视图层),VM(ViewModel,V与M连接的桥梁,也可以看作为控制器MVC的C层)
1)M:模型层,主要负责业务数据相关;
2) V:视图层,顾名思义,负责视图相关,细分下来就是html+css层;
3) VM:V与M沟通的桥梁,负责监听M或者V的修改,是实现MVVM双向绑定的要点;因此开发者只需关注业务逻辑,不需要手动操作DOM, 不需要关注数据状态的同步问题,复杂的数据状态维护完全由 MVVM 来统一管理。
7.MVP思想
1)MVP的全称为Model-View-Presenter,Model提供数据,View负责显示,Presenter表示器;
2) MVP与MVC有着一个重大的区别: MVP与MVC最不同的一点是M与V是不直接关联的也是就Model与View不存在直接关系,这两者之间间隔着的是Presenter层,其负责调控View与Model之间的间接交互
。
8、小结
1)什么是框架:封装与业务逻辑无关的重复代码形成框架;
2)MVC 思想:一种将数据层与视图层进行分离的设计思想;
3)MVVM思想:意思就是当M层数据进行修改时,VM层会监测到变化,并且通知V层进行相应的修改,反之相同
;
4)MVP思想:MVP的全称为Model-View-Presenter,Model提供数据,View负责显示,Presenter负责逻辑的处理。
三、新增
1、dome元素新增
<!DOCTYPE html>
<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>Document</title>
</head>
<body>
<h1 id="demoarr"></h1>
<button onclick="add()">新增</button>
<button onclick="">删除</button>
<script>
let arr=["aaa","bbb","cc"];
let demoarr=document.getElementById("demoarr");
demoarr.innerText=arr;
function add() {
arr.push("dd");
//zai走一遍,把新增之后的arr插入
let demoarr=document.getElementById("demoarr");
demoarr.innerText=arr;
}
</script>
</body>
</html>
2、vue新增:
下载依赖:
npm install --save vue
<!DOCTYPE html>
<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></title>
<script src="../node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="demodiv">
{{arr}}
<button @click="add()">点击新增</button>
</div>
<script>
new Vue({
el:"#demodiv",
data:{
arr:["aa","bb","cc"]
},
methods:{
add(){
this.arr.push("dd")
}
}
})
</script>
</body>
</html>
四、声明式渲染与数据驱动
1、Vue声明式渲染
1)Vue.js 的核心是一个允许采用简洁的模板语法来声明式的将数据渲染进 DOM,也就
是将模板中的文本数据写进DOM中;
2)命令式渲染 : 命令我们的程序去做什么,程序就会跟着你的命令去一步一步执行;
3)声明式渲染 : 我们只需要告诉程序我们想要什么效果,其他的交给程序来做。
2、Vue数据驱动
通过控制数据的变化来显示vue的数据驱动是视图的内容随着数据的改变而改变。
五、Vue渲染方式
1、{{}}–表达式
将双大括号中的数据替换成对应属性值进行响应式的展示
2、表达式概述
双大括号语法也叫模板语法
3、表达式中可以写入哪些内容?
1)JSON数据
2)数组
3)结合刚开始使用原始方法完成的demo使用vue完成演示数组数据和JSON数据
4、表达式基本用法
1)注意
避免在双括号中使用复杂表达式
2)常见问题
如何区分插值中的内容是表达式还是普通文本?
Vue.js 会通过是否带引号区分两者
5、模板语法基本用法
模板语法中可以写入哪些内容?
1)数字
2)字符串
3)计算 mvc设计思想,是为了使页面和数据进行很好的分离;如果在表达式中写入过多的逻辑代码,那么违背了最初的设计思想;也就使代码看起来很复杂,难以维护。
总结:
1、表达式概念:使用双大括号来包裹 js 代码构成表达式
2、表达式语法:使用双花括号语法
六、vue指令初识
基本概念:指令是带有 v- 前缀的特殊属性
1、 Vue.js 指令的用途
它们作用于HTML元素,指令提供了一些特殊的特性,将指令绑定在元素上时,指令会为绑定的目标元素添加一些特殊的行为,我们可以将指令看作特殊的HTML属性(attribute)。
2、Vue.js 指令的书写规范:
1)书写位置:任意 HTML 元素的开始标签内
2)注意:一个开始标签内可写入多个指令,多个指令间使用空格分隔
3、初识vue
<!DOCTYPE html>
<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>Document</title>
<!-- 1.引包 -->
<script src="node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<!-- 2.创建v层 -->
<div id="demodiv">
<!-- 展示数据 (一个双花括号,只能展示一个数据)-->
{{name}}
{{age}}
</div>
<script>
// 3.创建vm层 -----就是vue实例
// vm层的作用是干什么?
// 连接v与m之间建立关系
new Vue({
// 关联v层
el:"#demodiv",
// 创建m层
data:{
name:"啦啦啦",
age:22
}
})
</script>
</body>
</html>
4、双花括号
<!DOCTYPE html>
<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>Document</title>
<script src="node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="demodiv">
<h1>{{"num"}}</h1>
<h1>{{numTwo}}</h1>
<h1>{{num+numTwo}}</h1>
<h1>{{num+text}}</h1>
<h1>{{obj.name}}</h1>
<h1>{{arr[4]}}</h1>
<h1>{{bool}}</h1>
<!-- 主意:避免在双括号中使用复杂表达式 下面这个写法不建议大家在视图当中出现-->
<h1>{{text.substr(0,2).toUpperCase()}}</h1>
</div>
<script>
new Vue({
el:"#demodiv",
data:{
num:1,
numTwo:3,
text:"abcdefg",
//对象
obj:{
name:"xixi"
},
//数组
arr:[11111,22222,33333,44444,5555],
bool:true
}
})
</script>
</body>
</html>
七、常见 Vue.js 指令
1、v-model 指令
1)作用:主要是用于表单上数据的双向绑定
2)语法:v-model = 变量
注:v-model 指令必须绑定在表单元素上
<!DOCTYPE html>
<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>Document</title>
<style>
.box1{
display: block;
font-size:20px;
color:red;
}
</style>
<script src="node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="box">
<p @click="fun()" class="box1">{{text}}</p>
<input type="text" v-model="text" v-show="bool" placeholder="输入">
</div>
</body>
</html>
<script>
new Vue({
el:"#box",
data:{
text:"请输入",
bool:true
},
methods:{
fun(){
console.log(this.text)
//在methods 里面使用this,this代表vue实例
//点击过后非隐藏或者显示
this.bool = !this.bool;
//点击过后恢复原状
this.text="请输入"
}
}
})
</script>
2、v-show 指令
1)作用:控制切换一个元素的显示和隐藏
2)语法:v-show = 表达式
①根据表达式结果的真假,确定是否显示当前元素
②true
表示显示该元素;false(默认)
表示隐藏该元素
③元素一直存在只是被动态设置了display:none
show的显示隐藏
<!DOCTYPE html>
<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>Document</title>
<style>
.show{
width:200px;
height:100px;
background: violet;
margin-top:10px;
}
</style>
<script src="node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="box">
<h1>小练习 v-model与v-show的组合练习</h1>
<input type="checkbox" v-model="show">{{show}}
<!-- 三元表达式 -->
<!-- {{show?"隐藏":"显示"}} -->
<!-- 注 :把一个变量通过v-model绑定给复选框,就是一个真或者假;
刚好 v-show就收的就是真或者假-->
<div class="show" v-show="show"></div>
</div>
</body>
</html>
<script>
new Vue({
el:"#box",
data:{
//获取show的值 true 或者 false
show:""
},
})
</script>
3、v-on 指令
1)作用:为 HTML 元素绑定事件监听
2)语法:v-on:事件名称=‘函数名称()’
3)简写语法:@事件名称=‘函数名称()’
注:函数定义在 methods
配置项中
<!DOCTYPE html>
<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>Document</title>
<script src="node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="demodiv">
<h1>v-on指令 用来绑定事件</h1>
<button v-on:click="fun()">点我在控制台输出你好</button>
<h1>注意上面写的写法是繁写 还有更好更推荐的写法</h1>
<button @click="fun()">事件绑定简写</button>
</div>
<script>
new Vue({
el:"#demodiv",
data:{
},
// 如果要写函数 那么必须必须必须在vue实例中与el,data同级 创建一个methods来进行存放
methods:{
//这里面写函数
fun(){
console.error("你好")
console.log("你坏")
console.warn("你可爱")
}
}
})
</script>
</body>
</html>
4、v-for 指令
1)作用:遍历 data 中的数据,并在页面进行数据展示
2)语法:v-for = ‘(item, index) in arr’
item 表示每次遍历得到的元素
index 表示item的索引,可选参数
<!DOCTYPE html>
<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">
<script src="node_modules/vue/dist/vue.min.js"></script>
<title>Document</title>
</head>
<body>
<div id="box">
<!-- 数组 -->
<!-- v代表 arr数组里面的元素 -->
<p v-for="v in arr">{{v}}</p>
<!-- item 代表 arr数组里面的元素,index下标 -->
<p v-for="(item,index) in arr">{{item}}========={{index}}</p>
<!-- json对象 -->
<div v-for="(item,index) in obj">
<!-- 根据下标取得 -->
<a href="#">{{obj[index].name}}</a>
<!-- 根据获得的元素取得 -->
<a href="#">{{item.age}}</a>
</div>
</div>
</body>
</html>
<script>
new Vue({
el:"#box",
data:{
//数组
arr:["aa","bb","cc","dd"],
//json对象
obj:[
{name:"拉拉1",age:19},
{name:"拉拉2",age:18},
{name:"拉拉3",age:17},
{name:"拉拉4",age:16},
{name:"拉拉5",age:15}
]
}
})
</script>
5、v-bind 指令
1)作用:绑定 HTML 元素的属性
2)语法:v-bind:属性名 = ‘表达式’/ 简写 :属性名=‘表达式’
①绑定一个属性:
②绑定多个属性(不能使用简写):
③<img v-bind=‘{src:myUrl, title: msg}’ />
6、v-if指令
1)作用:判断是否加载固定的内容
2)语法:v-if = 表达式
①根据表达式结果的真假,确定是否显示当前元素
②true表示加载该元素;false表示不加载该元素
③元素的显示和隐藏 是对Dom元素进行添加和删除
注:v-show与v-if区别:v-if有更高的切换消耗(安全性高)。v-show有更高的初始化的渲染消耗(对安全性无要求选择)
7、v-else-if 指令
作用:当有一项成立时执行。
1、v-if 和 v-else 指令(v-else后面什么都不写)
<!DOCTYPE html>
<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">
<script src="node_modules/vue/dist/vue.min.js"></script>
<title></title>
</head>
<body>
<div id="box">
<button v-model="bool" @click="fun()">点击</button>
<p v-if="bool">进来了</p>
<p v-else>出去了</p>
</div>
</body>
</html>
<script>
new Vue({
el:"#box",
data:{
bool:true
},
methods:{
fun(){
this.bool=!this.bool;
}
}
})
</script>
8、v-text 指令
作用:操作网页元素中的纯文本内容。{{}}是他的简写
9、v-html 指令
1)作用:双大括号会将数据解释为纯文本,而非 HTML 。为了输出真正的 HTML ,你需要使用 v-html 指令
2)语法:<p v-html="text"></p>
<!DOCTYPE html>
<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">
<script src="node_modules/vue/dist/vue.min.js"></script>
<style>
h1{
color: chartreuse;
}
</style>
<title></title>
</head>
<body>
<div id="box">
<div v-html="newhtml">
</div>
</div>
</body>
</html>
<script>
new Vue({
el:"#box",
data:{
newhtml:"<h1>我是添加的标签</p>"
}
})
</script>
10、v-once 指令
1)作用:当数据改变时,插值处的内容不会更新(会影响到该节点上的所有属性)
2)语法:<p v-once>{{text}}</p>
作用:当数据改变时,插值处的内容不会更新(会影响到该节点上的所有属性)
<!DOCTYPE html>
<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">
<script src="node_modules/vue/dist/vue.min.js"></script>
<style>
h2{
color: coral;
}
</style>
<title></title>
</head>
<body>
<div id="box">
<input type="text" value="" v-model="text">
<h2>{{text}}</h2>
<!-- 语法 -->
<h2 v-once>{{text}}</h2>
</div>
</body>
</html>
<script>
new Vue({
el:"#box",
data:{
text:"我在双花括号里面变,在v-once插入的元素里 不改变"
}
})
</script>
11、双向绑定(即关联)
Vue框架核心的功能就是双向的数据绑定。 双向是指:HTML标签数据 绑定到 Vue对象,另外反方向数据也是绑定的使用 v-model 指令来实现双向数据绑定 把视图数据与模型数据相互绑定;
1) 双向绑定–原理数据劫持
①vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的;
②数据劫持:当我们访问或设置对象的属性的时候,都会触发Object.defineProperty()函数来拦截(劫持),然后在返回(get)或设置(set)对象的属性的值。并且当数据发生改变的时候做出反应。
2)双向绑定–原理发布者-订阅者模式
①vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的
②发布者-订阅者模式:其定义对象间一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知。
<!DOCTYPE html>
<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>Document</title>
<script src="node_modules/vue/dist/vue.min.js"></script>
<style>
#text{
display: block;
width:300px;
height:200px;
border:2px solid red;
font-size:20px;
color:violet;
}
</style>
</head>
<body>
<div id="demodiv">
<h1>v-model="变量" 主要用于把表单元素和 模型数据进行关联</h1>
<!-- 1.视图中挂载的模型数据改变了 -->
<!-- 2.vm收到了改变的通知--发现模型数据改变了 -->
<!-- 3.通知视同也随之发生改变 -->
<input type="text" name="uname" v-model="inputText"/>
<p id="text">{{inputText}}</p>
</div>
<script>
new Vue({
el:"#demodiv",
data:{
inputText:""
}
})
</script>
</body>
</html>
跟随输入框改动:
12、案例
<!DOCTYPE html>
<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>Document</title>
<style>
.box1{
display: block;
font-size:20px;
color:red;
}
</style>
<script src="node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="box">
<p @click="fun()" class="box1">{{text}}</p>
<input type="text" v-model="text" v-show="bool" placeholder="输入">
</div>
</body>
</html>
<script>
new Vue({
el:"#box",
data:{
text:"请输入",
bool:true
},
methods:{
fun(){
console.log(this.text)
//在methods 里面使用this,this代表vue实例
//点击过后非隐藏或者显示
this.bool = !this.bool;
//点击过后恢复原状
this.text="请输入"
}
}
})
</script>
13、绑定HTML元素的属性
<!DOCTYPE html>
<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>Document</title>
<script src="node_modules/vue/dist/vue.min.js"></script>
<style>
.chartreuse{
background: chartreuse;
}
.coral{
background: coral;
}
</style>
</head>
<body>
<div id="box">
<!-- 改变链接地址 -->
<h3>链接练习</h3>
<a v-bind:href="lianjie">{{baidu}}</a>
<h3>下拉框,练习2</h3>
<select name="" id="" v-model="oText">
<option value="text">text</option>
<option value="checkbox">checkbox</option>
<option value="password">password</option>
<option value="radio">radio</option>
<option value="button">button</option>
</select>{{oText}}
<!-- 把 v-model 传给了他,改变了type属性-->
<input :type="oText">
<h3>修改样式,练习3</h3>
<!-- 当bool为真的时候为chartreuse ,为假的时候为coral -->
<input type="checkbox" v-model="bool">点击变色
<p :class="bool?'chartreuse':'coral'">颜色改变</p>
</div>
</body>
</html>
<script>
new Vue({
el:"#box",
data:{
baidu:"点击我跳转到百度",
lianjie:"http://www.baidu.com",
oText:"",
bool:true
}
})
</script>
14、购物车案例
<!DOCTYPE html>
<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">
<style>
#box{
width:250px;
/* height:350px; */
background: lightskyblue;
margin:10% auto;
padding:10px 20px;
}
h3{
text-align: center;
line-height:100%;
}
a{
color:#000;
text-decoration:none;
display:block;
margin-top:19px;
height:40px;
line-height:40px;
background: salmon;
padding:0 10px;
}
span{
float:right;
}
.across{
border-top:2px solid gray;
margin-top:10px;
}
p{
font-size:18px;
padding:0 10px;
}
.true{
color:#000;
text-decoration:none;
display:block;
margin-top:19px;
height:40px;
line-height:40px;
background: salmon;
padding:0 10px;
}
.flase{
color:#000;
text-decoration:none;
display:block;
margin-top:19px;
height:40px;
line-height:40px;
background: yellowgreen;
padding:0 10px;
}
</style>
<script src="node_modules/vue/dist/vue.min.js"></script>
<title></title>
</head>
<body>
<div id="box">
<h3>Services</h3>
<!-- item是一整行,把它传给点击函数 -->
<a href="#"
v-for="(item,index) in obj"
@click="fun(item)"
v-bind:class="item.bool?'true':'flase'"
>
{{item.name}}<span>{{item.price}}</span>
</a>
<div class="across"></div>
<p>price<span>{{price}}</span></p>
</div>
</body>
</html>
<script>
new Vue({
el:"#box",
data:{
price:0,
obj:[//bool:true保存当前样式
{name:"苹果",price:10,bool:true},
{name:"香蕉",price:12,bool:true},
{name:"栗子",price:16,bool:true},
{name:"方便面",price:1,bool:true}
]
},
methods:{
fun(x){
x.bool=!x.bool;
if(x.bool==true){
this.price -= Number(x.price);
}else{
this.price += Number(x.price);
}
}
}
})
</script>
15、删除数据,添加数据
<!DOCTYPE html>
<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>Document</title>
<script src="node_modules/_vue@2.6.10@vue/dist/vue.min.js"></script>
<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">
</head>
<body>
<div id="demodiv">
<div class="container">
<div class="row">
<div class="col-md-12">
<input type="text" class="form-control" v-model="inputa"/>
</div>
<div class="col-md-12">
<input type="text" class="form-control" v-model="inputb"/>
</div>
</div>
<div class="row">
<button type="button" class="btn btn-primary" @click="add()">添加</button>
<button type="button" class="btn btn-success">重置</button>
</div>
<div class="row">
<h1>用户信息表</h1>
</div>
<div class="row">
<table class="table table-hover table-bordered">
<tr>
<td>序号</td>
<td>名字</td>
<td>年龄</td>
<td>操作</td>
</tr>
<tr v-for="(v,i) in obj">
<td>{{i+1}}</td>
<td>{{v.title}}</td>
<td>{{v.age}}</td>
<td><button class="btn btn-success" data-toggle="modal" data-target="#myModal" v-on:click="delnum=i">删除</button></td>
</tr>
<tr v-if="obj.length>0">
<td colspan="4" class="text-right"><button class="btn btn-primary" data-toggle="modal" data-target="#myModal" v-on:click="delnum=-100">删除全部</button></td>
</tr>
<tr v-else>
<td colspan="4" class="text-center">暂无数据.......</td>
</tr>
</table>
</div>
</div>
<!-- 模态框代码 -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
<h4 class="modal-title" id="myModalLabel">确定删除吗?</h4>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" v-on:click="del(delnum)">确定</button>
<button type="button" class="btn btn-primary" data-dismiss="modal">取消</button>
</div>
</div>
</div>
</div>
</div>
<script src="node_modules/jquery/dist/jquery.min.js"></script>
<script src="node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
<script>
new Vue({
el:"#demodiv",
data:{
inputa:"",
inputb:"",
delnum:0,
obj:[
{title:"小名",age:18},
{title:"小名1",age:181}
]
},
methods:{
add(){
this.obj.push({title:this.inputa,age:this.inputb})
this.inputa="";
this.inputb="";
},
del(i){
console.log(i)
if(i>=0){
this.obj.splice(i,1);
}else{
this.obj=[];
}
}
}
})
</script>
</body>
</html>
八、事件
1、语法:<div @click=‘fn($event)’></div>中,$event为事件对象
;
2、作用:记录事件相关的信息。
<!DOCTYPE html>
<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">
<script src="node_modules/vue/dist/vue.min.js"></script>
<title></title>
</head>
<body>
<div id="box">
<button @click="fun($event)">点我</button>
<input type="text" @keydown.space="funb($event)" placeholder="请写内容">
</div>
</body>
</html>
<script>
new Vue({
el:"#box",
data:{
},
methods:{
fun(e){
console.log(e)
},
funb(e){
console.log(e)
}
}
})
</script>
3、prevent修饰符:阻止事件的默认行为(submit提交表单)
<!DOCTYPE html>
<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">
<script src="node_modules/vue/dist/vue.min.js"></script>
<title></title>
</head>
<body>
<div id="box">
<!-- 阻止传输时候显示 -->
<form action="" method="get" @submit.prevent="fun($event)">
<input type="text" name="uname">
<input type="submit">
</form>
</div>
</body>
</html>
<script>
new Vue({
el:"#box",
data:{
},
methods:{
fun(e){
console.log(e);
}
}
})
</script>
4、冒泡
<!DOCTYPE html>
<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">
<script src="node_modules/vue/dist/vue.min.js"></script>
<title></title>
</head>
<body>
<div id="box">
<!-- 阻止传输时候显示 -->
<form action="" method="get" @submit.prevent="fun($event)">
<input type="text" name="uname">
<input type="submit">
</form>
<hr>
<!-- 冒泡:从内到外 -->
<div @click="fun1()">
aaa
<div @click="fun2()">
bbb
</div>
</div>
<hr>
</div>
</body>
</html>
<script>
new Vue({
el:"#box",
data:{
},
methods:{
fun(e){
console.log(e);
},
fun1(e){
console.log("啊啊啊啊啊啊啊啊啊");
},
fun2(e){
console.log("啵啵啵啵啵啵啵啵啵");
}
}
})
</script>
点击bbb的时候,aaa也出来:
组织冒泡(点击谁打印谁)
<!DOCTYPE html>
<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">
<script src="node_modules/vue/dist/vue.min.js"></script>
<title></title>
</head>
<body>
<div id="box">
<!-- 阻止传输时候显示 -->
<form action="" method="get" @submit.prevent="fun($event)">
<input type="text" name="uname">
<input type="submit">
</form>
<hr>
<!-- 冒泡:从内到外 -->
<div @click="fun1()">
aaa
<!-- 给他添加stop阻止冒泡 -->
<div @click.stop="fun2()">
bbb
</div>
</div>
<hr>
</div>
</body>
</html>
<script>
new Vue({
el:"#box",
data:{
},
methods:{
fun(e){
console.log(e);
},
fun1(e){
console.log("啊啊啊啊啊啊啊啊啊");
},
fun2(e){
console.log("啵啵啵啵啵啵啵啵啵");
}
}
})
</script>
5、只触发自己的事件
<!DOCTYPE html>
<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">
<script src="node_modules/vue/dist/vue.min.js"></script>
<title></title>
</head>
<body>
<div id="box">
<!-- 只触发自己的事件 -->
<div @click.self.once="fun1()">
aaa
<div @click="fun2()">
bbb
</div>
</div>
</div>
</body>
</html>
<script>
new Vue({
el:"#box",
data:{
},
methods:{
fun(e){
console.log(e);
},
fun1(e){
console.log("啊啊啊啊啊啊啊啊啊");
},
fun2(e){
console.log("啵啵啵啵啵啵啵啵啵");
}
}
})
</script>
6、 事件修饰符
1)概念:v-on指令提供了事件修饰符来处理DOM事件细节
2)按键修饰符: .up, .down, .ctrl, .enter, .space等等
3)语法:@click.修饰符=‘fn()’
7、【扩展】事件修饰符
1)prevent修饰符:阻止事件的默认行为(submit提交表单)
2)stop修饰符:阻止事件冒泡
3)capture修饰符:与事件冒泡的方向相反,事件捕获由外到内
4)self:只会触发自己范围内的事件,不包含子元素
5)once:只会触发一次
注意:修饰符可以串联使用
九、vue数据交互
Axios的使用:
npm install --save axios
1、请求数据
1)后台server.js文件
注:①下载:npm install --save express
npm install --save body-parser
②运行
node server
var express=require("express");
var app=express();
var bodyParser=require("body-parser");
var uE=bodyParser.urlencoded({extended:true});
app.use(function(req,res,next){
res.header('Access-Control-Allow-Origin','*');
res.header('Access-Control-Allow-Headers', 'Content-Type,Content-Length, Authorization, Accept,X-Requested-With , yourHeaderFeild');
res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE,OPTIONS');
next();
})
app.get("/get",function(req,res){
res.send("okget")
})
app.post("/post",function(req,res){
res.send("okpost")
})
app.listen(3000);
2)数据请求
注:下载:npm install --save vue
npm install --save axios
<!DOCTYPE html>
<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></title>
<!-- yin入文件 -->
<script src="../node_modules/vue/dist/vue.min.js"></script>
<script src="./node_modules/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="box">
<button @click="funget()">点我发送get请求</button>
<button @click="funpost()">点我发送post请求</button>
</div>
</body>
</html>
<script>
new Vue({
el:"#box",
data: {
},
methods: {
// get数据请求
funget(){
axios.get("http://localhost:3000/get").then((ok)=>{
console.log(ok);
})
},
// post数据请求
funpost(){
axios.post("http://localhost:3000/post").then((ok)=>{
console.log(ok);
})
}
}
})
</script>
2、发送数据
1)server.js文件
var express=require("express");
var app=express();
var bodyParser=require("body-parser");
var uE=bodyParser.urlencoded({extended:true});
app.use(function(req,res,next){
res.header('Access-Control-Allow-Origin','*');
res.header('Access-Control-Allow-Headers', 'Content-Type,Content-Length, Authorization, Accept,X-Requested-With , yourHeaderFeild');
res.header('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE,OPTIONS');
next();
})
app.get("/get",function(req,res){
// get发送过来的数据
udata=req.query.udata;
//打印前台发过来的shu ju
console.log("get发来的数据:"+udata);
//请求get数据
res.send("okget")
})
app.post("/post",uE,function(req,res){
//post接收前台 发送过来的数据
udata=req.body.udata;
console.log("post发送过来的数据:"+udata);
//请求post数据
res.send("okpost")
})
app.listen(3000);
2)发送数据的html页面
①简写的方式
<!DOCTYPE html>
<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></title>
<!-- yin入文件 -->
<script src="../node_modules/vue/dist/vue.min.js"></script>
<script src="./node_modules/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="box">
<button @click="funget()">点我发送get请求</button>
<button @click="funpost()">点我发送post请求</button>
</div>
</body>
</html>
<script>
new Vue({
el:"#box",
data: {
},
methods: {
funget(){
axios.get("http://localhost:3000/get?udata=拉拉").then((ok)=>{
console.log(ok);
})
},
//post发送数据
funpost(){
//实例化一个对象
let param=new URLSearchParams();//使用URLSearchParams对 对象进行操作
//使用实例化的这个对象 下的 append这个方法,往里面键值对插入
param.append("udata","哈哈");//后台需要神魔发神魔
axios.post("http://localhost:3000/post",param).then((ok)=>{
console.log(ok);
})
}
}
})
</script>
②普通写法
<!DOCTYPE html>
<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></title>
<!-- yin入文件 -->
<script src="../node_modules/vue/dist/vue.min.js"></script>
<script src="./node_modules/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="box">
<button @click="funget()">点我发送get请求</button>
<button @click="funpost()">点我发送post请求</button>
</div>
</body>
</html>
<script>
new Vue({
el:"#box",
data: {
},
methods: {
funget(){
axios({
url:"http://localhost:3000/get",
method:"get",
params:{udata:"啦啦啦啊"}
}).then((ok)=>{
console.log(ok)
})
},
funpost(){
//实例化一个对象
let param=new URLSearchParams();//使用URLSearchParams对 对象进行操作
//使用实例化的这个对象 下的 append这个方法,往里面键值对插入
param.append("udata","哈哈");//后台需要神魔发神魔
axios({
url:"http://localhost:3000/post",
method:"post",
data:param
}).then((ok)=>{
console.log(ok)
})
}
}
})
</script>
3、TodoList练习
<!DOCTYPE html>
<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>Document</title>
<script src="node_modules/_vue@2.6.10@vue/dist/vue.min.js"></script>
<style>
.red{
background-color: red;
}
li{
font-size:20px;
}
ul{
list-style-type:none;
}
</style>
</head>
<body>
<div id="demodiv">
<h1>任务列表</h1>
<p>任务总数:{{obj.length}};还有:{{sheng()}}; <button @click="del()">完成</button></p>
<ul>
<li v-for="(v,i) in obj" :class="v.style?'red':''">
<input type="checkbox" v-model="v.style"/>
<span v-if="!v.edit" @click="fun(i)">{{v.title}}-----{{v.style}}</span>
<input type="text" v-model="v.title" v-else @blur="fun(i)"/>
</li>
</ul>
<input type="text" v-model="inputtext"><button @click="add()">添加</button>
</div>
<script>
new Vue({
el:"#demodiv",
data:{
inputtext:"",
obj:[
{title:"蛮王",style:false,edit:false},
{title:"vn",style:false,edit:false},
{title:"ez",style:false,edit:false},
{title:"寒冰",style:false,edit:false}
]
},
methods:{
del(){
// 1.新建一个变量用来存储 原始的旧数据;
var newobj=this.obj;
// 2.吧旧数据清空
this.obj=[];
// 3.循环便利这个新建的变量
for(var i=0;i<newobj.length;i++){
// 4.在循环中判断新建的这个变量中style是否==false
if(newobj[i].style==false){
// 5.吧这些符合要求的数据push得到旧数据中
this.obj.push(newobj[i]);
}
}
},
fun(i){
if(this.obj[i].style==false){
this.obj[i].edit=!this.obj[i].edit;
}else{
return;
}
},
add(){
this.obj.push({title:this.inputtext,style:false,edit:false})
this.inputtext="";
},
sheng(){
var i=0;
for(var k=0;k<this.obj.length;k++){
// 判断 判断每条数据的style是否为false 如果为false i++
if(this.obj[k].style==false){
i++;
}
}
//返回一个值,给 sheng(),在把他传到上面去
return i;
}
}
})
</script>
</body>
</html>
十一、计算属性
1、为什么要用计算属性?
模板内的表达式非常便利,但是设计它们的初衷是用于简单运算的。在模板中放入太多的逻辑会让模板过重且难以维护
<p>{{text.toUpperCase().substr(2,1)}}</p>
2、 计算属性
1)概念:顾名思义,首先它是一种属性,其次它有“计算”这个特殊性质。每次取得它的值得时候,它并不像普通属性那样直接返回结果,而是经过一系列的计算之后再返回结果。同时只要在它的当中里引用了 data 中的某个属性,当这个属性发生变化时,计算属性仿佛可以嗅探到这个变化,并自动重新执行。
注:
①如果有一条data数据想在很多个地方都是用因该怎么办? 想在那用就在那写
②如何把数据原样的插入到试图中呢?有几种方式? 有三种方式 1.{{}} 2.v-text 3v-html
③ 官方的概念(需要记忆):顾名思义,首先它是一种属性,其次它有“计算”这个特殊性质。每次取得它的值得时候,它并不像普通属性那样直接返回结果,而是经过一系列的计算之后再返回结果。同时只要在它的当中里引用了data 中的某个属性,当这个属性发生变化时,计算属性仿佛可以嗅探到这个变化,并自动重新执行。 简单的来说计算属性: a、 引用场景一条数据想在很多个地方展示出不同的内容形态; b、就是计算(可能会对数据进行处理,我们简称这个过程叫做计算)data中的属性。
④语法:与data或者methods同级的地方创建一个 。
2) 语法
computed: {//与data同级
需要返回的数据: function () {
return 处理操作(逻辑操作)
}
}
- 计算属性–使用
//改造把数据转大写并且截取的例子
computed:{
demoText:function(){
return this.data中的数据.toUpperCase().substr(2,1);
}
}
//展示:{{demoText}}
//注:①上面的例子也可以使用方法来完成。
methods:{
textfun(){
return this.text.toUpperCase().substr(2,2)
}
}
//展示{{textfun()}}
①同一数据展示不同形态
<!DOCTYPE html>
<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></title>
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="box">
<!-- 计算属性:
思考 如果有一条data数据想在很多个地方都是用因该怎么办? 想在那用就在那写
思考2 如何把数据原样的插入到试图中呢?有几种方式? 有三种方式 1.{{}} 2.v-text 3v-html
官方的概念(需要记忆):概念:顾名思义,首先它是一种属性,其次它有“计算”这个特殊性质。每次取得它的值得时候,
它并不像普通属性那样直接返回结果,而是经过一系列的计算之后再返回结果。同时只要在它的当中里引用了
data 中的某个属性,当这个属性发生变化时,计算属性仿佛可以嗅探到这个变化,并自动重新执行。
简单的来说计算属性 引用场景一条数据想在很多个地方展示出不同的内容形态
计算属性简单的来说 就是计算(可能会对数据进行处理 我们简称这个过程叫做计算)data中的属性
语法:
与data或者methods同级的地方创建一个 computed:{
接受返回值的变量(){
return必须 处理data中属性的逻辑
}
}
-->
<h1>计算属性</h1>
<p>全小写{{arr}}</p>
<p>全大写{{texta}}</p>
<p>截取第一个,并转换为大写{{textb}}</p>
</div>
</body>
</html>
<script>
new Vue({
el:"#box",
data:{
arr:"abcdefg"
},
computed: {
texta(){//texta是一个变量
return this.arr.toUpperCase();
},
textb(){
return this.arr.substr(0,1).toUpperCase();
}
},
})
</script>
②用函数实现,转换数据
<!DOCTYPE html>
<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></title>
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="box">
<p>全da写{{fun()}}</p>
</div>
</body>
</html>
<script>
new Vue({
el:"#box",
data:{
arr:"abcdefg"
},
methods: {
fun(){
return this.arr.toUpperCase();
}
},
computed: {//计算属性
},
})
</script>
3、那么计算属性和方法有什么区别呢?
①计算属性是基于它们的依赖进行缓存的。计算属性只有在它的相关依赖发生改变时才会重新求值。
②方法绑定数据只要被调用,方法将总会再次执行函数。(方法既是函数)
③计算属性相对于方法在处理特定场合下节省资源性能。
<!DOCTYPE html>
<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></title>
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="box">
<h1>函数方式全大写</h1>
<p>{{fun()}}</p>
<p>{{fun()}}</p>
<p>{{fun()}}</p>
<p>{{fun()}}</p>
<p>{{fun()}}</p>
<p>{{fun()}}</p>
<h1>计算属性全大写</h1>
<p>{{textb}}</p>
<p>{{textb}}</p>
<p>{{textb}}</p>
<p>{{textb}}</p>
<p>{{textb}}</p>
<p>{{textb}}</p>
</div>
</body>
</html>
<script>
new Vue({
el:"#box",
data:{
arr:"abcdefg"
},
methods: {
fun(){
console.log("函数");
return this.arr.toUpperCase();
},
funa(){
return this.arr.substr(0,1).toUpperCase();
}
},
computed: {
texta(){//texta是一个变量
console.log("计算属性");
return this.arr.toUpperCase();
},
textb(){
return this.arr.substr(0,1).toUpperCase();
}
},
})
</script>
十一、侦听/ 监听( watch)
watch就是用来data模型数据的监控,一旦数据发生了改变, 就会触发watch
1、监听的语法
1)watch:可以监听data模型数据 当模型数据改变的时候就会触发
watch:{//与data、methods同级
监听的data数据(newval,oldval){
console.log(newval+"---"+oldval);//处理逻辑
}
}
<!DOCTYPE html>
<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>Document</title>
<script src="node_modules/_vue@2.6.10@vue/dist/vue.min.js"></script>
<style>
</style>
</head>
<body>
<div id="demodiv" >
<!-- watch就是用来data模型数据的监控 一旦数据发送了改变就会触发对应的watch 初始化的时候wartch不会触发-->
<input type="text" v-model="text">
{{text}}
</div>
<script>
new Vue({
el:"#demodiv",
data:{
text:"aa"
},
methods:{
},
watch: {
// 你要监听的data数据(newval,oldval){
// 你要处理的逻辑
// }
//监听的数据是text
text(newval,oldval){
console.log("新值"+newval)
console.log("旧值"+oldval)
}
}
})
</script>
</body>
</html>
2)watch初始化的时候不会运行,只有数据被改变之后才会运行
javascript
2、 什么时候使用watch
1)当需要在数据变化时执行异步或开销较大的操作时,watch这个方式是最有用的。
2)计算属性与侦听器的区别:
①当watch监听的值发生改变就会被调用,watch可以在数据变化时做一些异步处理或者开销大的操作
;
②计算属性是计算依赖的值,当依赖的值发生改变才会触发。
<!DOCTYPE html>
<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>Document</title>
<script src="./node_modules/_vue@2.6.11@vue/dist/vue.min.js"></script>
<link rel="stylesheet" href="./node_modules/bootstrap/dist/css/bootstrap.min.css">
</head>
<body>
<div id="demodiv">
<div class="container">
<div class="row">
<div class="col-md-12">
<input type="text" class="form-control" v-model="inputa"/>
</div>
<div class="col-md-12">
<input type="text" class="form-control" v-model="inputb"/>
</div>
</div>
<div class="row">
<button type="button" class="btn btn-primary" @click="add()" :disabled="bool">添加</button>
<button type="button" class="btn btn-success">重置</button>
</div>
<div class="row">
<h1>用户信息表</h1>
</div>
<div class="row">
<table class="table table-hover table-bordered">
<tr>
<td>序号</td>
<td>名字</td>
<td>年龄</td>
<td>操作</td>
</tr>
<tr v-for="(v,i) in obj">
<td>{{i+1}}</td>
<td>{{v.title}}</td>
<td>{{v.age}}</td>
<td><button class="btn btn-success" data-toggle="modal" data-target="#myModal" v-on:click="delnum=i">删除</button></td>
</tr>
<tr v-if="obj.length>0">
<td colspan="4" class="text-right"><button class="btn btn-primary" data-toggle="modal" data-target="#myModal" v-on:click="delnum=-100">删除全部</button></td>
</tr>
<tr v-else>
<td colspan="4" class="text-center">暂无数据.......</td>
</tr>
</table>
</div>
</div>
<!-- 模态框代码 -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">确定删除吗?</h4>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal" v-on:click="del(delnum)">确定</button>
<button type="button" class="btn btn-primary" data-dismiss="modal">取消</button>
</div>
</div>
</div>
</div>
</div>
<script src="./node_modules/jquery/dist/jquery.min.js"></script>
<script src="./node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
<script>
new Vue({
el:"#demodiv",
data:{
bool:true,
inputa:"",
inputb:"",
delnum:0,
obj:[
{title:"小名",age:18},
{title:"小名1",age:181}
]
},
watch:{
// 监听第一个输入框与第二个输入框都不能为空的时候才可以让用户点击
inputa(){
if(this.inputa!=""&&this.inputb!=""){
this.bool=false;
}else{
this.bool=true;
}
},
inputb(){
if(this.inputa!=""&&this.inputb!=""){
this.bool=false;
}else{
this.bool=true;
}
}
},
methods:{
add(){
this.obj.push({title:this.inputa,age:this.inputb})
this.inputa="";
this.inputb="";
},
del(i){
console.log(i)
if(i>=0){
this.obj.splice(i,1);
}else{
this.obj=[];
}
}
}
})
</script>
</body>
</html>
注:①vue下载:npm install --save vue
②bootstrap下载:npm install --save bootstrap
③jQuery下载:npm install --save jquery
十二、过滤器(使用过滤器,要结合管道符 | 一起使用)
1、局部过滤器(与data、el 同级)
1)语法:
filters:{
过滤器的名字:function(val){ //val是形参,他是自动注入的,它代表 你要过滤的数据
return 输出的内容
}
}
<!DOCTYPE html>
<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></title>
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="box">
{{num|add}}
</div>
</body>
</html>
<script>
new Vue({
el:"#box",
data:{
num:19
},
methods: {
},
filters:{
add:function(val){//形参是我要过滤的数据
return '¥'+val
}
}
})
</script>
十三、 虚拟 dom 与 diff 算法
1、什么是虚拟DOM:所谓的虚拟 dom,也就是我们常说的虚拟节点,它是通过JS的Object对象模拟DOM中的节点,然后再通过特定的render(渲染)方法将其渲染成真实的DOM的节点。
2、 为什么使用虚拟DOM?
使用JQuery的时候,会大量操作DOM,那么DOM元素的变化自然会引起页面的回流或者重绘,页面的DOM重绘自然会导致页面性能下降,那么如何尽可能的去减少DOM的操作是框架需要考虑的一个重要问题!
3、 真实DOM和虚拟DOM的区别:
1)虚拟DOM不会进行排版与重绘操作;
2)真实DOM频繁排版与重绘的效率是相当低;
3)虚拟DOM进行频繁修改,然后一次性比较并修改真实DOM中需要改的部分,最后并在真实DOM中进行排版与重绘,减少过多DOM节点排版与重绘损耗;
4)虚拟DOM有效降低的重绘与排版,因为最终与真实DOM比较差异,可以只渲染局部。
4、 DOM Diff
1)虚拟DOM,是一种为了尽可能减少页面DOM频繁操作DOM的方式,那么在虚拟DOM中,通过什么方式才能做到呢? 就是Diff算法
2) DOM Diff原理
逐步解析newdom的节点,找到它在olddom中的位置,如果找到了就移动对应的DOM元素,如果没找到说明是新增节点,则新建一个节点插入。遍历完成之后如果oldVdom中还有没处理过的节点,则说明这些节点在newVdom中被删除了,删除它们即可
十四、过滤、接口数据请求、没数据时显示动画、props
1、过滤器
1)过滤器作用
①在不改变数据的情况下,输出前端需要的格式数据
②2.0中已经废弃了过滤器,需要我们自定义过滤器来使用filter
2)全局过滤器(写在vue实例之外)
<!DOCTYPE html>
<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>Document</title>
<script src="node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="demodiv">
aaaa {{texta|add}}
</div>
<div id="demodivb">
1111 {{textb|add}}
</div>
<div id="demodivc">
2222 {{textc|add}}
</div>
<script>
// 全局过滤器:可以在所有的vue实例中都可以使用
// 书写位置:写在vue实例之外
// Vue.filter("过滤器的名字",function(val){
// return 逻辑
// })
Vue.filter("add",function(val){
return "$"+val;
})
new Vue({
el:"#demodiv",
data:{
texta:"我是第一个"
}
})
new Vue({
el:"#demodivb",
data:{
textb:"我是第2个"
}
})
new Vue({
el:"#demodivc",
data:{
textc:"我是第3个"
}
})
</script>
</body>
</html>
2、局部过滤器
1)只能在当前vue注册内容中使用
2)在vue实例中与el属性data属性同级定义
3)
filters:{
过滤器名字 : function(val){
return 输出内容;
}
}
<!DOCTYPE html>
<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>Document</title>
<script src="node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="demodiv">
{{num|add}}
</div>
<script>
new Vue({
el:"#demodiv",
data:{
num:199
},
methods:{},
computed:{},
watch:{},
// 过滤器
// filters:{
// demo(val){
// return 逻辑
// }
// }
filters:{
add(val){
return "¥"+val
}
}
})
</script>
</body>
</html>
3、生命周期和数据请求
1)生命周期
①vue生命周期: Vue从创建到销毁的过程
② 钩子函数:生命周期内到特殊阶段被自动执行的函数叫做钩子函数(完成指定逻辑)
③8个钩子函数:(书写位置在data与methods同级处)
beforeCreate(创建实例)
created(创建完成)
beforeMount(开始创建模板)
mounted(创建完成)
beforeUpdate(开始更新)
updated(更新完成)
beforeDestroy(开始销毁)
destroyed(销毁完成)
注:一旦vue实例销毁了,数据就不能更新了。
<!DOCTYPE html>
<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></title>
<script src="./node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="box">
{{num}}
<button @click="fun()">点我更新数据</button>
<button @click="funb()">点我销毁数据</button>
</div>
</body>
</html>
<script>
new Vue({
el:"#box",
data:{
num:100
},
methods:{
fun(){
this.num="我是更新后的数据"
},
funb(){
// 销毁
this.$destroy();
}
},
computed:{},
watch:{},
filters:{},
beforeCreate() {
console.log("创建实例")
},
created() {
console.log("实例创建完成")
},
beforeMount() {
console.log("开始创建模板")
},
mounted() {
console.log("模板创建完成")
},
beforeUpdate() {
console.log("开始更新")
},
updated() {
console.log("更新完成")
},
beforeDestroy() {
console.log("开始销毁")
},
destroyed() {
console.log("销毁完成")
}
})
</script>
2)下载vue、axios
①下载vue :
npm install --save vue
②下载axios,请求数据 :
npm install --save axios
4、生命周期和数据请求
1)从后台请求到那个数据
<!DOCTYPE html>
<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></title>
<script src="./node_modules/vue/dist/vue.min.js"></script>
<script src="./node_modules/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="box">
<div v-for="(v,i) in arr" :key="v.id">
{{v.commentTxt}}
</div>
</div>
</body>
</html>
<script>
new Vue({
el:"#box",
data:{
arr:[]
},
methods: {
},
// 用户访问到我们当前项目的时候自动去请求后台数据进行数据的展示这块用created 和 mounted 都
//(不牵扯到处理页面的元素 而且vue是双向绑定的,模型变了,视图自然就会改变)
created() {
axios({
url:"http://api.artgoer.cn:8084/artgoer/api/v1/user/324380/v3/topic/topicHomeByLabel?pageIndex=1&token=b544cd63-6d42-46fe-a96c-3cf96bae3113&topicId=62187",
//不用发送数据
methods:"get"
}).then((ok)=>{
console.log(ok.data.data.commentList);
// ba他赋值给data中的变量
this.arr=ok.data.data.commentList
})
},
})
</script>
2)把值经过遍历,放到页面上,并且给,请求过程中,加一个动画
<!DOCTYPE html>
<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></title>
<script src="node_modules/vue/dist/vue.min.js"></script>
<script src="node_modules/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="box">
<!-- 让数据 长度等于零的时候,展示图片 -->
<div v-if="arr.length==0">
<img src="1.gif" alt="">
</div>
<div v-else>
<table>
<tr v-for="(v,i) in arr">
<td>{{v.commentTxt}}</td>
<td>{{v.userName}}</td>
<td>{{v.createAt|fil}}</td>
</tr>
</table>
</div>
</div>
</body>
</html>
<script>
new Vue({
el:"#box",
data:{
//设置一个变量存数据
arr:[]
},
// 用户访问到我们当前项目的时候自动去请求后台数据进行数据的展示这块用created 和 mounted 都( 不牵扯到处理页面的元素 而且vue是双向绑定的,模型变了,视图自然就会改变)
created() {
axios({
url:"http://api.artgoer.cn:8084/artgoer/api/v1/user/324380/v3/topic/topicHomeByLabel?pageIndex=1&token=b544cd63-6d42-46fe-a96c-3cf96bae3113&topicId=62187",
//不用发送数据
method:"get"
}).then((ok)=>{
//ba他赋值给data中的变量
console.log(ok.data.data.commentList);
this.arr=ok.data.data.commentList;
})
},
filters:{
//局部过滤器(把他留给最后一个td哪里,就好)
fil(val){//substring结束下标,包含开始,不包含结束
return val.substring(0,10);
}
}
})
</script>
5、组件
1) 全局组件的定义
①建议:组件名 (字母全小写且必须包含一个连字符)。这会帮助你避免和当前以及未来的 HTML 元素相冲突。
②语法:
Vue.component(‘name’, {
template: ‘<div></div>’
});
<!DOCTYPE html>
<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>Document</title>
<script src="node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="demodiv">
aaaa {{texta}}
<!-- 基本使用组件 -->
<tem></tem>
<!-- 驼峰命名法的组件使用 把大写转小写 前面加个- -->
<demo-tem-apple></demo-tem-apple>
<!-- 多个html标签组件调用 -->
<tema></tema>
</div>
<div id="demodivb">
1111 {{textb}}
</div>
<div id="demodivc">
2222 {{textc}}
</div>
<script>
// 组件:组件就是自定义控件/自定义标签 用来封装可以重复使用的html
// 全局组件:在任何vue实例中都可以使用
Vue.component("tem",{
template:"<div>我是一个全局组件</div>"
})
// 如果组件使用驼峰命名法起名字
Vue.component("demoTemApple",{
template:"<div>我是2个全局组件</div>"
})
// 多个html标签怎么办?如果组件有多个标签 那么必须必须必须用一个父元素包裹
Vue.component("tema",{
template:"<div><div>多个标签1</div><div>多个标签2</div><div>多个标签3</div></div>"
})
// 写道这个时候 发现标签写起来麻烦的一匹
// 外部组件模板 看下个例子
new Vue({
el:"#demodiv",
data:{
texta:"我是第一个"
}
})
new Vue({
el:"#demodivb",
data:{
textb:"我是第2个"
}
})
new Vue({
el:"#demodivc",
data:{
textc:"我是第3个"
}
})
</script>
</body>
</html>
2)局部组件(与data同级)
①语法:定义在vue实例中只能在当前实例范围内生效。
components:{
"组件名":{
template:"模板",
data(){
return {数据} //定义一个变量,例:text:"哈哈"
},
methods:{数据}
}
}
②在html中定义外部模板,向组件标签内 添加内容。
<template id="模板">
<div>
<p>{{ }}</p>
</div>
</template>
<!DOCTYPE html>
<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>Document</title>
<script src="node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="demodiv">
<com-demo></com-demo>
</div>
<!-- 定义外部模板,向<com-demo></com-demo>里面加 -->
<template id="tema">
<div>
<p>{{text}}</p>
<button @click="fun()">点我</button>
</div>
</template>
<script>
new Vue({
el:"#demodiv",
data:{},
components:{
"comDemo":{
template:"#tema",
data(){
return{
text:"局部组件的变量"
}
},
methods:{
fun(){
console.log("aaaaaa")
}
}
}
}
})
</script>
</body>
</html>
6、props
1)props选项,期待外部传值,在props中生命的变量默认是没有值,它的值是在调用。
2)组件的时候,从外部传进来的;
3)在 props组件中,创建位置与template等属性同级;
4)props默认情况下是字符串数组:
props:[" “,” ",…]
5)props验证
验证外部传进来的数据,是不是我们想要的数据类型
props:{
title:Number, //title它是传递过来的数据名
image:string //string 是接收的数据类型
}
6)语法
<!DOCTYPE html>
<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></title>
<script src="node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="box">
<!-- 传递的数据是写死的 -->
<com title="我是props"></com>
<!-- 传递的数据是一个动态的变量? -->
<com :title="vuetext"></com>
</div>
<template id="tem">
<div>
<h1>{{text}}{{title}}</h1>
</div>
</template>
</body>
<script>
// props选项 期待外部传值 在props中生命的变量默认是没有值的 他的值实在调用
// 组件的时候从外部传递进来
// props存在与组件中---------创建的位置也应该是组件中与template等属性同级
Vue.component("com",{
template:"#tem",
data(){
return {
text:'aaa'
}
},
// 默认情况下应该是一个字符串数组
// props:["title"]
// 但是在工作开发的过程中经常需要对外部传递进来数据进行数据类型等相关的验证
// props验证来进行数据类型的校验
// 如果引用的是min压缩的vue文件那么在这个时候是看不到错误的 所以要使用非压缩文
props:["title"]
})
let vm=new Vue({
el:"#box",
data:{
vuetext:"我是外部传递进来的变量"
}
})
</script>
</html>
7)验证
<!DOCTYPE html>
<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></title>
<!-- yong 压缩包,是不会报错的,所以不能用压缩包 -->
<script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="box">
<!-- 传递的数据是写死的,这块会报错 -->
<com title=111></com>
<!-- 传递的数据是一个动态的变量? -->
<com :title="vuetext"></com>
</div>
<template id="tem">
<div>
<h1>{{text}}{{title}}</h1>
</div>
</template>
</body>
<script>
// props选项 期待外部传值 在props中生命的变量默认是没有值的 他的值实在调用
// 组件的时候从外部传递进来
// props存在与组件中---------创建的位置也应该是组件中与template等属性同级
Vue.component("com",{
template:"#tem",
data(){
return {
text:'aaa'
}
},
// 默认情况下应该是一个字符串数组
// props:["title"]
// 但是在工作开发的过程中经常需要对外部传递进来数据进行数据类型等相关的验证
// props验证来进行数据类型的校验
// 如果引用的是min压缩的vue文件那么在这个时候是看不到错误的 所以要使用非压缩文
props:{
//判定是否为,数字类型
// title:Number
//判断是否是字符串和数字类型
title:[String,Number]
}
})
let vm=new Vue({
el:"#box",
data:{
//这块写的是数据类型
vuetext:2222
}
})
</script>
</html>
8)默认值和判断是否为空,不能混合使用
<!DOCTYPE html>
<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></title>
<!-- yong 压缩包,是不会报错的,所以不能用压缩包 -->
<script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="box">
<!-- 传递的数据是一个动态的变量? -->
<com :title="vuetext"></com>
<!-- 默认值,不传值 -->
<com></com>
</div>
<template id="tem">
<div>
<h1>{{text}}{{title}}</h1>
</div>
</template>
</body>
<script>
// props选项 期待外部传值 在props中生命的变量默认是没有值的 他的值实在调用
// 组件的时候从外部传递进来
// props存在与组件中---------创建的位置也应该是组件中与template等属性同级
Vue.component("com",{
template:"#tem",
data(){
return {
text:'aaa'
}
},
// 默认情况下应该是一个字符串数组
// props:["title"]
// 但是在工作开发的过程中经常需要对外部传递进来数据进行数据类型等相关的验证
props:{
//设置props默认值
title:{
type:String,
default:"我是props的默认值"
}
}
})
let vm=new Vue({
el:"#box",
data:{
//这块写的是数据类型
vuetext:'2222'
}
})
</script>
</html>
7、案例
<!DOCTYPE html>
<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></title>
<script src="../node_modules/axios/dist/axios.min.js"></script>\
<script src="../node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<!-- 这块用全局组件 -->
<div id="box">
<com></com>
</div>
<template id="tem">
<div>
</div>
</template>
</body>
<script>
Vue.component('com',{
template:'#tem',
//自己请求的东西,写自己这
created() {
axios({
url:"data.json",
method:"get",
}).then(function(ok){
//数据请求到了,把请求道德数据赋值给data
console.log(ok);
})
}
})
new Vue({
el:"#box",
data:{},
methods: {}
})
</script>
</html>
访问成功,输出到视图:
<!DOCTYPE html>
<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></title>
<script src="../node_modules/vue/dist/vue.min.js"></script>
<script src="../node_modules/axios/dist/axios.min.js"></script>
</head>
<body>
<!-- 这块用全局组件 -->
<div id="box">
<com></com>
</div>
<template id="tem">
<div>
<!-- 多个html的时候,需要一个父元素包裹 -->
<div>
<p v-for="(v,i) in arr">
<!-- 在这块使用管道符 -->
{{v.title|fil}}
<!-- :属性="变量" -->
<img :src="v.images.small" alt="">
</p>
</div>
</div>
</template>
</body>
<script>
Vue.component("com",{
//当一个数据过不来的时候可以 let that=this;
template:"#tem",
data(){
return{
arr:[]
}
},
//自己请求的东西,写自己这
created(){
axios({
url:"data.json",
method:"get",
}).then((ok)=>{//这块要用箭头函数,不要用匿名函数(因为this指向问题,用普通的匿名函数的话,this就不会指向component 当中去)
//数据请求到了,把请求道德数据赋值给data
console.log(ok.data.subjects);
this.arr=ok.data.subjects;
console.log(this.arr);
})
},
//使用过滤器
filters:{
fil(val){
return "《" + val + "》"
}
}
})
new Vue({
el:"#box"
})
</script>
</html>
403 代表访问到了,被人家给拒绝了,因为 这是站外盗链
十五、插槽(内容相同,数量不同 slot(槽口) 的作用)
slot 作用:用来混合父组件的内容与子组件自己的模板;
1、普通槽口
<!DOCTYPE html>
<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></title>
<script src="node_modules/vue/dist/vue.min.js"></script>
</head>
<body>
<div id="box">
<com>
<p>你好</p>
</com>
<com>
<p>你好2</p>
<p>你好2</p>
</com>
<com>
<p>你好3</p>
<p>你好3</p>
<p>你好3</p>
</com>
</div>
<template id="tem">
<div>
我是组件
<!-- 插槽 (比如内容心相同,数量不同,用槽口) 没有slot组件名中间插不进去东西 -->
<slot></slot>
</div>
</template>
</body>
<script>
new Vue({
el:"#box",
components:{
"com":{
template:"#tem"
}
}
})
</script>
</html>
2、具名槽口
① 元素可以用一个特殊属性 name 来配置如何分发内容;
②多个slot可以有不同的名字;
③具名slot将匹配内容片段中有对应slot特性的元素。
<!DOCTYPE html>
<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></title>
<script src="node_modules/vue/dist/vue.js"></script>
</head>
<body>
<div id="box">
<com>
<!-- 先定义一个任意标签,用slot属性指向 aa 才可以,这样插数据才会 更加准确 -->
<span slot="aa">你好a</span>
<span slot="bb">你好b</span>
<span slot="cc">你好c</span>
<!-- 你把多个内容指向一个槽口里面,也可以,但是美哟有人 会这样做 -->
</com>
</div>
<template id="tem">
<div>
我是组件
<!-- 具名 带有名字的槽口(槽口的名字用name) 如果想往带有名字的槽口中插入数据 必须对应的名字擦能插入 -->
<slot name="aa"></slot>
<slot name="bb"></slot>
<slot name="cc"></slot>
</div>
</template>
<script>
new Vue({
el:"#box",
components:{
"com":{
template:"#tem"
}
}
})
</script>
</body>
</html>
十六、路由、页面跳转、重定向、路由钩子、路由传参、hash模式-history模式
1、路由
之前已经使用js方式进行跳转路由----这种方式被称之为编程式导航
使用router-link进行跳转路由----称之为声明式
1)路由的概述
①路由的作用
a、路由:所有的路径都经由这个模块进行重新分配(改变URL,在不重新请求页面的情况下,更新页面视图。)
b、根据 url 锚点路径,在容器中加载不同的模块
c、完成 SPA(单页面应用)的开发
2)路由安装:
npm install --save vue-router
2、一级路由
- 用 Vue.js + Vue Router 创建单页面应用,是非常简单的。将组件 (components) 映射到路由 (routes),然后告诉 Vue Router 在哪里渲染它们。
① 定义 (路由) 组件模板
注意:外置模板(可以使用template模板进行html封装,调用id属性更加方便)
② 定义路由规则
使用component来进行路由映射组件;name属性是命名路由通过一个名称来标识一个路由;path是路径。
③创建 router 实例,然后传routes
配置(这个router是上面传进来的)
④ 创建和挂载根实例
通过 router 配置参数注入路由,从而让整个应用都有路由功能。
⑤使用标签设置路由跳转 to属性用来设置跳转链接; 路由出口表明路由模版显示的位置
注:a、当 对应的路由匹配成功,将自动设置 class 属性值 .router-link-active。
b、通过自动设置的类名方便进行路由导航样式设置。
3、编程式导航,既是js逻辑帮助我们进行逻辑跳转。(他写在vue实例中的methods里面)
使用this.$router全局路由的push()方法进行路由跳转
注:replace跳转与router书写地方一样(但是它回不去了)
区别:与push()唯一的不同就是,它不会向 历史url记录中添加新记录,而是跟它的方法名一样 —— 替换掉当前的 history 记录。
案例
<!DOCTYPE html>
<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>Document</title>
<script src="node_modules/vue/dist/vue.min.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.min.js"></script>
</head>
<body>
<div id="demodiv">
<!-- 路由跳转连接 -->
<!-- 使用router-link的方式叫做声明式导航声明式导航声明式导航声明式导航 -->
<router-link to="/tema">tema</router-link>
<router-link to="/temb">temb</router-link>
<router-link to="/temc">temc</router-link>
<router-link to="/temd">temd</router-link>
<!-- 大家观察一下上面的跳转方式-----必须通过用户的点击才能进行跳转 局限性太大 -->
<!-- 如果想让js逻辑帮助我们进行路由页面的跳转------要用到编程时导航(用js控制路由跳转方式叫做编程时导航)
-->
<button @click="funa()">编程式导航tema</button>
<button @click="funb()">编程式导航temb</button>
<button @click="func()">编程式导航temc</button>
<button @click="fund()">编程式导航temd</button>
<!-- 编程式当行的replace 替换(回不去了) -->
<button @click="fune()">replace跳转 tema</button>
<button @click="funf()">replace跳转 temb</button>
<button @click="fung()">replace跳转 temc</button>
<button @click="funh()">replace跳转 temd</button>
<!-- 路由出口 -->
<router-view></router-view>
</div>
<template id="tema">
<div>
A就卡死的就
</div>
</template>
<template id="temb">
<div>
B哈加达但撒谎
</div>
</template>
<template id="temc">
<div>
C和大数据扩大
</div>
</template>
<template id="temd">
<div>
D骄傲傻傻的
</div>
</template>
<script>
// 1.创建组件模版
let tema={template:"#tema"};
let temb={template:"#temb"};
let temc={template:"#temc"};
let temd={template:"#temd"};
// 2.定义路由规则
let routes=[
{name:"tema",path:"/tema",component:tema},
{name:"temb",path:"/temb",component:temb},
{name:"temc",path:"/temc",component:temc},
{name:"temd",path:"/temd",component:temd}
]
// 3.实例化路由对象
let router=new VueRouter({
routes
})
new Vue({
el:"#demodiv",
router,
methods:{
funa(){
// 编程式路由跳转
this.$router.push("/tema");
},
funb(){
// 编程式路由跳转
this.$router.push("/temb");
},
func(){
// 编程式路由跳转
this.$router.push("/temc");
},
fund(){
// 编程式路由跳转
this.$router.push("/temd");
},
// replace跳转
fune(){
this.$router.replace("/tema");
},
funf(){
this.$router.replace("/temb");
},
fung(){
this.$router.replace("/temc");
},
funh(){
this.$router.replace("/temd");
},
}
})
</script>
</body>
</html>
4、用户输入错误的url提示
1)常规参数只会被 / 分割的URL片段中的字符匹配;如果要匹配任意路径,我们可以使用通配符 *
{name:“teme”,path:"*",component:teme}
2)匹配任意开头的路径使用通配符 *
注:
①当使用通配符路由时,请确保路由的顺序是正确的,也就是说含有通配符的路由应该放在最后。路由 { path: ‘*’ } 通常用于客户端 404 错误(一般情况下,它用不到)
② 同一个路径可以匹配多个路由,此时,匹配的优先级就按照路由的定义顺序:谁先定义的,谁的优先级就最高。
3 )this.$router.go(n)这个方法的参数是一个整数,意思是在 history 记录中向前或者后退多少步,类似 window.history.go(n)。
4)重定向(他要写到最后面)
<!DOCTYPE html>
<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></title>
<script src="node_modules/vue/dist/vue.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.min.js"></script>
</head>
<body>
<div id="box">
<router-link to="/in1">tema</router-link>
<router-link to="/in2">temb</router-link>
<router-link to="/in3">temc</router-link>
<router-link to="/in4">temd</router-link>
<router-view></router-view>
</div>
<template id="tema">
<div>
按市场内地市场的
</div>
</template>
<template id="temb">
<div>
此处乃是两次都是看到
</div>
</template>
<template id="temc">
<div>
彻底删除你是对此
</div>
</template>
<template id="temd">
<div>
随擦但是 地擦拭
</div>
</template>
<!-- 404的外部组件 -->
<template id="teme">
<div>
<h1>404</h1>
</div>
</template>
<script>
let tema={template:"#tema"};
let temb={template:"#temb"};
let temc={template:"#temc"};
let temd={template:"#temd"};
//创建一个404页面组件
let teme={template:"#teme"}
let routes=[
{name:"tema",path:"/in1",component:tema},
{name:"temb",path:"/in2",component:temb},
{name:"temc",path:"/in3",component:temc},
{name:"temd",path:"/in4",component:temd},
//定义404路由的规则(当地址输入错误,就提示404);它一般情况下,用不到
{name:"teme",path:"*",component:teme}
/*重定向的写法非常的简单 只需在在路由规则中定义,这样就可以跳转到指定的页面组件
{path:"/*",redirect:"/in1"}*/
]
let router=new VueRouter({
routes
})
new Vue({
el:"#box",
router
})
</script>
</body>
</html>
5、二级路由
1)配置二级路由路径参数中使用 children 配置(路径前不加斜杠)
2)配置模板
<!DOCTYPE html>
<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>Document</title>
<script src="./node_modules/vue/dist/vue.min.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.min.js"></script>
<style>
.bottombar{
width: 100%;
display: flex;
flex-direction: row;
position: fixed;
bottom: 0px;
}
.bottombar>a{
flex: 1;
}
.bottombar>.router-link-active{
background-color: pink;
}
</style>
</head>
<body>
<div id="demodiv">
<div class="bottombar">
<router-link to="/tema">首页</router-link>
<router-link to="/temb/era">书影音</router-link>
<router-link to="/temc">小组</router-link>
<router-link to="/temd">我的</router-link>
</div>
<router-view></router-view>
</div>
<template id="tema">
<div>
tema
</div>
</template>
<template id="temb">
<div>
temb
<!-- 3.设置二级路由的跳转和出口 注意必须在对应的一级路由的组件模版中进行设置 -->
<div class="topbar">
<router-link to="/temb/era">国产剧</router-link>
<router-link to="/temb/erc">港台剧</router-link>
<router-link to="/temb/erd">日韩剧</router-link>
<router-link to="/temb/ere" >欧美剧</router-link>
</div>
<router-view></router-view>
</div>
</template>
<template id="temc">
<div>
temc
</div>
</template>
<template id="temd">
<div>
temd
</div>
</template>
<!-- 二级路由的外部模版 -->
<template id="era">
<div>
国产剧
</div>
</template>
<template id="erc">
<div>
港台剧
</div>
</template>
<template id="erd">
<div>
日韩剧
</div>
</template>
<template id="ere">
<div>
欧美剧
</div>
</template>
<script>
// 多集路由的创建方式
let tema={template:"#tema"};
let temb={template:"#temb"};
let temc={template:"#temc"};
let temd={template:"#temd"};
// 1.二级路由---创建组件与组件模版
let era={template:"#era"};
let erc={template:"#erc"};
let erd={template:"#erd"};
let ere={template:"#ere"};
let routes=[
{name:"tema",path:"/tema",component:tema},
// 2.二级路由----设置路由规则 使用children
{
name:"temb",
path:"/temb",
component:temb,
children:[
// 路径前面不加/不加/不加/不加/不加/不加/不加/
{name:"era",path:"era",component:era},
{name:"erc",path:"erc",component:erc},
{name:"erd",path:"erd",component:erd},
{name:"ere",path:"ere",component:ere},
]
},
{name:"temc",path:"/temc",component:temc},
{name:"temd",path:"/temd",component:temd},
//重定向
{path:"/*",redirect:"/tema"}
]
let router=new VueRouter({
routes
})
new Vue({
el:"#demodiv",
router
})
</script>
</body>
</html>
6、路由守卫,导航守卫
用途:vue项目中经常在路由跳转前做一些验证,比如登录验证,是网站中的普遍需求
。
1)全局前置守卫
①当一个导航触发时,全局前置守卫(在进入组件之前
)按照创建顺序调用。
②vue-router 提供的 router.beforeEach((to,from,next)=>{})可以方便地实现全局前置导航守卫
a: to:即将要进入的目标 路由对象
b: from: 当前导航正要离开的路由
c: next: 下一步执行
2)局后置钩子
①当一个导航触发时,全局后置钩子(在进入组件之后
)调用。
②vue-router 提供的 router.afterEach((to, from) => {})实现全局后置守卫
③to:即将要进入的目标 路由对象
④from: 当前导航正要离开的路由
<!DOCTYPE html>
<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></title>
<script src="node_modules/vue/dist/vue.js"></script>
<script src="vue-router.js"></script>
</head>
<body>
<div id="box">
<router-link to="/in1">首页</router-link>
<router-link to="/in2">详情页</router-link>
<router-link to="/in3">注册</router-link>
<router-link to="/in4">登录</router-link>
<router-view></router-view>
</div>
<template id="tema">
<div>
首页
</div>
</template>
<template id="temb">
<div>
详情页
</div>
</template>
<template id="temc">
<div>
注册
</div>
</template>
<template id="temd">
<div>
登录
</div>
</template>
</body>
<script>
let tema={template:"#tema"};
let temb={template:"#temb"};
let temc={template:"#temc"};
let temd={template:"#temd"};
let routes=[
{name:"tema",path:"/in1",component:tema},
{name:"temb",path:"/in2",component:temb},
{name:"temc",path:"/in3",component:temc},
{name:"temd",path:"/in4",component:temd},
{path:"/*",redirect:"/in1"}
]
let router=new VueRouter({
routes
});
// to即将进入的路由
// from即将离开的路由
// next 下一步
router.beforeEach((to, from, next) => {
console.log(to);
console.log(from);
next();
})
new Vue({
el:"#box",
router
})
</script>
</html>
点击首页和产品时 让其登陆后访问,点击登录或注册 直接切换,做法如下:
<!DOCTYPE html>
<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></title>
<script src="node_modules/vue/dist/vue.js"></script>
<script src="vue-router.js"></script>
</head>
<body>
<div id="box">
<router-link to="/in1">首页</router-link>
<router-link to="/in2">详情页</router-link>
<router-link to="/in3">注册</router-link>
<router-link to="/in4">登录</router-link>
<router-view></router-view>
</div>
<template id="tema">
<div>
首页
</div>
</template>
<template id="temb">
<div>
详情页
</div>
</template>
<template id="temc">
<div>
注册
</div>
</template>
<template id="temd">
<div>
登录
</div>
</template>
</body>
<script>
let tema={template:"#tema"};
let temb={template:"#temb"};
let temc={template:"#temc"};
let temd={template:"#temd"};
let routes=[
{name:"tema",path:"/in1",component:tema},
{name:"temb",path:"/in2",component:temb},
{name:"temc",path:"/in3",component:temc},
{name:"temd",path:"/in4",component:temd},
// {path:"/*",redirect:"/in3"}
]
let router=new VueRouter({
routes
});
// to即将进入的路由
// from即将离开的路由
// next 下一步
router.beforeEach((to, from, next) => {
/*console.log(to);
console.log(from);
next();*/
//给一个判断(让路径定于神魔 to.path)
if(to.path=="/in3"||to.path=="/in4"){//如果是他俩正常进入
next();//下一步
}else{
alert("您没有登录,请登录之后访问");
//next里面写 一个值,指的 踢回这个路径里
next("/in3")//next里面一个值,让其返回到那个路径里面
}
})
// 全局后置钩子(已经进来成功了,进行了下一步,依然会使用)
router.afterEach((to, from) => {
console.log("全局后置钩子")
})
new Vue({
el:"#box",
router
})
</script>
</html>
3)路由独享
①与全局前置守卫相比路由独享守卫只是对一个人路由进行单一控制 参数和全局前置守卫相同
②在路由配置上直接定义 beforeEnter 进行路由独享守卫定义
4)路由组件更多的使用
①组件内守卫只会对当前组件生效。
②在组件中使用beforeRouteEnter(to, from, next) {}
来进行进入组建前的钩子;
<!DOCTYPE html>
<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></title>
<script src="node_modules/vue/dist/vue.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.min.js"></script>
</head>
<body>
<div id="box">
<router-link to="/tama">拉拉</router-link>
<router-link to="/tamb">哈哈</router-link>
<router-link to="/tamc">嘿嘿</router-link>
<router-link to="/tamd">呵呵</router-link>
<router-view></router-view>
</div>
<template id="tema">
<div>
A{{text}}
</div>
</template>
<template id="temb">
<div>
B
</div>
</template>
<template id="temc">
<div>
C
</div>
</template>
<template id="temd">
<div>
D
</div>
</template>
<script>
let tema={
template:"#tema",
data(){
return{
text:"我是变量"
}
},
//进入组件前自动执行下面的函数(在组件里面写,没有太大的作用)
beforeRouteEnter (to, from, next) {
next((d)=>{//随便写一个参数 打印出来了,这个组件的相关信息
console.log(d);
})
}
};
let temb={template:"#temb"};
let temc={template:"#temc"};
let temd={template:"#temd"};
let routes=[
{name:"tema",path:"/tama",component:tema},
{name:"temb",path:"/tamb",component:temb},
{name:"temc",path:"/tamc",component:temc},
{name:"temd",path:"/tamd",component:temd}
]
let router=new VueRouter({
routes
})
new Vue({
el:"#box",
router
})
</script>
</body>
</html>
③在组件中使用beforeRouteLeave(to, from, next) {}来进行离开组件的钩子。
可以 用来判断是否离开当前页面
<!DOCTYPE html>
<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></title>
<script src="node_modules/vue/dist/vue.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.min.js"></script>
</head>
<body>
<div id="box">
<router-link to="/tama">拉拉</router-link>
<router-link to="/tamb">哈哈</router-link>
<router-link to="/tamc">嘿嘿</router-link>
<router-link to="/tamd">呵呵</router-link>
<router-view></router-view>
</div>
<template id="tema">
<div>
A{{text}}
</div>
</template>
<template id="temb">
<div>
B
</div>
</template>
<template id="temc">
<div>
C
</div>
</template>
<template id="temd">
<div>
D
</div>
</template>
<script>
let tema={
template:"#tema",
data(){
return{
text:" 我是变量"
}
},
//进入组件前自动执行下面的函数(在组件里面写,没有太大的作用)
beforeRouteEnter (to, from, next) {
next((d)=>{//随便写一个参数
console.log(d.text);
})
/*
//或者下面这个写法
beforeRouteEnter(to, from, next) {
next(that=>{//这里的vm指的就是vue实例,可以用来当做this使用
console.log(that);//这样就可以修改data里面的变量
})
}
*/
},
//离开组件的时候
beforeRouteLeave (to, from, next) {
if(confirm("你是否要离开 '拉拉'")==true){
next()
}else{
next(false)
}
}
};
let temb={template:"#temb"};
let temc={template:"#temc"};
let temd={template:"#temd"};
let routes=[
{name:"tema",path:"/tama",component:tema},
{name:"temb",path:"/tamb",component:temb},
{name:"temc",path:"/tamc",component:temc},
{name:"temd",path:"/tamd",component:temd}
]
let router=new VueRouter({
routes
})
new Vue({
el:"#box",
router
})
</script>
</body>
</html>
5)路由知识点扩展—数据获取
①进入某个路由后,需要从服务器获取数据。例如,在渲染用户信息时,你需要从服务器获取用户的数据。我们可以通过两种方式来实现
②导航完成之后获取:先完成导航,然后在接下来的组件生命周期钩子中获取数据
③导航完成之前获取:导航完成前,在路由进入的守卫中获取数据,在数据获取成功后执行导航。
④从技术角度讲,两种方式都不错 —— 就看你想要的用户体验是哪种。
7、 路由传参
把一个参数从一个页面传到另外一个页面,把数据通过路由,把数据从一个页面传到另外一个页面;组件传参,是一个组件,传到另一个;路由传参,是页面之间
方式大体分为两种:params、 query
1)params的方式
<!DOCTYPE html>
<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>Document</title>
<script src="../node_modules/vue/dist/vue.min.js"></script>
<script src="../vue-router.js"></script>
</head>
<body>
<div id="demodiv">
<!-- 路由跳转连接 -->
<router-link to="/tema">tema</router-link>
<router-link to="/temb">temb</router-link>
<router-link to="/temc">temc</router-link>
<!-- 1-2发送数据 -->
<!-- <router-link to="/temd/数据">temd</router-link> -->
<!-- 发送数据方式2 推荐第二种,name对应的是下面路由跳转规则的name -->
<router-link :to="{name:'temd',params:{xiaoming:'我是第二种方式发送的数据'}}">temd</router-link>
<!-- 编程时方式自己尝试 -->
<!-- 路由出口 -->
<router-view></router-view>
</div>
<template id="tema">
<div>
tema
</div>
</template>
<template id="temb">
<div>
temb
</div>
</template>
<template id="temc">
<div>
temc
</div>
</template>
<template id="temd">
<div>
temd
<!-- 1-3接收参数 -->
{{this.$route.params.xiaoming}}
</div>
</template>
<script>
/* 动态路由匹配/路由传参
1.params方式传参
(1-1)在路由规则中设置接受参数
(1-2)发送数据
(1-3)接收参数
注:全文的 xiaoming 可以随意改
*/
let tema={template:"#tema"};
let temb={template:"#temb"};
let temc={template:"#temc"};
let temd={template:"#temd"};
let routes=[
{name:"tema",path:"/tema",component:tema},
{name:"temb",path:"/temb",component:temb},
{name:"temc",path:"/temc",component:temc},
// (1-1)在路由规则中设置接受参数(给d发送)
{name:"temd",path:"/temd/:xiaoming",component:temd}
]
let router=new VueRouter({
routes
})
new Vue({
el:"#demodiv",
router
})
</script>
</body>
</html>
2) query的方式
<!DOCTYPE html>
<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>Document</title>
<script src="../node_modules/vue/dist/vue.min.js"></script>
<script src="../vue-router.js"></script>
</head>
<body>
<div id="demodiv">
<!-- 路由跳转连接 -->
<router-link to="/tema">tema</router-link>
<router-link to="/temb">temb</router-link>
<router-link to="/temc">temc</router-link>
<!-- // (1)设置发送数据 建议用第二种-->
<!-- <router-link to="/temd?xiaoming=我是数据1111111 & lala=多个数据">temd</router-link> -->
<router-link :to="{name:'temd',query:{xiaoming:'数据2'}}">temd</router-link>
<!-- <router-link :to="{path:'/temd',query:{xiaoming:'数据33333333'}}">temd</router-link> -->
<!-- 路由出口 -->
<router-view></router-view>
</div>
<template id="tema">
<div>
tema
</div>
</template>
<template id="temb">
<div>
temb
</div>
</template>
<template id="temc">
<div>
temc
</div>
</template>
<template id="temd">
<div>
temd
<!-- // (2)设置接收 -->
{{this.$route.query.xiaoming}}
</div>
</template>
<script>
/* query传参
(1)设置发送数据
(2)设置接收
*/
let tema={template:"#tema"};
let temb={template:"#temb"};
let temc={template:"#temc"};
let temd={template:"#temd"};
let routes=[
{name:"tema",path:"/tema",component:tema},
{name:"temb",path:"/temb",component:temb},
{name:"temc",path:"/temc",component:temc},
{name:"temd",path:"/temd",component:temd}
]
let router=new VueRouter({
routes
})
new Vue({
el:"#demodiv",
router
})
</script>
</body>
</html>
3)params与query区别
①用法上的:query要用path来引入,params要用name来引入,接收参数都是类似的,分别是this.$route.query.name和this.$route.params.name
。
②url展示上的
③params类似于post,query更加类似于我们ajax中get传参,说的再简单一点,前者在浏览器地址栏中不显示参数,后者显示,所以params传值相对安全一些。
8、hash模式-history模式
1)hash模式url里面永远带着#号,我们在开发当中默认使用这个模式。
2)history模式
①history模式没有#号,是个正常的url适合推广宣传
。
②考虑url的规范那么就需要使用history模式,因为当然其功能也有区别,在开发app的时候有分享页面,这个分享出去的页面就是用vue做的,把这个页面分享到第三方的app里,有的app里面url是不允许带有#号的,所以要将#号去除那么就要使用history模式,history模式还有一个问题就是,做刷新操作,会出现404错误
,那么就需要和后端人士配合让他配置一下apache或是nginx的url重定向,重定向到你的首页路由上。
<!DOCTYPE html>
<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>Document</title>
<script src="node_modules/vue/dist/vue.min.js"></script>
<script src="vue-router.js"></script>
</head>
<body>
<div id="demodiv">
<!-- 路由跳转连接 -->
<router-link to="/tema">tema</router-link>
<router-link to="/temb">temb</router-link>
<router-link to="/temc">temc</router-link>
<router-link to="/temd">temd</router-link>
<!-- 路由出口 -->
<router-view></router-view>
</div>
<template id="tema">
<div>
tema
</div>
</template>
<template id="temb">
<div>
temb
</div>
</template>
<template id="temc">
<div>
temc
</div>
</template>
<template id="temd">
<div>
temd
</div>
</template>
<script>
// history模式的设置
// hash模式url中默认带有#
// history模式 没有#更加适合推广使用
// history模式还有一个问题就是,做刷新操作,会出现404错误,
// 那么就需要和后端人配合让他配置一下apache或是nginx的url重定向,重定向到你的首页路由上。
let tema={template:"#tema"};
let temb={template:"#temb"};
let temc={template:"#temc"};
let temd={template:"#temd"};
let routes=[
{name:"tema",path:"/tema",component:tema},
{name:"temb",path:"/temb",component:temb},
{name:"temc",path:"/temc",component:temc},
{name:"temd",path:"/temd",component:temd}
]
let router=new VueRouter({
routes,
mode:"history"
})
new Vue({
el:"#demodiv",
router
})
</script>
</body>
</html>
刚打开:
刷新一哈(刷新之前,要先点击一哈),他就会报错
十七、新闻案例
<!DOCTYPE html>
<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></title>
<script src="node_modules/vue/dist/vue.js"></script>
<script src="./node_modules/vue-router/dist/vue-router.min.js"></script>
<style>
.bot{
width:80%;
display:flex;
flex-direction:row;
position:fixed;
bottom: 100px;
left:100px;
}
.bot>a{
flex:1;
}
</style>
</head>
<body>
<!-- box属于实例,创建组件在实例中,创建 -->
<div id="box">
<router-view></router-view>
<bottom></bottom>
</div>
<template id="tema">
<div>
首页
</div>
</template>
<template id="temb">
<div>
新闻列表<!-- 把新闻列表遍历出来( 不管点击那一条,都跳转到详情页面) -->
<ul>
<li v-for="(v,i) in newlist">
<router-link :to="{name:'home3',params:{xiaoming:v.id}}">{{v.title}}</router-link>
</li>
</ul>
</div>
</template>
<template id="temc">
<div>
新闻详情
{{this.$route.params.xiaoming}}
<!-- 我们写的是数组 -->
<h1>{{obj[0].title}}</h1>
<p>{{obj[0].content}}</p>
</div>
</template>
<!-- 底部 bottom 的外部模板 -->
<template id="bottomtem">
<div class="bot"><!--给他谁设置样式 -->
<!-- 这个里面写跳转链接 -->
<router-link to="/tema">首页</router-link>
<router-link to="/temb">列表</router-link>
<!-- 不用它 -->
<!-- <router-link to="/temc">详情</router-link> -->
<!-- rang其输出在box里 -->
</div>
</template>
</body>
<script>
//定义组件 新闻就应该写在新闻列表的组件里 自己事情自己做
let tema={template:"#tema"};
let temb={
template:"#temb",
//创建数据
data(){
return{
newlist:[
//第一数据题目
{id:11,title:"csbn视频中说了什么?",
//第二条数据 内容
content:"csbn"},
{id:22,title:"csbn如何回应?",
content:"..............。"},
{id:33,title:"dasdasdasdasdasdasdasdsadsa",
content:"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX。....."}
]
}
}
};
let temc={
template:"#temc",
data(){
//这块应该是Ajax传参
return{
// a 下面赋值上来的
obj:[],
newlist:[
//第一数据题目
{id:11,title:"视频中说了什么?",
//第二条数据 内容
content:"啦啊啊啊啊啊啦啦啦啦啦啦啦啦啦啦啦啦啦"},
{id:22,title:"如何回应?",
content:"啦啊啊啊啊啊啦啦啦啦啦啦啦啦啦啦啦啦啦..............。"},
{id:33,title:"啦啊啊啊啊啊啦啦啦啦啦啦啦啦啦啦啦啦啦”",
content:"啦啊啊啊啊啊啦啦啦啦啦啦啦啦啦啦啦啦啦。....."}
]
}
},
//页面加载之后
created() {
console.log(this.$route.params.xiaoming);
// a 过滤数组,会返回一个新的数组 (newtemc这个就是我想要的id数据,把这个赋值给data)
let newtemc=this.newlist.filter((v,i)=>{
if(this.$route.params.xiaoming==v.id){
return v;
}
})
this.obj=newtemc;
console.log(this.obj)
//然后去新闻详情页
}
}
//路由规则
let routes=[
{name:"home1",path:"/tema",component:tema},
{name:"home2",path:"/temb",component:temb},
/*用params传:
1、在路由规则里配置接收id;
2、在路由跳转位置发送参数;
3、接收数据
*/
{name:"home3",path:"/temc/:xiaoming",component:temc},
//设置重定向
{path:"*",redirect:"/tema"}
]
let router=new VueRouter({
routes
})
new Vue({
el:"#box",
router,
//创建局部组件
components:{
"bottom":{
template:"#bottomtem"
}
}
})
</script>
</html>