& VUE 学习记录-1
VUE学习记录
Day01
什么是Vue.js
- Vue.js 是目前最火的一个前端框架,React是最流行的一个前端框架(React除了开发网站,还可以开发手机App, Vue语法也是可以用于进行手机App开发的,需要借助于Weex)
- Vue.js 是前端的主流框架之一,和Angular.js、React.js 一起,并成为前端三大主流框架!
- Vue.js 是一套构建用户界面的框架,只关注视图层,它不仅易于上手,还便于与第三方库或既有项目整合。(Vue有配套的第三方类库,可以整合起来做大型项目的开发)
- 前端的主要工作?主要负责MVC中的V这一层;主要工作就是和界面打交道,来制作前端页面效果;
为什么要学习流行框架
- 企业为了提高开发效率:在企业中,时间就是效率,效率就是金钱;
- Jquery + art-template + Ajax
- 在没有前端框架之前,我们前端需要经常的操作DOM元素;
- 在项目中,vue 能够简化DOM操作,让程序员根本不用操作任何DOM元素,就能渲染页面;
- 企业中,使用框架,能够提高开发的效率;
- 提高开发效率的发展历程:原生JS -> Jquery之类的类库 -> 前端模板引擎 -> Angular.js / Vue.js(能够帮助我们减少不必要的DOM操作;提高渲染效率;双向数据绑定的概念【通过框架提供的指令,我们前端程序员只需要关心数据的业务逻辑,不再关心DOM是如何渲染的了】)
- 在Vue中,一个核心的概念,就是让用户不再操作DOM元素,解放了用户的双手,让程序员可以更多的时间去关注业务逻辑;
框架
和库
的区别
- 框架:是一套完整的解决方案;对项目的侵入性较大,项目如果需要更换框架,则需要重新架构整个项目。
node 中的 express; - 库(插件):提供某一个小功能,对项目的侵入性较小,如果某个库无法完成某些需求,可以很容易切换到其它库实现需求。
- 从Jquery 切换到 Zepto
- 从 EJS 切换到 art-template
Node(后端)中的MVC
与 前端中的 MVVM
之间的区别
- MVC 是后端的分层开发概念;
- MVVM是前端视图层的概念,主要关注于 视图层分离,也就是说:MVVM把前端的视图层,分为了 三部分 Model, View , VM ViewModel
Vue之 - 基本的代码结构和插值表达式
、v-cloak
- 使用 插值表达式,存在内容闪烁的问题,但是,
v-text
没有闪烁问题; - 在插值表达式中,可以使用
v-cloak
解决闪烁问题; - 插值表达式只会插入内容,并不会清楚其余的内容;
v-text
会把元素中之前的内容都清空!
Vue指令之v-text和v-html
<div id="app">
<div v-text="msg3"></div>
<div v-html="msg3"></div>
</div>
<script>
//这列new Vue()得到的VM实例就是MVVM中的核心 VM,他提供了双向数据绑定的能力
let vue = new Vue({
//指定当前要创建的这个vm实例,要控制页面上哪个区域 element 此处el属性指定的元素就是我们的MVVM中的V视图层
el:'#app',
//data是一个对象,表示我们要渲染的一些数据 此处data属性就是MVVM中的M视图数据层
data:{
msg3:'<h6>小标题</h6>',
}
});
</script>
Vue指令之v-bind
的三种用法
- 直接使用指令v-bind
- 使用简化指令:
- 在绑定的时候,拼接绑定内容::title=”btnTitle + ‘, 这是追加的内容’”
<body>
<!--创建一个容器,将来使用VUE就可以控制这个指定容器中的所有DOM元素-->
<div id="app">
<!--v-bind: 可以为元素的属性绑定一些数据-->
<input type="button" value="按钮" v-bind:title="btnTitle">
<hr>
<input type="button" value="按钮" v-bind:id="customIdName" >
<hr>
<!--v-bind: 这个指令可以被简写成 :-->
<input type="button" value="按钮" :title="btnTitle">
<hr>
<input type="button" value="按钮" :id="customIdName" >
<hr>
<!--v-bind: 指令中,如果想要实现表达式的拼接,被拼接的字符串一定要用引号包裹起来,否则会被当做变量解析-->
<input type="button" value="按钮" :title="btnTitle + '这是追加的内容'">
</div>
<script>
//这列new Vue()得到的VM实例就是MVVM中的核心 VM,他提供了双向数据绑定的能力
let vue = new Vue({
el:'#app',//指定当前要创建的这个vm实例,要控制页面上哪个区域 element 此处el属性指定的元素就是我们的MVVM中的V视图层
data:{//data是一个对象,表示我们要渲染的一些数据 此处data属性就是MVVM中的M视图数据层
btnTitle:'这是按钮的自定义title值',
customIdName:'这是按钮的自定义id值'
}
});
</script>
</body>
Vue指令之v-on
和跑马灯效果
跑马灯效果
<!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="./lib/vue-2.5.9.js"></script>
</head>
<body>
<div id="app">
<!--<input type="button" value="浪起来" id="btn1" v-on:click="lang" >-->
<input type="button" value="浪起来" id="btn1" @click="lang" >
<input type="button" value="stop浪" id="btn2" @click="stop">
<hr>
<h3>{{ msg }}</h3>
</div>
<script>
let vue = new Vue({
el:'#app',
data:{
msg: '猥琐发育别浪~',
intervalId: null //定时器的id
},
methods:{
lang(){
if(this.intervalId != null){
return;
}
//定时器
this.intervalId = setInterval(() => {
let header = this.msg.substring(0,1)
let body = this.msg.substring(1)
this.msg = body + header
},300);
},
stop(){
clearInterval(this.intervalId)
}
}
});
</script>
</body>
</html>
Vue指令之v-on
的缩写@
和事件修饰符
事件修饰符:
- .stop 阻止冒泡 事件修饰符之.stop详解
- .prevent 阻止默认事件 事件修饰符之.prevent详解
- .capture 添加事件侦听器时使用事件捕获模式 事件修饰符之.capture .self .once 详解
- .self 只当事件在该元素本身(比如不是子元素)触发时触发回调 事件修饰符之.capture .self .once 详解
- .once 事件只触发一次 事件修饰符之.capture .self .once 详解
事件修饰符之.stop详解
<!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="./lib/vue-2.5.9.js"></script>
<style>
#inner {
background-color: pink;
height: 150px;
width: 200px;
}
#inner2 {
background-color: pink;
height: 150px;
width: 200px;
}
</style>
</head>
<body>
<div id="app">
<!--此处点击按钮 会触发冒泡事件 btnClick->innerClick -->
<div id="inner" @click="innerClick">
<input type="button" value="按钮" @click="btnClick">
</div>
<hr>
<div id="inner2" @click="innerClick">
<!--.stop阻止冒泡事件-->
<input type="button" value="按钮" @click.stop="btnClick">
</div>
</div>
<script>
let vue = new Vue({
el: '#app',
data: {},
methods: {
innerClick() {//内部的div点击事件
console.log("内部的div点击事件")
},
btnClick(){//按钮的点击事件
console.log("按钮的点击事件")
}
}
});
</script>
</body>
</html>
事件修饰符之.capture .self .once 详解
<body>
<div id="app">
<!--a链接-->
<a href="http://www.baidu.com" @click.prevent="linkClick">百度百度</a>
<!--表单-->
<form @submit.prevent="postForm">
<input type="text" name="username">
<input type="text" name="gender">
<input type="submit" value="提交表单">
</form>
</div>
<script>
let vue = new Vue({
el: '#app',
data: {},
methods: {
linkClick(){
console.log("按钮呗点击了")
},
postForm(){
console.log("触发了表单的submit")
//阻止了form的默认行为之后,就可以在这里就可以自定义调用接口
}
}
});
</script>
</body>
事件修饰符之.prevent详解
<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="./lib/vue-2.5.9.js"></script>
<style>
.inner {
background-color: pink;
height: 150px;
width: 200px;
}
</style>
</head>
<body>
<div id="app">
<!--.capture添加事件侦听器时使用事件捕获模式-->
<div class="inner" @click.capture="innerClick">
<input type="button" value="按钮" @click="btnClick">
</div>
<hr>
<div class="inner" @click.self="innerClick">
<!--.self只当事件在该元素本身(比如不是子元素)触发时触发回调-->
<input type="button" value="按钮" @click="btnClick">
</div>
<hr>
<!--.once只执行一次-->
<div class="inner" @click.once="innerClick">
<input type="button" value="按钮" @click="btnClick">
</div>
</div>
<script>
let vue = new Vue({
el: '#app',
data: {},
methods: {
innerClick() {//内部的div点击事件
console.log("内部的div点击事件")
},
btnClick(){//按钮的点击事件
console.log("按钮的点击事件")
}
}
});
</script>
</body>
capture
self
once
Vue指令之v-model
和双向数据绑定
v-bind
: 指令只能实现数据的单项绑定,从data自动同步到view上- 在Vue中,只有
v-model
指令实现了数据的双向绑定,其他指令都是单向 - 注意:
v-model
只能应用在表单元素中 - 表单元素 例:
input text radio checkbox textarea select
简易计算器案例
<body>
<div id="app">
<input type="text" v-model="n1">
<select v-model="opt">
<option value="+">+</option>
<option value="-">-</option>
<option value="*">*</option>
<option value="/">/</option>
</select>
<input type="text" v-model="n2">
<input type="button" value="=" @click="calc">
<input type="text" v-model="result">
</div>
<script>
let vue = new Vue({
el: '#app',
data: {
n1: 0,
opt: '+',
n2: 0,
result: 0,
},
methods: {
calc(){
/*switch (this.opt){
case "+":
this.result = parseFloat(this.n1) + parseFloat(this.n2);
break;
case "-":
this.result = parseFloat(this.n1) - parseFloat(this.n2);
break;
case "*":
this.result = parseFloat(this.n1) * parseFloat(this.n2);
break;
case "/":
this.result = parseFloat(this.n1) / parseFloat(this.n2);
break;
}*/
eval(`this.result = parseFloat(this.n1) ${this.opt} parseFloat(this.n2);`)
}
}
});
</script>
</body>
在Vue中使用样式
使用class样式
- 数组
<h1 :class="['red', 'thin']">这是一个邪恶的H1</h1>
- 数组中使用三元表达式
<h1 :class="['red', 'thin', isactive?'active':'']">这是一个邪恶的H1</h1>
- 数组中嵌套对象
<h1 :class="['red', 'thin', {'active': isactive}]">这是一个邪恶的H1</h1>
- 直接使用对象
<h1 :class="{red:true, italic:true, active:true, thin:true}">这是一个邪恶的H1</h1>
使用内联样式
- 1.直接在元素上通过
:style
的形式,书写样式对象
<h1 :style="{color: 'red', 'font-size': '40px'}">这是一个善良的H1</h1>
- 2.将样式对象,定义到
data
中,并直接引用到:style
中
- 在data上定义样式:
- ```html
data: {
h1StyleObj: { color: 'red', 'font-size': '40px', 'font-weight': '200' }
}
```- 在元素中,通过属性绑定的形式,将样式对象应用到元素中:
<h1 :style="h1StyleObj">这是一个善良的H1</h1>
- 在 :style 中通过数组,引用多个 data 上的样式对象
- 在data上定义样式:
```
data: {
h1StyleObj: { color: ‘red’, ‘font-size’: ‘40px’, ‘font-weight’: ‘200’ },
h1StyleObj2: { fontStyle: ‘italic’ }
} - 在元素中,通过属性绑定的形式,将样式对象应用到元素中:
<h1 :style="[h1StyleObj, h1StyleObj2]">这是一个善良的H1</h1>
- 在data上定义样式:
- 在 :style 中通过数组,引用多个 data 上的样式对象
Vue指令之v-for和key属性
- 1.迭代数组
<ul>
<li v-for="(item, i) in list">索引:{{i}} --- 姓名:{{item.name}} --- 年龄:{{item.age}}</li>
</ul>
- 2.迭代对象中的属性
循环遍历对象身上的属性
<div v-for="(val, key, i) in userInfo">{{val}} --- {{key}} --- {{i}}</div>
- 3.迭代数字
<p v-for="i in 10">这是第 {{i}} 个P标签</p>
<ul>
<!--今后,只要涉及到了v-for这种循环,推荐给循环的每一项添加:key属性-->
<!--:key属性,只接受number或string类型的数据,不要直接为:key指定对象-->
<!--:key 指定的值必须具有唯一性-->
<li v-for="(item,i) in list" :key="item.id">
<input type="checkbox">
{{ item.id }}---{{ item.name }}---{{ i }}</li>
</ul>
2.2.0+ 的版本里,当在组件中使用 v-for 时,key 现在是必须的。
当 Vue.js 用 v-for 正在更新已渲染过的元素列表时,它默认用 “就地复用” 策略。如果数据项的顺序被改变,Vue将不是移动 DOM 元素来匹配数据项的顺序, 而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。
为了给 Vue 一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一 key 属性。
Vue指令之v-if和v-show
- v-if和v-show只有一个作用,就是根据指定的标识符,切换元素的显示和隐藏状态
- v-if是实时的创建和移除元素,从而达到元素的显示和隐藏
- v-show是通过为元素 添加活移除 display:none 来实现隐藏和显示的
- 一般来说,v-if 有更高的切换消耗而 v-show 有更高的初始渲染消耗。因此,如果需要频繁切换 v-show 较好,如果在运行时条件不大可能改变 v-if 较好。
品牌管理案例
Vue调试工具vue-devtools
作业
<style>
.normal{
color: blue;
}
.active{
color: red;
font-weight: bold;
}
</style>
</head>
<body>
<div id="app">
<ul>
<li v-for="(item,i) in list" :key="item.id"
:class="['normal',{active:i == selectedIndex?true:false}]"
@click="change(i)">
<input type="checkbox" :checked="i == selectedIndex">
{{item.id}},{{item.name}},{{item.age}},{{item.sex}}
</li>
</ul>
</div>
<script>
let vue = new Vue({
el: '#app',
data: {
selectedIndex: 0,
list: [
{id: 1, name: '王五', age: 12, sex: '男'},
{id: 2, name: '张三', age: 13, sex: '男'},
{id: 3, name: '小红', age: 14, sex: '女'},
]
},
methods: {
change(i){
this.selectedIndex = i
}
}
});
</script>
</body>
过滤器
- 过滤器的使用注意事项:
- 1.Vue.filter(‘过滤器的名称’,’过滤器的处理函数’)
- 2.注意:过滤器的处理函数中,第一个形参,功能已经被规定好了,永远都是管道符前面的值
- 3.调用过滤器 {{ item.ctime | formatDate }}
- 4.在调用过滤器的时候 可以传递参数{{ item.ctime | formatDate(‘传递参数’) }}
- 5.注意:调用过滤器传递的参数 只能从处理函数的第二个形参开始接收 因为第一个形参已经被管道符前面的值给占用了
- 6.注意:过滤器的处理函数中 必须返回一个值
- 7.可以连续使用管道符 调用多个过滤器 最终输出的结果 永远以最后一个过滤器为准
- 8.注意:过滤器只能使用在差值表达中 或者 v-bind中 不能使用在其他地方 比如v-text就不支持
全局过滤器
<label>{{cTime | dataFormat()}}</lable>
// 定义一个全局过滤器
Vue.filter('dataFormat', function (input, pattern = '') {
var dt = new Date(input);
// 获取年月日
var y = dt.getFullYear();
var m = (dt.getMonth() + 1).toString().padStart(2, '0');
var d = dt.getDate().toString().padStart(2, '0');
// 如果 传递进来的字符串类型,转为小写之后,等于 yyyy-mm-dd,那么就返回 年-月-日
// 否则,就返回 年-月-日 时:分:秒
if (pattern.toLowerCase() === 'yyyy-mm-dd') {
return `${y}-${m}-${d}`;
} else {
// 获取时分秒
var hh = dt.getHours().toString().padStart(2, '0');
var mm = dt.getMinutes().toString().padStart(2, '0');
var ss = dt.getSeconds().toString().padStart(2, '0');
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`;
}
});
私有过滤器
当全局过滤器和私有过滤器重名时,就近原则,优先加载私有过滤器
<div id="app">
<label>{{msg | msgFilter | addStr}}</label>
</div>
<script>
Vue.filter('msgFilter',function (msg){
// let s = msg.replace('纯洁','邪恶');
// /g是全部匹配
let s = msg.replace(/纯洁/g,'邪恶');
console.log(s)
return s;
});
let vue = new Vue({
el: '#app',
data: {
msg: '曾经纯洁,曾经纯洁,曾经纯洁,曾经纯洁,曾经纯洁'
},
methods: {
},
filters:{
addStr:function (data) {
return data+'~~~~~~~~~~~~~~~';
},
//当全局过滤器和私有过滤器重名时,就近原则,优先加载私有过滤器
msgFilter:function (data) {
return data+'=============';
},
}
});
</script>
自定义指令
官方文档:https://cn.vuejs.org/v2/guide/custom-directive.html
全局自定义指令
<label>搜索:
<input type="text" @change="search" v-model="keywords" v-focus>
</label>
Vue.directive('focus',{
//全局自定义 获得焦点的v-focus指令
//Vue 自定义指令的名称中,不需要写v-前缀,但是,在调用自定义指令的时候,必须在起那么加上v-前缀
//参数列表中的第一个参数,永远是el 表示被绑定指令的那个元素
//如果要操作元素的样式,写到bind就行
bind:function (el){//当指令绑定到的元素,被Vue实例解析的时候,就会立即执行bind函数
// console.log(el)
//el.focus();//如果想要让文本框获得焦点,那么,文本框必须先插入到文档中才能生效
// el.style.color='red'
},
//今后在自定义指令的时候,如果需要操作元素的JS行为 最好写到inserted中
inserted:function (el){//调用时机:当指令绑定到的元素,被插入到文档的父节点的时候,调用inserted函数
// console.log('2 inserted执行了')
el.focus();
}
})
私有自定义指令
<th v-color="'green'" v-bold="1000" v-italic>操作</th>
let vue = new Vue({
el: '#app',
data: {},
methods: {},
//私有过滤器
filters:{},
//私有指令
directives:{
//让指定元素字体加粗的指令
bold:{
bind(el,binding){
console.log(binding.value)
el.style.fontWeight = binding.value
},
inserted(el){}
},
//让文字倾斜的指令
italic:function (el,binding) {
//此处用到了指令函数的简写形式,如果指令给定的是function,
// 则等同于把这个function中的代码,
// 分别定义到了bind和update中去;
el.style.fontStyle="italic"
}
},
});
键盘修饰符
<label>NAME:
<input type="text" v-model="name" @keyup.enter="add">
</label>
vue实例的生命周期
- 什么是生命周期:从Vue实例创建、运行、到销毁期间,总是伴随着各种各样的事件,这些事件,统称为生命周期!
- 生命周期钩子:就是生命周期事件的别名而已;
- 生命周期钩子 = 生命周期函数 = 生命周期事件
- 主要的生命周期函数分类:
- 创建期间的生命周期函数:
- beforeCreate:实例刚在内存中被创建出来,此时,还没有初始化好 data 和 methods 属性
- created:实例已经在内存中创建OK,此时 data 和 methods 已经创建OK,此时还没有开始 编译模板
- beforeMount:此时已经完成了模板的编译,但是还没有挂载到页面中
- mounted:此时,已经将编译好的模板,挂载到了页面指定的容器中显示
- 运行期间的生命周期函数:
- beforeUpdate:状态更新之前执行此函数, 此时 data 中的状态值是最新的,但是界面上显示的 数据还是旧的,因为此时还没有开始重新渲染DOM节点
- updated:实例更新完毕之后调用此函数,此时 data 中的状态值 和 界面上显示的数据,都已经完成了更新,界面已经被重新渲染好了!
- 销毁期间的生命周期函数:
- beforeDestroy:实例销毁之前调用。在这一步,实例仍然完全可用。
- destroyed:Vue 实例销毁后调用。调用后,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="../day01/lib/vue-2.5.9.js"></script>
</head>
<body>
<div id="app">
<input type="button" value="ChangeMsg" @click="msg='数据被修改了'">
<h3 id="myh3">{{ msg }}</h3>
</div>
<script>
let vue = new Vue({
el: '#app',
data: {
msg: 'message'
},
methods: {
show(){
console.log('show方法被调用了')
}
},
//第一个生命周期函数 【创建阶段】
beforeCreate(){
// console.log(this.msg)
// this.show()
},
//第二个生命周期函数 【创建阶段】
//当执行到created函数的时候,data和methods都已经初始化完毕了,此时,可以随意的去访问 其中的数据或方法了
//结论:如果要操作data中的数据,或调用methods中的函数,最早,只能在created函数中进行。
created(){
console.log(this.msg)
this.show()
},
//第三个生命周期函数 表示即将挂载 【创建阶段】
//当模板页面被编译好之后,就会立即执行beforeMount这个函数
//此时,我们的HTML代码结构,已经在内存中创建好了,但是,尚未挂载到页面中
//结论:在这个函数中,页面上的DOM元素是原始的插值表达式之类的VUE代码
beforeMount() {
// let elementById = document.getElementById('myh3');
// console.log(elementById.innerHTML)
},
//第四个生命周期函数,表示页面已经完成了渲染,
// 同时,mounted函数的执行,标志着创建阶段的结束,从此以后,Vue实例,就从创建阶段,进入到运行阶段
//结论:如果大家要引用一些第三方的插件来操作DOM元素了,最好在mounted中去操作DOM元素,因为这时候才是真正的页面
mounted(){
/* let elementById = document.getElementById('myh3');
console.log(elementById.innerHTML)*/
},
beforeUpdate(){
/*let elementById = document.getElementById('myh3');
console.log(elementById.innerHTML)*/
},
updated(){
let elementById = document.getElementById('myh3');
console.log(elementById.innerHTML)
}
});
//Vue的实例,也分为三个阶段:分别是创建阶段、运行阶段、销毁阶段
//在实例运行的三个阶段中,总是伴随着各种各样的事件,那个,这些事件,统称为实例的生命周期函数(钩子函数、生命周期事件)
</script>
</body>
</html>
vue-resource 实现 get, post, jsonp请求
使用vue-resource请求数据
<!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="lib/vue-2.5.9.js"></script>
<!--vue-resource 只能在vue的后面导入-->
<script src="lib/vue-resource-1.3.4.js"></script>
</head>
<body>
<div id="app">
<input type="button" value="Get请求" @click="getInfo">
<input type="button" value="Post请求" @click="postInfo">
<input type="button" value="jsonp请求" @click="jsonpInfo">
</div>
<script>
let vue = new Vue({
el: '#app',
data: {},
methods: {
//get方式请求数据
/*getInfo(){
this.$http.get("http://www.liulongbin.top:3005/api/getlunbo").then(function (data) {
console.log(data)
console.log(data.body)
})
}*/
async getInfo(){
// let data = await this.$http.get("http://www.liulongbin.top:3005/api/getlunbo");
// console.log(data.body)
// 此处{ body } 是取data中的body节点的内容!!!
let { body } = await this.$http.get("http://www.liulongbin.top:3005/api/getlunbo");
console.log(body)
},
async postInfo(){
let { body } = await this.$http.post("http://www.liulongbin.top:3005/api/post",{name:'高婆婆',age:22})
console.log(body)
},
async jsonpInfo(){
let { body } = await this.$http.jsonp("http://www.liulongbin.top:3005/api/jsonp")
console.log(body)
}
}
});
</script>
</body>
</html>
axios结合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="lib/vue-2.5.9.js"></script>
<script src="lib/axios-v0.17.1.js"></script>
</head>
<body>
<div id="app">
<input type="button" value="Get请求" @click="getInfo">
<input type="button" value="Post请求" @click="postInfo">
<!--axios 不支持发送jsonp请求-->
<!--<input type="button" value="jsonp请求" @click="jsonpInfo">-->
</div>
<script>
//把axios挂载到Vue构造函数的原型上
Vue.prototype.$http = axios
let vue = new Vue({
el: '#app',
data: {},
methods: {
async getInfo(){
// let result = await axios.get("http://www.liulongbin.top:3005/api/getlunbo")
// console.log(result)
// let {data} = await axios.get("http://www.liulongbin.top:3005/api/getlunbo")
// console.log(data)
let {data} = await this.$http.get("http://www.liulongbin.top:3005/api/getlunbo");
console.log(data)
},
async postInfo(){
let { data } = await this.$http.post("http://www.liulongbin.top:3005/api/post",{name:'高婆婆',age:22})
console.log(data)
}
}
});
</script>
</body>
</html>
Vue中的动画
使用过渡类名
- html结构
<div id="app"> <input type="button" value="动起来" @click="myAnimate"> <!-- 使用 transition 将需要过渡的元素包裹起来 --> <transition name="fade"> <div v-show="isshow">动画哦</div> </transition> </div>
- VM实例
// 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: { isshow: false }, methods: { myAnimate() { this.isshow = !this.isshow; } } });
- 定义两组类样式
/* 定义进入和离开时候的过渡状态 */ .fade-enter-active, .fade-leave-active { transition: all 0.2s ease; position: absolute; } /* 定义进入过渡的开始状态 和 离开过渡的结束状态 */ .fade-enter, .fade-leave-to { opacity: 0; transform: translateX(100px); }
使用第三方 CSS 动画库
- 导入动画类库
<link rel="stylesheet" type="text/css" href="./lib/animate.css">
- 定义transition及属性
<transition enter-active-class="fadeInRight" leave-active-class="fadeOutRight" :duration="{ enter: 500, leave: 800 }"> <div class="animated" v-show="isshow">动画哦</div> </transition>
使用动画钩子函数
- 定义 transition 组件以及三个钩子函数:
<div id="app"> <input type="button" value="加入购物车" @click="flag=!flag"> <transition @before-enter="beforeEnter" @enter="enter" @after-enter="afterEnter"> <div id="ball" v-show="flag"></div> </transition> </div>
- 定义三个 methods 钩子方法:
let vue = new Vue({ el: '#app', data: { flag: false //显示的状态 }, methods: { beforeEnter(el){//小球开始动画之前的起始状态 el.style.transform='translate(0,0)' }, enter(el,done){//小球动画结束之后的结束状态 //这里是固定写法,如果不写el.offsetWidth就无法实现动画效果 el.offsetWidth el.style.transform='translate(150px,300px)' el.style.transition='all 1s ease' //当动画执行完毕后,会自动调用done这个函数,这个done就是afterEnter函数的引用 done() }, afterEnter(el){//小球动画结束之后的回调函数,用来做一些清理工作 this.flag = !this.flag }, } });
v-for 的列表过渡
- 定义过渡样式:
<style> .list-enter, .list-leave-to { opacity: 0; transform: translateY(10px); } .list-enter-active, .list-leave-active { transition: all 0.3s ease; } </style>
- 定义DOM结构,其中,需要使用 transition-group 组件把v-for循环的列表包裹起来:
<div id="app"> <input type="text" v-model="txt" @keyup.enter="add"> <transition-group tag="ul" name="list"> <li v-for="(item, i) in list" :key="i">{{item}}</li> </transition-group> </div>
- 定义 VM中的结构:
// 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: { txt: '', list: [1, 2, 3, 4] }, methods: { add() { this.list.push(this.txt); this.txt = ''; } } });
视频中代码:
<!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>
<link rel="stylesheet" href="./lib/animate.css">
<script src="lib/vue-2.5.9.js"></script>
<script src="lib/axios-v0.17.1.js"></script>
<style>
ul{
list-style: none;
padding: 0;
margin: 0;
}
li{
line-height: 30px;
border: 1px dashed #ccc;
margin: 5px;
font-size: 12px;
padding-left: 10px;
width: 500px;
cursor: pointer;
}
li:hover{
background-color: orange;
box-shadow: 0 0 7px gray;
/*transition: all 0.6s ease;*/
}
.v-enter,
.v-leave-to{
opacity: 0;
transform: translateY(200px);
}
.v-enter-active,
.v-leave-active{
transition: all 0.5s ease;
}
.v-move{/*让元素被改变定位的时候,有一个缓动效果*/
transition: all 0.5s ease;
}
.v-leave-active{/*表示要被删除的哪个元素,让即将被移除的元素,脱离标准流,这样,后面的元素就能渐渐的浮动上来*/
position: absolute;
}
</style>
</head>
<body>
<div id="app">
<div>
Id: <input type="text" v-model="id">
Name: <input type="text" v-model="name">
<input type="button" value="添加" @click="add">
</div>
<transition-group tag="ul">
<li v-for="(item,i) in list" :key="item.id" @click="remove(i)">{{item.id}}-- {{item.name}}</li>
</transition-group>
</div>
<script>
let vue = new Vue({
el: '#app',
data: {
list: [
{id: 1,name: '高军军'},
{id: 2,name: '付哥哥'},
{id: 3,name: '玉姐姐'},
{id: 4,name: '斌哥哥'}
],
id: '',
name: ''
},
methods: {
remove(i){
this.list.splice(i,1)
},
add(){
const p = {id: this.id,name: this.name}
// this.list.push(p)
this.list.unshift(p)//放最前面
this.id = this.name = ''
}
}
});
</script>
</body>
</html>
列表的排序过渡
<transition-group>
组件还有一个特殊之处。不仅可以进入和离开动画,还可以改变定位。要使用这个新功能只需了解新增的 v-move
特性,它会在元素的改变定位的过程中应用。
v-move
和v-leave-active
结合使用,能够让列表的过渡更加平缓柔和:
.v-move{ transition: all 0.8s ease; } .v-leave-active{ position: absolute; }
演示transition中name属性的重要性
<!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>
<link rel="stylesheet" href="./lib/animate.css">
<script src="lib/vue-2.5.9.js"></script>
<script src="lib/axios-v0.17.1.js"></script>
<style>
.v-enter,
.v-leave-to{
opacity: 0;
transform: translateX(100px);
}
.v-enter-active,
.v-leave-active{
transition: all 0.4s ease;
}
.fade-enter,
.fade-leave-to{
opacity: 0;
transform: translateX(100px);
}
.fade-enter-active,
.fade-leave-active{
transition: all 3s ease;
}
</style>
</head>
<body>
<div id="app">
<input type="button" value="Toggle" @click="flag=!flag">
<transition>
<h3 v-show="flag">111111111</h3>
</transition>
<hr>
<input type="button" value="Toggle" @click="flag2=!flag2">
<transition name="fade">
<h3 v-show="flag2">111111111</h3>
</transition>
</div>
<script>
let vue = new Vue({
el: '#app',
data: {
flag: true,
flag2: true
}
});
</script>
</body>
</html>
Day02
定义Vue组件
- 什么是模块化:模块化是从代码的角度出发,分析项目,把项目中一些功能类似的代码,单独的抽离为一个个的模块;那么为了保证大家以相同的方式去封装模块,于是我们就创造了模块化的规范(CommonJS规范);
- 模块化的好处:方便项目的开发;和后期的维护与扩展;今后如果需要某些固定功能的模块,则直接拿来引用就行,提高了项目开发效率!
- 什么是组件化:从UI的角度出发考虑问题,把页面上有重用性的UI解构和样式,单独的抽离出来,封装为单独的组件;
- 组件化的好处:随着项目规模的发展,我们手里的组件,会越来越多,这样,我们今后一个页面中的UI,几乎都可以从手中拿现成的组件拼接出来;方便项目的开发和维护;
全局组件定义的三种方式
第一种方式:
- 先调用
Vue.extend()
得到组件的构造函数:
// 创建全局组件的第一种方式: component const com1 = Vue.extend({ template: '<h1>这是创建的第一个全局组件</h1>' // template 属性,表示这个组件的 UI 代码解构 })
- 通过
Vue.component('组件的名称', 组件的构造函数)
来注册全局组件:
// 使用 Vue.component 向全局注册一个组件 // Vue.component('组件的名称', 组件的构造函数) Vue.component('mycom1', com1)
- 把注册好的全局组件名称,以标签形式引入到页面中即可:
<!-- 如何引入一个全局的Vue组件呢? 直接把 组件的名称,以标签的形式,放到页面上就好了! --> <mycom1></mycom1>
第二种方式:
- 直接使用
Vue.component('组件名称', { 组件模板对象 })
const com2Obj = { // 1. template 属性中,不能单独放一段文本,必须用标签包裹起来; // 2. 如果在 template 属性中,想要放多个元素了,那么,在这些元素外,必须有唯一的一个根元素进行包裹; template: '<div><h2>这是直接使用 Vue.component 创建出来的组件</h2><h3>红红火火</h3></div>' } // 定义全局的组件 // Vue.component 的第二个参数,既接收 一个 组件的构造函数, 同时,也接受 一个对象 Vue.component('mycom2', com2Obj)
第三种方式:
- 先使用
template
标签定义一个模板的代码解构:
<!-- 定义一个 template 标签元素 --> <!-- 使用 Vue 提供的 template 标签,可以定义组件的UI模板解构 --> <template id="tmpl"> <div> <h3>哈哈,这是在外界定义的组件UI解构</h3> <h3>我是来捣乱的</h3> </div> </template>
- 使用
Vue.component
注册组件:
// 这是定义的全局组件 Vue.component('mycom3', { template: '#tmpl' })
注意: 从更抽象的角度来说,每个组件,就相当于是一个自定义的元素; 注意: 组件中的DOM结构,有且只能有唯一的根元素(Root Element)来进行包裹!
定义私有组件
const vm = new Vue({
el: '#app',
data: {},
methods: {},
components: {//定义实例中私有组件的 组件名称 和组件结构
'mycom4': {
template: '<h6>啦啦啦啦啦啦</h6>'
}
}
})
组件中展示数据和响应事件
Vue.component('mycom', {
template: '<h3 @click="show">这是自定义的全局组件:{{ msg }}</h3>',
data: function () { // 在 组件中,可以有自己的私有数据,但是,组件的 data 必须是一个 function,并且内部 return 一个 数据对象
return {
msg: '哈哈哈'
}
},
methods: { // 尝试定义组件的私有方法
show() {
console.log('触发了组件的私有show方法!')
}
}
})
【重点】为什么组件中的data属性必须定义为一个方法并返回一个对象
通过计数器案例演示
<!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.导入Vue包-->
<script src="../day01/lib/vue-2.5.9.js"></script>
</head>
<body>
<!--2.创建要控制的区域-->
<div id="app">
<counter></counter>
<counter></counter>
</div>
<script>
const o = { count: 0 }
//定义全局的组件
//Vue.component的第二个参数,即接收组件的构造函数,同时也接收组件的一个对象
Vue.component('counter', {
template: `<div>
<input type="button" value="+1" @click="add">
<h3>当前count值为:{{count}}</h3>
</div>`,
//为什么要把组件中的data定义为一个function呢?因为这样做的话,每当我们在页面上引用一次组件,
// 必然会先调用这个data function,从而得到一个当前组件私有的数据对象;
data: function (){
//这是官方推荐的
return {
count: 0
}
//这是自己改造后的形式
//如果使用此种方式,当我们在页面上多次引用组件时,o始终是同一个对象,就会造成数据联动!!!
// return o;
},
methods: {
add(){//点击按钮让组件的count值自增+1
this.count++
}
}
})
const vm = new Vue({
el: '#app',
data: {},
methods: {}
})
</script>
</body>
</html>
使用flag
标识符结合v-if
和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">
<title>Document</title>
<!--1.导入Vue包-->
<script src="../day01/lib/vue-2.5.9.js"></script>
</head>
<body>
<!--2.创建要控制的区域-->
<div id="app">
<input type="button" value="显示登录" @click="flag=true">
<input type="button" value="显示注册" @click="flag=false" >
<login v-if="flag"></login>
<reg v-else="flag"></reg>
</div>
<script>
Vue.component('login',{
template: `<h3>登录模块1</h3>`
})
Vue.component('reg',{
template: `<h3>注册模块2</h3>`
})
const vm = new Vue({
el: '#app',
data: {
flag: true
},
methods: {}
})
</script>
</body>
</html>
使用component标签的:is
属性来切换组件,并添加动画
<!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="../day01/lib/vue-2.5.9.js"></script>
<style>
.v-enter{
/*即将进入时候的坐标*/
opacity: 0;
transform: translateX(100px);
}
.v-leave-to{
/*离开时候,最终到达的位置*/
opacity: 0;
transform: translateX(-100px);
}
.v-enter-active,
.v-leave-active{
transition: all 0.4s ease;
position: absolute;
}
</style>
</head>
<body>
<div id="app">
<!--transition transition-group template component-->
<!--通过component的:is属性 可以显示指定【名称】的组件-->
<!--<component :is="componentId"></component>-->
<a href="#" @click="comId='com1'">显示组件1</a> <br>
<a href="#" @click="comId='com2'">显示组件2</a> <br>
<a href="#" @click="comId='com3'">显示组件3</a> <br>
<a href="#" @click="comId='com4'">显示组件4</a> <br>
<!--mode="out-in"先离开之后再进入-->
<transition mode="out-in">
<component :is="comId"></component>
</transition>
</div>
<script>
Vue.component('com1',{
template: `<h3>组件1-</h3>`
})
Vue.component('com2',{
template: `<h3>组件2--</h3>`
})
Vue.component('com3',{
template: `<h3>组件3---</h3>`
})
Vue.component('com4',{
template: `<h3>组件4----</h3>`
})
const vm = new Vue({
el: '#app',
data: {
comId: 'com1'
},
methods: {}
})
</script>
</body>
</html>
父组件向子组件传值
父组件向子组件传递普通数据和对象
<div id="app">
<!--父组件如果想给子组件传递数据,则需要使用属性绑定的形式-->
<!--这样,子组件身上的自定义数据 就是你要传递给子组件的数据-->
<com1 :obj="msgObj" :value="parentMsg"></com1>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
parentMsg: '普通值',
msgObj: {//对象
address: '北京',
location: '顺义---马坡南'
}
},
methods: {},
components: {
'com1': {
template: `<h3>好好 {{obj}} ---- {{value}}</h3>`,
props: ['obj','value']
}
}
})
</script>
父组件向子组件传递方法
<div id="app">
<!--1. 如果要向子组件传递data中的数据,则使用属性绑定的形式 v-bind-->
<!--2. 如果向子组件传递methods中的方法,则使用事件绑定的形式 v-on-->
<com1 @showme="show"></com1>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {},
methods: {
show(){
console.log('有人调用了父组件中的show方法')
}
},
components: {
'com1': {
<!--当点击子组件按钮的时候 调用一下父组件传递过来的showme方法-->
template: `<div>
<input type="button" value="这是子组件的按钮" @click="btnClick">
</div>`,
methods: {
btnClick(){
//console.log('okok');
//调用一下父组件传递过来的shwome方法 emit英文原意为发射,在计算机中引申为触发!
this.$emit('showme')
}
}
}
}
})
</script>
子组件向父组件传值
<div id="app">
<!--1. 如果要向子组件传递data中的数据,则使用属性绑定的形式 v-bind-->
<!--2. 如果向子组件传递methods中的方法,则使用事件绑定的形式 v-on-->
<com1 @showme="show"></com1>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
msgFormSon: ''
},
methods: {
show(arg1){
// console.log('有人调用了父组件中的show方法' + arg1)
//把子组件传递过来的数据,保存到父组件的data中
this.msgFormSon = arg1
console.log(this.msgFormSon)
}
},
components: {
'com1': {
<!--当点击子组件按钮的时候 调用一下父组件传递过来的showme方法-->
template: `<div>
<input type="button" value="这是子组件的按钮" @click="btnClick">
</div>`,
data(){
return {
sonMsg: '这是子组件中的数据'
}
},
methods: {
btnClick(){
//console.log('okok');
//调用一下父组件传递过来的shwome方法 emit英文原意为发射,在计算机中引申为触发!
//子组件向父组件传值本质上还是调用了父组件传递过来的方法,只不过,子组件在调用的时候把数据当做参数,传给这个方法了
this.$emit('showme',this.sonMsg)
}
}
}
}
})
</script>
评论列表案例
目标:主要练习父子组件之间传值
<body>
<div id="app">
<cmt-box @add="addNewCnt"></cmt-box>
<ul>
<cmt-item v-for="(item,i) in list" :key="i" :item="item"></cmt-item>
</ul>
</div>
<script>
Vue.component('cmt-item',{
template: `<ul>
<li>
<h3>评论人:{{ item.name }}</h3>
<h5>评论内容:{{ item.content }}</h5>
</li>
</ul>`,
props:["item"]
})
Vue.component('cmt-box',{
template: `
<div>
<label>评论人:</label>
<br>
<input type="text" v-model="name">
<br>
<label>评论内容:</label>
<br>
<textarea v-model="content"></textarea>
<br>
<input type="button" value="发表评论" @click="postComment">
</div>`,
data: function() {
return {
name: '',
content: ''
}
},
methods: {
postComment(){//发表评论
const cmt = {name: this.name,content: this.content}
this.$emit('add',cmt)
}
},
})
const vm = new Vue({
el: '#app',
data: {
list: [
{name:'张三',content:'沙发1'},
{name:'111',content:'沙发2'},
{name:'qqq',content:'沙发3'},
{name:'eee',content:'沙发4'}
]
},
methods: {
addNewCnt(obj){//添加新评论
console.log('okokok')
this.list.push(obj)
}
}
})
</script>
</body>
使用this.$refs来获取元素
<div id="app">
<input type="button" value="点击获取元素的内容" @click="getInfo" ref="btn">
<h3 ref="myh3">{{msg}}</h3>
</div>
<script>
const vm = new Vue({
el: '#app',
data: {
msg: '000'
},
methods: {
getInfo(){//点击按钮,获取H3中的文本内容
console.log(this.$refs.myh3.innerHTML)
console.log(this.$refs.btn.value)
}
}
})
</script>
使用this.$refs来获取组件
<body>
<div id="app">
<input type="button" value="获取页面上的组件" @click="getCom">
<com1 ref="mycom"></com1>
</div>
<script>
Vue.component('com1',{
template: `
<h3>这是一个小组件 {{msg}}</h3>
`,
data: function (){//子组件的私有数据
return {
msg: 'ok'
}
},
methods: {//子组件的方法
show(){
console.log('有人调用了子组件的方法')
}
}
})
const vm = new Vue({
el: '#app',
data: {
msg: '000'
},
methods: {
getCom(){
// console.log(this)
//修改子组件上的数据
// this.$refs.mycom.msg = '123'
//调用子组件中的方法
this.$refs.mycom.show()
}
}
})
</script>
</body>
在Vue组件中data和props的区别
- data 在组件中,要被定义成function并返回一个对象
- props 在组件中,要被定义成数组,其中,数组的值都是字符串名,表示父组件传递过来的数据;
- props 的数据,不要直接拿来修改,如果想要修改,必须在 data 上重新定义一个 属性,然后把属性的值 从 this.props 拿过来;
data 上的数据,都是组件自己私有的, data 上的数据,都是可读可写的 props 数据,都是外界传递过来的数据, props 中的数据只能读取,不能重新写入
什么是路由
- 对于普通的网站,所有的超链接都是URL地址,所有的URL地址都对应服务器上对应的资源;
- 对于单页面应用程序来说,主要通过URL中的hash(#号)来实现不同页面之间的切换,同时,hash有一个特点:HTTP请求中不会包含hash相关的内容;所以,单页面程序中的页面跳转主要用hash实现;
- 在单页面应用程序中,这种通过hash改变来切换页面的方式,称作前端路由(区别于后端路由);
- 前端的路由:就是根据不同的Hash地址,在页面上展示不同的前端组件;
在 vue 中使用 vue-router
- 导入 vue-router 组件类库:
<!-- 1. 导入 vue-router 组件类库 --> <script src="./lib/vue-router-2.7.0.js"></script>
- 使用 router-link 组件来导航
<!-- 2. 使用 router-link 组件来导航 --> <router-link to="/login">登录</router-link> <router-link to="/register">注册</router-link>
- 使用 router-view 组件来显示匹配到的组件
<!-- 3. 使用 router-view 组件来显示匹配到的组件 --> <router-view></router-view>
- 创建使用
Vue.extend
创建组件
// 4.1 使用 Vue.extend 来创建登录组件 var login = Vue.extend({ template: '<h1>登录组件</h1>' }); // 4.2 使用 Vue.extend 来创建注册组件 var register = Vue.extend({ template: '<h1>注册组件</h1>' });
- 创建一个路由 router 实例,通过 routers 属性来定义路由匹配规则
// 5. 创建一个路由 router 实例,通过 routers 属性来定义路由匹配规则 var router = new VueRouter({ routes: [ { path: '/login', component: login }, { path: '/register', component: register } ] });
- 使用 router 属性来使用路由规则
// 6. 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', router: router // 使用 router 属性来使用路由规则 });
设置路由高亮 linkActiceClass
<!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="./lib/vue-2.5.9.js"></script>
<!-- 1. 导入路由JS文件 -->
<script src="./lib/vue-router-v3.0.1.js"></script>
<style>
.router-link-active {
color: red;
font-weight: bold;
font-style: italic;
font-size: 20px;
text-decoration: underline;
}
.my-active {
color: orange;
font-size: 30px;
}
</style>
</head>
<body>
<div id="app">
<!-- 路由链接 -->
<router-link to="/login">登录</router-link>
<router-link to="/reg">注册</router-link>
<!-- 展示路由组件的容器 -->
<router-view></router-view>
</div>
<script>
//2.定义两个要切换的组件
const login = {
template: '<h3>登录组件</h3>'
}
const reg = {
template: '<h3>登录组件</h3>'
}
//3. 创建路由对象
const router = new VueRouter({
routes: [//路由规则的数组
// { path: '/', component: login },
{ path: '/', redirect: '/login' }, // node 的 express 框架中,有 res.redirect('/login')
{path: '/login',component: login},
{path: '/reg',component: reg},
],
linkActiceClass: 'my-actice' //配置默认被选中路由的高亮类名,默认类名为 router-link-actice
})
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {},
router // 4. 把路由对象,挂载到 VM 实例上
});
</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>Document</title>
<script src="./lib/vue-2.5.9.js"></script>
<!-- 1. 导入路由JS文件 -->
<script src="./lib/vue-router-v3.0.1.js"></script>
<style>
.router-link-active {
color: red;
font-weight: bold;
font-style: italic;
font-size: 20px;
text-decoration: underline;
}
.my-active {
color: orange;
font-size: 30px;
}
.v-enter,
.v-leave-to {
opacity: 0;
transform: translateX(100px);
}
.v-enter-active,
.v-leave-active {
transition: all 0.3s ease;
position: absolute;
}
</style>
</head>
<body>
<div id="app">
<!-- 路由链接 -->
<router-link to="/login">登录</router-link>
<router-link to="/reg">注册</router-link>
<!-- 展示路由组件的容器 -->
<transition>
<router-view></router-view>
</transition>
</div>
<script>
// 2. 定义两个要切换的组件
const login = {
template: '<h3>登录组件</h3>'
}
const reg = {
template: '<h3>注册组件</h3>'
}
// 3. 创建路由对象
const router = new VueRouter({
routes: [ // 路由规则的数组
// { path: '/', component: login },
{ path: '/', redirect: '/login' }, // node 的 express 框架中,有 res.redirect('/login')
{ path: '/login', component: login },
{ path: '/reg', component: reg }
],
linkActiveClass: 'my-active' // 配置默认被 选中路由的高亮类名的 , 默认类名为 router-link-active
})
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {},
router // 4. 把路由对象,挂载到 VM 实例上
});
</script>
</body>
</html>
路由传参
?拼接传参
<div id="app">
<!-- 路由链接 -->
<router-link to="/login?id=10">登录</router-link>
<router-link to="/reg">注册</router-link>
<!-- 展示路由组件的容器 -->
<transition>
<router-view></router-view>
</transition>
</div>
<script>
// 2. 定义两个要切换的组件
const login = { //组件也有自己的生命周期函数,这些函数,和Vm实例的生命周期函数一致
template: '<h3>登录组件----{{$route.query.id}}</h3>',
created() {
console.log(this.$route.query)
console.log(this.$route.query.id)
}
}
const reg = {
template: '<h3>注册组件</h3>'
}
// 3. 创建路由对象
const router = new VueRouter({
routes: [ // 路由规则的数组
{ path: '/', redirect: '/login' },
{ path: '/login', component: login },
{ path: '/reg', component: reg }
],
linkActiveClass: 'my-active'
})
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {},
router // 4. 把路由对象,挂载到 VM 实例上
});
</script>
在路由规则中定义参数
<body>
<div id="app">
<!-- 路由链接 -->
<router-link to="/login/10/zs">登录</router-link>
<router-link to="/reg">注册</router-link>
<!-- 展示路由组件的容器 -->
<transition>
<router-view></router-view>
</transition>
</div>
<script>
// 2. 定义两个要切换的组件
const login = { //组件也有自己的生命周期函数,这些函数,和Vm实例的生命周期函数一致
template: '<h3>登录组件----{{ $route.params.id }} --- {{ $route.params.name }}</h3>',
created() {
console.log(this.$route)
}
}
const reg = {
template: '<h3>注册组件</h3>'
}
// 3. 创建路由对象
const router = new VueRouter({
routes: [ // 路由规则的数组
{ path: '/', redirect: '/login' },
{ path: '/login/:id/:name', component: login },
{ path: '/reg', component: reg }
],
linkActiveClass: 'my-active'
})
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {},
router // 4. 把路由对象,挂载到 VM 实例上
});
</script>
路由中使用prop获取参数
{ path: '/login/:id/:name', component: login ,props: true},
const login = { //组件也有自己的生命周期函数,这些函数,和Vm实例的生命周期函数一致
props: ['name','id'],
template: '<h3>登录组件----{{ id }} --- {{ name }}</h3>',
created() {
console.log(this.$route)
}
}
<div id="app">
<!-- 路由链接 -->
<router-link to="/login/10/zs">登录</router-link>
<router-link to="/reg">注册</router-link>
<!-- 展示路由组件的容器 -->
<transition>
<router-view></router-view>
</transition>
</div>
<script>
// 2. 定义两个要切换的组件
const login = { //组件也有自己的生命周期函数,这些函数,和Vm实例的生命周期函数一致
props: ['name','id'],
template: '<h3>登录组件----{{ id }} --- {{ name }}</h3>',
created() {
console.log(this.$route)
}
}
const reg = {
template: '<h3>注册组件</h3>'
}
// 3. 创建路由对象
const router = new VueRouter({
routes: [ // 路由规则的数组
{ path: '/', redirect: '/login' },
{ path: '/login/:id/:name', component: login ,props: true},
{ path: '/reg', component: reg }
],
linkActiveClass: 'my-active'
})
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {},
router // 4. 把路由对象,挂载到 VM 实例上
});
</script>
使用 children
属性实现路由嵌套
<div id="app">
<router-link to="/account">Account</router-link>
<router-view></router-view>
</div>
<script>
// 父路由中的组件
const account = Vue.extend({
template: `<div>
这是account组件
<router-link to="/account/login">login</router-link> |
<router-link to="/account/register">register</router-link>
<router-view></router-view>
</div>`
});
// 子路由中的 login 组件
const login = Vue.extend({
template: '<div>登录组件</div>'
});
// 子路由中的 register 组件
const register = Vue.extend({
template: '<div>注册组件</div>'
});
// 路由实例
var router = new VueRouter({
routes: [
{ path: '/', redirect: '/account/login' }, // 使用 redirect 实现路由重定向
{
path: '/account',
component: account,
children: [ // 通过 children 数组属性,来实现路由的嵌套
{ path: 'login', component: login }, // 注意,子路由的开头位置,不要加 / 路径符
{ path: 'register', component: register }
]
}
]
});
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {},
components: {
account
},
router: router
});
</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>Document</title>
<script src="./lib/vue-2.5.9.js"></script>
<script src="./lib/vue-router-v3.0.1.js"></script>
<style>
html,
body,
h1 {
margin: 0;
padding: 0;
font-size: 20px;
}
.header {
height: 120px;
background-color: darkcyan;
}
.container {
height: 400px;
display: flex;
}
.sidebar {
background-color: orange;
flex: 2;
}
.content {
background-color: pink;
flex: 10;
}
.footer {
background-color: black;
color: white;
height: 100px;
}
</style>
</head>
<body>
<div id="app">
<!-- 路由的容器 -->
<router-view name="top"></router-view>
<div class="container">
<router-view name="left"></router-view>
<router-view name="right"></router-view>
</div>
<router-view name="bottom"></router-view>
</div>
<script>
const header = {
template: `<h1 class="header">头部区域</h1>`
}
const sidebar = {
template: `<h1 class="sidebar">左侧侧边栏</h1>`
}
const content = {
template: `<h1 class="content">主体内容区域</h1>`
}
const footer = {
template: `<h1 class="footer">尾部</h1>`
}
const router = new VueRouter({
routes: [
// { path: '/', component: header }
{
path: '/', components: {
// 组件名称 : 组件对象
'top': header,
'left': sidebar,
'right': content,
'bottom': footer
}
}
]
})
// 创建 Vue 实例,得到 ViewModel
var vm = new Vue({
el: '#app',
data: {},
methods: {},
router
});
</script>
</body>
</html>
watch
属性的使用
考虑一个问题:想要实现 名
和 姓
两个文本框的内容改变,则全名的文本框中的值也跟着改变;(用以前的知识如何实现???)
- 场景一:watch监听
data
中属性的改变:
<div id="app"> <input type="text" v-model="firstName"> + <input type="text" v-model="lastName"> = <span>{{fullName}}</span> </div> <script> // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: { firstName: 'jack', lastName: 'chen', fullName: 'jack - chen' }, methods: {}, watch: { 'firstName': function (newVal, oldVal) { // 第一个参数是新数据,第二个参数是旧数据 this.fullName = newVal + ' - ' + this.lastName; }, 'lastName': function (newVal, oldVal) { this.fullName = this.firstName + ' - ' + newVal; } } }); </script>
- 场景二:watch监听路由对象的改变:
<div id="app"> <router-link to="/login">登录</router-link> <router-link to="/register">注册</router-link> <router-view></router-view> </div> <script> var login = Vue.extend({ template: '<h1>登录组件</h1>' }); var register = Vue.extend({ template: '<h1>注册组件</h1>' }); var router = new VueRouter({ routes: [ { path: "/login", component: login }, { path: "/register", component: register } ] }); // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: {}, methods: {}, router: router, watch: { '$route': function (newVal, oldVal) { if (newVal.path === '/login') { console.log('这是登录组件'); } } } }); </script>
computed
计算属性的使用
- 默认只有
getter
的计算属性:
<div id="app"> <input type="text" v-model="firstName"> + <input type="text" v-model="lastName"> = <span>{{ fullName }}</span> </div> <script> // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: { firstName: 'jack', lastName: 'chen' }, methods: {}, computed: { // 计算属性; 特点:当计算属性中所以来的任何一个 data 属性改变之后,都会重新触发 本计算属性 的重新计算,从而更新 fullName 的值 fullName() { return this.firstName + ' - ' + this.lastName; } } }); </script>
- 定义有
getter
和setter
的计算属性:
<div id="app"> <input type="text" v-model="firstName"> <input type="text" v-model="lastName"> <!-- 点击按钮重新为 计算属性 fullName 赋值 --> <input type="button" value="修改fullName" @click="changeName"> <span>{{fullName}}</span> </div> <script> // 创建 Vue 实例,得到 ViewModel var vm = new Vue({ el: '#app', data: { firstName: 'jack', lastName: 'chen' }, methods: { changeName() { this.fullName = 'TOM - chen2'; } }, computed: { fullName: { get: function () { return this.firstName + ' - ' + this.lastName; }, set: function (newVal) { var parts = newVal.split(' - '); this.firstName = parts[0]; this.lastName = parts[1]; } } } }); </script>
watch
、computed
和methods
之间的对比
computed
属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。主要当作属性来使用;methods
方法表示一个具体的操作,主要书写业务逻辑;watch
一个对象,键是需要观察的表达式,值是对应回调函数。主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作;可以看作是computed
和methods
的结合体;