什么是vue?
Vue是一套用于构建用户界面的渐进式JavaScript框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层,方便与第三方库或既有项目整合。
Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件
特点
易用
灵活
性能
MVC是后端分层开发概念
MVVM是前端视图层的概念,主要关注于视图层分离,也就是说,MVVM把前端的视图层,分为了三部分:Model,View,ViewModel
创建一个html
导入vue
vue cdn:
创建一个Vue实例
当我们导入包后,在浏览器内存中,就多了一个vue构造函数
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script type="text/javascript" src="https://unpkg.com/vue">script>
head>
<body>
<div id="app">
<h1>{{msg}}h1>
div>
<script>
var vm = new Vue({
el : '#app', // 表示,当前我们new的这个Vue实例,要控制页面上的哪个区域 #app 绑定了id为app的标签
data: {
// data 属性中,存放的是el中要用到的数据
msg: 'Hello,World!' // 通过Vue提供的指令,很方便的就能把数据渲染到页面上,不再手动操作DOM元素了
}
});
script>
body>
html>
解决插值表达式闪烁问题,闪烁问题:在打开页面时,会显示出{{msg}}
表达式,为了提升用户体验,我们在数据还没有加载出来时,让其显示空白
首先我们要给使用了插值表达式的标签,加上v-cloak
属性
然后通过css设置具有v-cloak
属性的标签的样式[v-cloak] {display: none;}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script type="text/javascript" src="https://unpkg.com/vue">script>
<style>
[v-cloak] {
display: none;
}
style>
head>
<body>
<div id="app">
<h1 v-cloak>{{msg}}h1>
div>
<script>
var vm = new Vue({
el : '#app',
data : {
msg: 'Hello,World!'
}
});
script>
body>
html>
和插值表达式没有太大区别,但是还是存在一些区别
v-text
不会具有闪烁问题,因为v-text
是属性v-text
会覆盖标签中原本的内容,但是插值表达式只会替换自己的占位符,不会清空其他内容<h1 v-text="msg">h1>h2>
和v-text相似,但是v-html可以解析html标签,v-html和v-text一样,同样会覆盖掉标签中原来的内容
<div id="app">
<div v-html="msg">div>
div>
<script>
var vm = new Vue({
el : '#app',
data : {
msg: 'i am a good boy!
'
}
});
script>
v-bind:
是vue中提供用来绑定属性的指令
<div id="app">
<input type="button" v-bind:title="mytitle" value="按钮">
div>
<script>
var vm = new Vue({
el : '#app',
data : {
mytitle:"这是一个自己定义的title"
}
});
script>
v-bind:
支持拼接,可以写合法的js表达式
<input type="button" v-bind:title="mytitle + '123'" value="按钮">
v-bind:
可以简写成一个冒号:
<input type="button" v-bind:title="mytitle" value="按钮">
Vue中提供了v-on:
事件绑定机制
<div id="app">
<input type="button" value="按钮" v-on:click="sayHi">
div>
<script>
var vm = new Vue({
el : '#app',
data : {
},
methods: { // 这个methods属性中定义了当前Vue实例所有可用的方法
sayHi : function () {
alert("Hi~~~");
}
}
});
script>
v-on:
可以简写成@
<input type="button" value="按钮" @click="sayHi">
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
<script type="text/javascript" src="https://unpkg.com/vue">script>
head>
<body>
<div id="app">
<button @click="start">开始button>
<button @click="end" >暂停button>
<div v-text="msg">div>
div>
<script>
var vm = new Vue({
el : '#app',
data : {
msg : '大风起兮云飞扬。威加海内兮归故乡。安得猛士兮守四方!',
flag : false, // 存放是否已经开启定时器的标志
intervalName:"" // 存放定时器名称
},
methods:{
start() {
var _this = this; // 解决在定时器内部this的指向问题
if (!this.flag){
this.flag=true;
this.intervalName = setInterval(function () {
var s = _this.msg.substring(0,1);
var e = _this.msg.substring(1);
_this.msg = e + s;
},100);
}
},
end(){
if (this.flag){
this.flag=false;
clearInterval(this.intervalName);
}
}
}
});
script>
body>
html>
事件默认会有冒泡机制
.stop 阻止冒泡
.prevent 阻止默认事件
.capture 添加事件侦听器时使用事件捕获模式
.self 只当事件在该元素本身(比如不是子元素)触发时触发回调,相当于阻止自己被冒泡
.once 事件只触发一次
<div id="app">
<div class="inner" @click.capture="divhandler">
<input type="button" value="点我一下" @click.stop="btnhandler">
<a href="https://www.baidu.com" @click.prevent="linkClick">百度a>
<a href="https://www.baidu.com" @click.prevent.once="linkClick">百度a>
div>
div>
<script>
var vm = new Vue({
el : '#app',
data : {
},
methods : {
divhandler(){
alert("点击了div");
},
btnhandler(){
alert("点击了btn");
},
linkClick(){
alert("出发了linkClick事件");
}
}
});
script>
v-model指令,可以实现表单元素和Model中的数据的双向绑定
注意:v-model只能用用在表单元素中!!
当页面中的数据修改时,data中的数据也会修改
当data中的数据修改时,页面中的数据也会修改
<div id="app">
<input type="text" v-model="msg" >
<p v-text="msg">p>
div>
<script>
var vm = new Vue({
el : '#app',
data : {
msg : ''
}
});
script>
通过v-model实现一个简单的小计算器
<div id="app">
<input type="text" v-model="num1">
<select v-model="opt">
<option value="+">+option>
<option value="-">-option>
<option value="*">*option>
<option value="/">/option>
select>
<input type="text" v-model="num2">
<input type="button" value="=" @click="test">
<input type="text" v-model="result">
div>
<script>
var vm = new Vue({
el : '#app',
data : {
num1 : '',
num2 : '',
result:'',
opt:'+'
},
methods: {
test(){
// 方法一:
// switch (this.opt) {
// case '+':
// this.result = parseInt(this.num1)+parseInt(this.num2);
// break;
// case '-':
// this.result = parseInt(this.num1)-parseInt(this.num2);
// break;
// case '*':
// this.result = parseInt(this.num1)*parseInt(this.num2);
// break;
// case '/':
// this.result = parseInt(this.num1)/parseInt(this.num2);
// break;
// }
// 方法二:
var codeStr = 'parseInt(this.num1)'+this.opt+'parseInt(this.num2)';
this.result = eval(codeStr); // eval函数解析执行 尽量少用这种方式
}
}
});
script>
数组
直接传递一个数组,注意:这里的class需要使用v-bind做数据绑定
<div id="app">
<h1 :class="['red','thin']">这是一个很大的h1,大到你无法想象~h1>
div>
数组中使用三元表达式
<div id="app">
<h1 :class="['red','thin',flag==true?'active':'']">这是一个很大的h1,大到你无法想象h1>
div>
<script>
var vm = new Vue({
el : '#app',
data : {
flag: true
}
});
script>
数组中嵌套对象
对象代替三元表达式,提高代码的可读性
<div id="app">
<h1 :class="['red','thin',{'active':flag}]">这是一个很大的h1,大到你无法想象h1>
div>
<script>
var vm = new Vue({
el : '#app',
data : {
flag: true
}
});
script>
直接使用对象
在为class使用v-bind绑定对象的时候,对象是属性是类名,属性值是一个标识符;对象的属性可以加引号也可以不加引号
<h1 :class="{thin:true,red:true,italic:false,active:true}">这是一个很大的h1,大到你无法想象h1>
直接在元素上通过:style
的形式,书写样式对象
<div id="app">
<h1 :style="{color:'red','font-weight':'200'}">这是一个h1h1>
div>
将样式对象,定义到data中,并直接引用到:style
中
<div id="app">
<h1 :style=styleobj>这是一个h1h1>
div>
<script>
var vm = new Vue({
el:'#app',
data : {
styleobj : {color:'red','font-weight':'200'}
}
});
script>
在:style
中通过数组,引用多个data
上的样式对象
<div id="app">
<h1 :style=[styleobj,styleobj2]>这是一个h1h1>
div>
<script>
var vm = new Vue({
el:'#app',
data : {
styleobj : {color:'red','font-weight':'200'},
styleobj2: {'font-style':'italic','letter-spacing': '0.5em'}
}
});
script>
遍历普通数组
<div id="app">
<p v-for="(item,index) in list" v-text="'索引值:'+index+' 每一项:'+item" >p>
div>
<script>
var vm = new Vue({
el : '#app',
data : {
list : [1,2,3,4,5,6]
}
});
script>
遍历数组对象
<div id="app">
<p v-for="(item,index) in list" v-text="'索引值:'+index+' id:'+item.id+' name:'+item.name" >p>
div>
<script>
var vm = new Vue({
el : '#app',
data : {
list : [
{id : 1,name : 'ls'},
{id : 2,name : 'zs'},
{id : 3,name : 'ww'},
{id : 4,name : 'cj'},
]
}
});
script>
遍历对象
在遍历对象身上的键值对的时候,除了有val:值,key:属性名,在第三个位置还有index:索引
<div id="app">
<p v-for="(val,key,index) in user " v-text="'索引:'+index+' key: '+key+' value: '+val">p>
div>
<script>
var vm = new Vue({
el : '#app',
data : {
user : {
id:1,
name:'杨幂',
gender:'woman',
age : '12'
}
}
});
script>
迭代数字
v-for迭代数字,i 从1开始
<div id="app">
<p v-for="i in 10" v-text="'这是第'+i+'次循环~'">p>
div>
v-for中key的使用注意事项
在2.20+的版本里,当在组件中使用v-for时,key是必须的
在循环时,通过key来标识现在这一项的唯一身份
<div id="app">
<input type="text" placeholder="id" v-model="id">
<input type="text" placeholder="name" v-model="name">
<input type="button" value="添加" @click="add">
<p v-for="(item,index) in list" :key="item.id">
<input type="checkbox">
{{item.id}}-------------{{item.name}}
p>
div>
<script>
var vm = new Vue({
el : '#app',
data : {
id:'',
name:'',
list : [
{id :1,name:'刘备'},
{id :2,name:'关羽'},
{id :3,name:'张飞'},
{id :4,name:'赵云'},
]
},
methods : {
add(){
var user = {id:this.id,name:this.name};
this.list.unshift(user);
this.id="";
this.name="";
}
}
});
一般来说,v-if更高的切换消耗而v-show有更高的初始渲染消耗,因此,如果需要频繁切换,v-show较好,如果在运行时条件不大可能改变v-if较好
<div id="app">
<input type="button" value="切换" @click="change">
<h2 v-if="flag">这是用v-if控制的元素h2>
<h2 v-show="flag">这是用v-show控制的元素h2>
div>
<script>
var vm = new Vue({
el : '#app',
data : {
flag:true
},
methods : {
change(){
this.flag = !this.flag;
}
}
});
script>
v-if 每次都会重新删除或创建元素
v-show 每次不会重新进行DOM的创建或删除操作,只是相当于是给标签加上了display:none
样式
<div id="app">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">添加品牌h3>
div>
<div class="panel-body form-inline">
<label>
Id:
<input type="text" class="form-control" v-model="id">
label>
<label>
Name:
<input type="text" class="form-control" v-model="name">
label>
<input type="button" class="btn btn-primary" value="添加" @click="add">
<label>
搜索名称关键字:
<input type="text" class="form-control" @input="search" v-model="keywords">
label>
div>
div>
<table class="table table-bordered table-hover table-striped">
<thead>
<tr>
<th>Idth>
<th>Nameth>
<th>Ctimeth>
<th>Operationth>
tr>
thead>
<tbody>
<tr v-for="(item,index) in search(keywords)" :key="item.id">
<th v-text="item.id">th>
<th v-text="item.name">th>
<th v-text="item.ctime">th>
<th><input type="button" value="删除" @click="del(item.id)" class="btn btn-primary">th>
tr>
tbody>
table>
div>
<script>
var vm = new Vue({
el : '#app',
data : {
id:'',
name:'',
keywords:'',
list : [
{id:1,name:'奔驰',ctime:new Date()},
{id:2,name:'宝马',ctime:new Date()},
{id:3,name:'福特',ctime:new Date()},
{id:4,name:'兰博基尼',ctime:new Date()},
{id:5,name:'玛莎拉蒂',ctime:new Date()}
]
},
methods : {
add(){
this.list.push({id:this.id,name: this.name,ctime: new Date()});
this.id="";
this.name="";
},
del(id){
that = this;
this.list.forEach(function (item,index) {
if (item.id==id){
that.list.splice(index,1);
}
});
},
search(){
var keywords = this.keywords;
// 方法一:
// var nlist = [];
// this.list.forEach(function (item,index) {
// if (item.name.indexOf(keywords)!=-1){
// nlist.push(item);
// }
// })
// return nlist;
// 方法二:
return this.list.filter(function (item) {
if (item.name.includes(keywords)){
return item;
}
})
}
}
});
script>
Vue中允许自己定义过滤器,可被用作一些常见的文本格式化,过滤器可以用在两个地方:mustachc
插值和v-bind
表达式,过滤器应该被添加在JavaScript表达式尾部,有“管道”符指示
过滤器在调用时:
<p>{{name | nameope}}p>
{{属性 | 过滤器名称}}
所谓的全局过滤器,就是所有Vue实例共享的
全局过滤器的定义:
Vue.filter('过滤器名称',function (data) {
// 对传过来的值做处理
})
过滤器中的function第一个参数已经被规定死了,永远都是过滤器管道符前面传递过来的数据,如{{name | nameope}}
,就是向nameope过滤器中传递name参数
过滤器要定义在Vue实例之前
调用过滤器时,也可以传递参数,要在定义过滤器时进行参数接收,可以传递多个参数
<div id="app">
<h1>{{msg | msgFormat('阳光') }}h1>
div>
<script>
// 定义一个vue的全局过滤器
Vue.filter('msgFormat',function (data,arg) {
return data.replace(/单纯/g,arg);
});
var vm = new Vue({
el : '#app',
data : {
msg : '曾经,我也是一个单纯的少年,单纯的我傻傻的问,谁是世界上最单纯的男人'
}
});
script>
可以调用多个过滤器,多个过滤器之间用管道符 | 隔开
<div id="app">
<h1>{{msg | msgFormat('疯狂') | test }}h1>
div>
<script>
// 定义一个vue的全局过滤器
Vue.filter('msgFormat',function (data,arg) {
return data.replace(/单纯/g,arg);
});
Vue.filter('test',function (data) {
return data + "-------这是第二个过滤器"
})
var vm = new Vue({
el : '#app',
data : {
msg : '曾经,我也是一个单纯的少年,单纯的我傻傻的问,谁是世界上最单纯的男人'
}
});
script>
调用多个过滤器时,第一个过滤器处理完成后,交给第二个过滤器,最后一个过滤器处理完成后,输出结果~
时间格式化:
<th>{{item.ctime | timeFormat}}th>
// 进行时间的格式化
<script>
Vue.filter('timeFormat',function (data) {
var dt = new Date(data);
var y = dt.getFullYear();
var m = dt.getMonth()+1;
var d = dt.getDate();
var h = dt.getHours();
var mi = dt.getMinutes();
var s = dt.getSeconds();
return `${y}-${m}-${d} ${h}:${mi}:${s}`; // 模板字符串
})
script>
<div id="app2">
<h2>{{dt|dtFormat}}h2>
div>
<script>
var vm2 = new Vue({
el : '#app2',
data : {
dt : new Date()
},
methods: {
},
filters: {
dtFormat: function (data) {
var dt = new Date(data);
var y = dt.getFullYear();
var m = dt.getMonth();
var d = dt.getDate();
var h = dt.getHours();
var min = dt.getMinutes();
var s = dt.getSeconds();
return `${y}-${m}-${d} ${h}:${min}:${s}`;
}
}
});
script>
过滤器调用的时候采取就近原则,如果私有过滤器和全局过滤器名称一致,这时候优先调用私有过滤器
补充:ES6中字符串新方法padStart,padEnd
string.prototype.padStart(maxLength,fillString="");//参数1:填充长度后总长度 参数2:用什么填充
string.prototype.padEnd(2,'0'); // 参数1:填充长度后总长度 参数2:用什么填充
<input type="text" @keyup.enter="add">
vue中提供的
.enter .up .tab
.down .delete .left
.esc(捕获删除和退格键) .right
.space
我们可以查询js里面的键盘时间对应的键盘码
<input type="text" @keyup.113="add">
我们可以自定义全局按键修饰符
<input type="text" @keyup.f2="add">
<script>
Vue.config.keyCodes.f2=113;
script>
这样,按键被定义后就可以直接使用了,相当于对键盘码取了一个别名,如果未定义不可以直接使用f2
在Vue中,所有的指令,在调用的时候都以v-
开头
在原生js中,文本框自动获取焦点
document.getElementById("search").focus();
但是在Vue中,不提倡这么做,我们可以通过自定义指令来实现
使用Vue.directive
定义全局指令,其中参数1:指令的名称,在定义的时候,指令名不与要加前缀v-
,在调用时,必须在指令名称前加v-
前缀。参数2:是一个对象,这个对象上,有一些指令相关的函数,这些函数可以在特定的阶段,执行相关的操作。
在每个函数中,第一个参数永远是el,表示被绑定的那个元素,这个el参数,是一个原生的js对象
定义全局指令
<script>
// 参数1:指令的名称,在定义的时候,指令的名称前面,不需要加 v- 前缀,在调用的时候必须加上v-前缀
// 参数2:是一个对象,这个对象上,有一些指令相关的函数,这些函数可以在特定的阶段,执行相关的操作
Vue.directive('focus',{
bind:function (el) {
// 每当指令绑定到元素上的时候,会立即执行这个bind函数,只执行一次
// 在元素刚绑定了指令的时候,还没有插入到DOM中去,这时候调用focus方法没有作用
},
inserted:function (el) {
// 元素插入到DOM中的时候会执行inserted函数 ,只触发一次
el.focus();
},
updated:function (el) {
// 当组件VNode更新的时候会执行updated 可能会触发多次
}
})
script>
和JS行为有关的操作,最好在inserted函数中执行,防止JS行为不生效,和样式相关的操作,一般都在bind函数中执行
Vue.directive('color',{
// 样式,只要通过指令绑定给了元素,不管这个元素有没有被插入到页面中去,这个元素肯定有了一个内联的样式
//将来元素肯定会显示到页面中,这时候,浏览器的渲染引擎必然会解析样式,应用给这个元素
bind:function (el) {
el.style.color="red";
}
})
钩子函数的参数
name
:指令名,不包括 v-
前缀value
:指令的绑定值,例如:v-my-directive="1 + 1"
中,绑定值为 2
oldValue
:指令绑定的前一个值,仅在 update
和 componentUpdated
钩子中可用。无论值是否改变都可用expression
:字符串形式的指令表达式。例如 v-my-directive="1 + 1"
中,表达式为 "1 + 1"
。arg
:传给指令的参数,可选。例如 v-my-directive:foo
中,参数为 "foo"
modifiers
:一个包含修饰符的对象。例如:v-my-directive.foo.bar
中,修饰符对象为 { foo: true, bar: true }
vnode
:Vue 编译生成的虚拟节点oldVnode
:上一个虚拟节点,仅在 update
和 componentUpdated
钩子中可用<input type="text" v-color="'green'">
Vue.directive('color',{
// 样式,只要通过指令绑定给了元素,不管这个元素有没有被插入到页面中去,这个元素肯定有了一个内联的样式
//将来元素肯定会显示到页面中,这时候,浏览器的渲染引擎必然会解析样式,应用给这个元素
bind:function (el,bindding) {
el.style.color=bindding.value; // 通过bindding参数来获取传递的参数
}
})
<div id="app2">
<p v-size="'50px'" v-text="msg">p>
div>
<script>
var vm2 = new Vue({
el : '#app2',
data : {
msg: 'hello,world!'
},
methods: {
},
filters: {
},
directives: {
'size' : {
bind : function (el,binding) {
el.style.fontSize=binding.value;
}
}
}
});
script>
什么是生命周期?
从Vue实例创建、运行、到销毁期间,总是伴随着各种各样的事件,这些事件,统称为生命周期!
生命周期钩子:就是生命周期事件的别名!
生命周期钩子=生命周期函数=生命周期事件
主要生命周期函数分类:
<div id="app">
<input type="button" value="改变msg" @click="msg='No'">
<h3 id="h3">{{msg}}h3>
div>
<script>
var vm = new Vue({
el : '#app',
data : {
msg : 'ok'
},
methods: {
show : function () {
console.log("执行了show方法~");
}
},
beforeCreate:function () {
// 这是我们遇到的第一个生命周期函数,实例被创建出来之前,执行它
// 在beforeCreate生命周期函数执行的时候,data和methods中的数据都还没有初始化
console.log(this.msg); // undefined
// this.show(); // this.show() is not a function
},
created: function () {
// 在created中,data和methods中的数据都已经被初始化好了
// 如果要调用methods中的方法,或者操作data中的数据,最早只能在该方法中
console.log(this.msg); // ok
this.show(); // 执行了show方法~
},
beforeMount :function () {
// 模板已经编译完成了,但是尚未把模板渲染到页面中
// 在beforeMount执行的时候,页面中的元素还没有真正被替换过来,只是之前写的一些模板字符串
console.log(document.getElementById("h3").innerText); // {{msg}}
},
mounted :function () {
// 内存中的模板,已经真实的挂载到了页面中,用户已经可以看到渲染好的页面了
// mounted 是实例创建期间的最后一个生命周期函数,当执行完mounted就表示,实例已经被完全创建好了
// 此时,如果没有其它操作的话,这个实例就静静的存在内存中
// 如果要通过某些插件操作页面上的dom节点,最早要在该方法中
console.log(document.getElementById("h3").innerText); // ok
},
beforeUpdate : function () {
// 这时候表示,我们的界面还没有被更新,但是data数据已经被更新了
// 当执行该函数的时候,页面中显示的数据还是旧的,此时data中的数据是最新的,页面尚未和最新的数据保存同步
console.log("界面上元素的内容:"+document.getElementById("h3").innerText); // 界面上元素的内容:ok
console.log("data中的msg数据:"+this.msg); // data中的msg数据:No
},
updated:function () {
// 页面和data数据已经保持同步了,都是最新的
console.log("界面上元素的内容:"+document.getElementById("h3").innerText); // 界面上元素的内容:No
console.log("data中的msg数据:"+this.msg); // data中的msg数据:No
},
beforeDestroy : function () {
// 当执行该函数时,就已经从运行阶段进入了销毁阶段
// 当执行该函数时,实例身上所有的data和所有的methods以及过滤器,指令等都处于可用状态,还没有真正执行销毁过程
},
destroyed : function () {
// 当执行到该函数时,实例已经被完全销毁了,此时实例身上所有的data和所有的methods以及过滤器,指令等都不可用了
}
});
script>
实现get,post,jsonp请求
首先要导入vue-resource.js cdn:
注意:vue-resource依赖于vue,所以要先导入vue在导入vue-resource
// global Vue object
Vue.http.get('/someUrl', [config]).then(successCallback, errorCallback);
Vue.http.post('/someUrl', [body], [config]).then(successCallback, errorCallback);
// in a Vue instance
this.$http.get('/someUrl', [config]).then(successCallback, errorCallback);
this.$http.post('/someUrl', [body], [config]).then(successCallback, errorCallback);
get(url, [config])
head(url, [config])
delete(url, [config])
jsonp(url, [config])
post(url, [body], [config])
put(url, [body], [config])
patch(url, [body], [config])
Config
Parameter | Type | Description |
---|---|---|
url | string |
URL to which the request is sent |
body | Object , FormData , string |
Data to be sent as the request body |
headers | Object |
Headers object to be sent as HTTP request headers |
params | Object |
Parameters object to be sent as URL parameters |
method | string |
HTTP method (e.g. GET, POST, …) |
responseType | string |
Type of the response body (e.g. text, blob, json, …) |
timeout | number |
Request timeout in milliseconds (0 means no timeout) |
credentials | boolean |
Indicates whether or not cross-site Access-Control requests should be made using credentials |
emulateHTTP | boolean |
Send PUT, PATCH and DELETE requests with a HTTP POST and set the X-HTTP-Method-Override header |
emulateJSON | boolean |
Send request body as application/x-www-form-urlencoded content type |
before | function(request) |
Callback function to modify the request object before it is sent |
uploadProgress | function(event) |
Callback function to handle the ProgressEvent of uploads |
downloadProgress | function(event) |
Callback function to handle the ProgressEvent of downloads |
Response
A request resolves to a response object with the following properties and methods:
Property | Type | Description |
---|---|---|
url | string |
Response URL origin |
body | Object , Blob , string |
Response body |
headers | Header |
Response Headers object |
ok | boolean |
HTTP status code between 200 and 299 |
status | number |
HTTP status code of the response |
statusText | string |
HTTP status text of the response |
Method | Type | Description |
text() | Promise |
Resolves the body as string |
json() | Promise |
Resolves the body as parsed JSON object |
blob() | Promise |
Resolves the body as Blob object |
<script>
var vm = new Vue({
el : '#app',
data : {
},
methods : {
getInfo : function () { // 发起get请求
// 当发起get请求后,通过.then来设置成功的回调函数
this.$http.get('localhost:8080/getTest',{params:{"arg":3}})
.then(function (result) {
// 请求成功执行回调函数
console.log(result);
},function () {
// 请求失败执行回调函数
console.log("请求失败!");
})
},
postInfo:function () {
// 发起post请求
// 手动发起的post请求,默认没有表单格式,有的服务器处理不了
// 通过post方法的第三个参数, {emulateJSON:true} 设置提交的内容类型为普通表单数据
this.$http.post('localhsot:8080/postTest',{params: {"id":1}},{})
.then(function (result) {
// 请求成功
console.log(result)
},function () {
// 请求失败
console.log("请求失败!")
})
},
jsonpInfo : function () { //发起jsonp请求
this.$http.jsonp('localhost:8080/jsonpTest',{params:{"id":2}}).then(function (result) {
// 请求成功
// 返回的为字符串,不是json对象
console.log(result);
}, function () {
console.log("请求失败");
})
}
}
});
script>
vue-rosource可以进行全局配置来设置根路径:
Vue.http.options.root="http://localhost:8080";
// 在发起请求时
// 路径会自动拼接为 http://localhost:8080/test
this.$http.get("/test").then(function(result){
...
});
全局配置emulateJSON选项
Vue.http.options.emulateJSON = true;
这样在发起POST请求时,就不用再单独设置提交的内容类型为普通表单数据了
jsonp的实现原理:
script
标签的形式,把script
标签的src属性,指向数据接口的地址,因为script
标签不存在跨域限制,这种数据获取方式,乘坐jsonp(注意:jsonp只支持get请求)所以,在实际的开发中,采用前后端分离,前后端部署在不同的服务器上,为了解决跨域问题,一般都会使用jsonp请求
Axios是一个开源的可以用在浏览器和Node.js的异步通信框架,主要作用的实现AJAX异步通信
// get请求
方法里可以只写路径。如果请求失败捕获一下异常。
axios
.get('http://rap2api.taobao.org/app/mock/23080/resources/search',{
params: {
id: 5
}
})
.then(res => {
console.log('数据是:', res);
})
.catch((e) => { // 处理异常
console.log('获取数据失败');
});
// post请求
this.$axios.post('http://rap2api.taobao.org/app/mock/121145/post',{
name: '小月'
})
.then(function(res){
console.log(res);
})
.catch(function(err){
console.log(err);
});
// 一次合并发送多个请求
function getUserAccount(){
return axios.get('/user/12345');
}
function getUserPermissions(){
return axios.get('/user/12345/permissions');
}
this.$axios.all([getUserAccount(),getUserPermissions()])
.then(axios.spread(function(res1,res2){
//当这两个请求都完成的时候会触发这个函数,两个参数分别代表返回的结果
}))
首先要导入axios,通过cdn
<script src="https://unpkg.com/axios/dist/axios.min.js">script>
<script>
var vm = new Vue({
el : '#app',
methods : {
},
data() {
return {
msg:"helloworld!",
// 请求返回参数合适,必须和json字符串一样
info : {
user : {
id :null,
name:null
}
}
}
},
mounted:function() {
that = this; // 要注意this的指向问题
axios.get('data.json').then(function (result) {
that.info = result.data.user;
})
}
});
script>
<script>
var vm = new Vue({
el : '#app',
data : {
msg: "hello",
info : {
user : {
id : null,
name : null
}
}
},
methods : {
},
mounted:function() {
that = this;
axios.get('data.json').then(function (result) {
that.info = result.data.user;
})
}
});
script>
为什么要写renturn返回
因为不使用return包裹的数据会在项目的全局可见,会造成变量污染
使用return包裹后数据中变量只在当前组件中生效,不会影响其他组件。
参数
1、url(必写)
请求地址
2、method
请求方法,默认是get
3、baseURL(常用)
baseURL会添加到url前(url是绝对地址除外)。
4、transformRequest
transformRequest
选项允许我们在请求发送到服务器之前对请求的数据做出一些改动
该选项只适用于以下请求方式:put/post/patch
5、transformResponse
transformResponse
选项允许我们在数据传送到then/catch
方法之前对数据进行改动
6、headers(常用,如设置请求头json类型)
自定义请求头信息
7、params(常用,只有get请求设置params,其他请求需设置params,即只有get的请求参数位于url后,其他请求参数都在请求体中)
params
选项是要随请求一起发送的请求参数----一般链接在URL后面
8、data(常用)
data
选项是作为一个请求体而需要被发送的数据,该选项只适用于方法:put/post/patch
在浏览器上data只能是FormData, File, Blob格式
9、timeout(常用)
超时时间
10、withCredentials
withCredentails
选项表明了是否是跨域请求、默认是default
11、onUploadProgress
onUploadProgress
上传进度事件
12、onDownloadProgress
下载进度的事件
13、maxContentLength
相应内容的最大值
注意:axios也要跨域问题!!axios只有两种请求方式:GET和POST
可以把计算属性想象成缓存!
当其中的某个数据发生改变时,其数据才会更新!!
在computed中可以定义一些属性,这些属性叫做【计算属性】,计算属性的本质就是一个方法,只不过,我们在使用这些计算属性的时候,是把他们的名称直接当作属性来使用,并不会把计算属性当作方法来使用
注意:计算属性,在引用的时候,一定不要加()去调用,直接把他当作普通属性
注意:计算属性内部,所依赖的任何data中的数据,只要发生变化,必然会重新计算 这个 计算属性的值
注意:计算属性的求值结果,会被缓存起来,方便下次直接使用,如果,计算属性方法中,所依赖的任何数据,都没有发生过变化,则不会重新对计算属性求值
<div id="app">
<h3>currentTime1 : {{currentTime1()}}h3>
<h3>currentTime2 : {{currentTime2}}h3>
div>
<script>
var vm = new Vue({
el : '#app',
data : {
msg : "hello,world!"
},
methods: {
currentTime1 : function () {
return new Date();
}
},
computed:{
// 计算属性,methods和computed方法名重名后,只会调用methods中的方法
// 计算属性中的方法通过属性来调用,不用加()
currentTime2 : function () {
this.msg; // 当msg的数据改变时,返回结果才会重新刷新
return new Date();
}
}
})
script>
将那些不经常变化的数据,我们可以将其放入缓存中!
Vue 提供了 transition
的封装组件,在下列情形中,可以给任何元素和组件添加进入/离开过渡
v-if
)v-show
)在进入/离开的过渡中,会有 6 个 class 切换。
v-enter
:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。v-enter-active
:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。v-enter-to
:2.1.8 版及以上定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter
被移除),在过渡/动画完成之后移除。v-leave
:定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。v-leave-active
:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。v-leave-to
:2.1.8 版及以上定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave
被删除),在过渡/动画完成之后移除。
<style>
/* v-enter【这是一个时间点】 进入之前,元素的起始状态,此时还没有开始进入 */
/* v-leave-to 【这是一个时间点】 是动画离开之后,离开的终止状态,此时,元素动画已经结束了 */
.v-enter,
.v-leave-to {
/* 透明度为0 */
opacity: 0;
transform: translate(80px);
}
/* v-enter-active 【入场动画的时间段】 */
/* v-leave-active 【离场动画的时间段】 */
.v-enter-active,
.v-leave-active {
transition: all 0.4s ease;
}
style>
head>
<body>
<div id="app">
<input type="button" value="切换" @click="flag=!flag">
<transition><h3 v-if="flag">这是一个h3h3>transition>
div>
<script>
var vm = new Vue({
el : '#app',
data : {
flag: false
}
});
script>
body>
对于这些在过渡中切换的类名来说,如果你使用一个没有名字的
,则 v-
是这些类名的默认前缀。如果你使用了
,那么v-enter
会替换为me-enter
Animate.css官网:https://animate.style/
animate.css cdn:
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/4.0.0/animate.min.css">
<div id="app">
<input type="button" value="切换" @click="flag=!flag">
<transition enter-active-class="animate__animated animate__bounce" leave-active-class="animate__animated animate__wobble" :duration="{enter:200,leave:400}">
<h3 v-show="flag">这是一个H3h3>
transition>
div>
<script>
var vm = new Vue({
el : '#app',
data : {
flag : false
}
});
script>
半场动画:只有入场,没有离场的动画
<transition
v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:after-enter="afterEnter"
v-on:enter-cancelled="enterCancelled"
v-on:before-leave="beforeLeave"
v-on:leave="leave"
v-on:after-leave="afterLeave"
v-on:leave-cancelled="leaveCancelled"
>
transition>
// ...
methods: {
// --------
// 进入中
// --------
// 动画钩子函数的第一个参数,el 表示要执行动画的那个DOM元素
beforeEnter: function (el) {
// ...
},
// 当与 CSS 结合使用时
// 回调函数 done 是可选的
enter: function (el, done) {
// ...
done()
},
afterEnter: function (el) {
// ...
},
enterCancelled: function (el) {
// ...
},
// --------
// 离开时
// --------
beforeLeave: function (el) {
// ...
},
// 当与 CSS 结合使用时
// 回调函数 done 是可选的
leave: function (el, done) {
// ...
done()
},
afterLeave: function (el) {
// ...
},
// leaveCancelled 只用于 v-show 中
leaveCancelled: function (el) {
// ...
}
}
如果要实现半场动画,只需要写入场或者离场的就可以了!!
<div id="app">
<input type="button" value="执行" @click="flag=!flag">
<transition v-on:before-enter="beforeEnter"
v-on:enter="enter"
v-on:after-enter="afterEnter">
<div class="ball" v-show="flag">div>
transition>
div>
<script>
var vm = new Vue({
el : '#app',
data : {
flag : false
},
methods : {
beforeEnter : function(el){
// 入场之前 , 此时动画尚未开始
// 可以在beforeEnter中设置元素开始动画之前的起始样式
// 设置小球开始动画之前的起始位置
el.style.transform = "translate(0,0)";
},
enter : function(el,done){
// 这句话没有实际的作用,但是不写出不来动画效果
// 可以任务el.offsetWidth会强制动画刷新
el.offsetWidth;
// enter表示动画开始之后的样式,这里,可以设置小球完成动画之后的结束状态
el.style.transform = "translate(150px,450px)";
el.style.transition = "all 1s ease";
// 这里的done起始就是afterEnter函数,也就是说:done是函数afterEnter的引用
// 当只用 JavaScript 过渡的时候,在 enter 和 leave 中必须使用 done 进行回调。否则,它们将被同步调用,过渡会立即完成。
done();
},
afterEnter : function(el){
// 动画完成之后,会调用该函数
this.flag = !this.flag;
}
}
})
script>
**在实现列表过渡的时候,如果需要过渡的元素是通过v-for循环渲染出来的,不能使用标签包裹,需要使用标签包裹 **
如果要为 v-for 循环创建的元素设置动画,必须为每一个元素设置 :key 属性
给transition-group添加appear属性,实现当页面刚展示出来的时候,入场时候的效果
通过为transiont-group设置tag属性,指定transition-group渲染为指定的元素,如果不指定tag属性,则默认渲染为span
<style>
li {
border: 1px dashed #999;
margin: 5px;
line-height: 35px;
padding-left: 5px;
font-size: 12px;
width: 100%;
}
li:hover {
background-color: #999;
transition: all 0.4s ease;
}
.v-enter,
.v-leave-to {
opacity: 0;
transform: translateY(50px);
}
.v-enter-active,
.v-leave-active {
transition: all 1s ease;
}
/* v-move 和 v-leave-acvice 配合使用能够实现后续的元素渐渐的补齐 */
.v-move {
transition: all 0.4s ease;
}
.v-leave-active {
position: absolute;
}
style>
head>
<body>
<div id="app">
<div>
<label>id: <input type="text" placeholder="id" v-model="id"> label>
<label>name: <input type="text" placeholder="name" v-model="name" @keyup.enter="add">label>
<input type="button" value="添加" @click="add">
div>
<transition-group appear tag="ul">
<li v-for="(user,index) in list" :key="user.id" @click="del(index)">{{user.id}}------------{{user.name}}li>
transition-group>
div>
<script>
var vm = new Vue({
el : '#app',
data : {
id: "",
name:"",
list : [
{id:1,name:'唐嫣'},
{id:2,name:'陈乔恩'},
{id:3,name:'刘诗诗'},
{id:4,name:'刘亦菲'},
{id:5,name:'白百合'}
]
},
methods : {
add: function(){
this.list.push({id:this.id,name:this.name});
this.id=this.name="";
},
del:function(index){
this.list.splice(index,1);
}
}
})
script>
body>
什么是组件:组件的出现,就是为了拆分Vue实例的代码量的,能够让我们以不同的组件,来划分不同的功能模块,将来我们需要什么样的功能,就可以去调用对应的组件!
组件化和模块化的不同:
方式一: 使用Vue.extend 来创建全局的Vue组件
注意:!!在创建全局组件时,组件名称可以用驼峰命名,但是在引用组件时,要使用 - 的形式连接,大写变小写
<div id="app">
<my-com1>my-com1>
div>
<script>
// 1 使用Vue.extend来创建全局的Vue组件
var com1 = Vue.extend({
template : 'hello,world
', // 通过template属性指定了组件要展示的HTML结构
});
// 2 使用Vue.component('组件名称',创建出来的组件模板对象)
Vue.extend('myCom1',com1);
var vm = new Vue({
el : '#app',
data : {
}
});
script>
Vue.extend 和 Vue.extend 合并为一步
Vue.component 第一个参数:组件名称 第二个参数:Vue.extend 创建的组件,其中template属性就是组件将来要展示的html
<div id="app">
<my-com1>my-com1>
div>
<script>
// Vue.component 第一个参数:组件名称 第二个参数:Vue.extend 创建的组件,其中template属性就是组件将来要展示的html
Vue.component('myCom1',Vue.extend({
template : 'hello world!
'
}));
var vm = new Vue({
el : '#app',
data : {
}
});
script>
方式二:相当于对方式一的简化
<script>
Vue.component('mycom2',{
// 注意,无论是哪种方式创建出来的组件,组件的template属性指向的模板内容必须有且只能有唯一的一个根元素
template : 'hello,world!
'
})
var vm = new Vue({
el : '#app',
data : {
}
});
script>
方式三:使用标签定义组件模板
在被控制的 #app 外面,使用template元素定义组件的模板结构
<template id="temp">
<h2>hello,world!1h2>
template>
<div id="app">
<mycom>mycom>
div>
<script>
Vue.component('mycom',{
template : '#temp'
})
var vm = new Vue({
el : '#app',
data : {
}
});
script>
<template id="mycom">
<h2>hello,world!h2>
template>
<div id="app">
<mycom>mycom>
div>
<script>
var vm = new Vue({
el : '#app',
data : {
},
components : {
mycom : {
template : '#mycom'
}
}
})
script>
data
组件可以有自己的data数据
组件中的data和实例的data有点不一样,实例中的data可以为一个对象,但是组件中的data必须是一个方法
组件中的data除了必须为一个方法外,这个方法内部还必须返回一个对象
组件中的data数据,使用方式,和实例中的data使用方式完全一样!!
<template id="temp">
<h3 v-text="msg">h3>
template>
<div id="app">
<mycom>mycom>
div>
<script>
Vue.component('mycom',{
template : '#temp',
data(){
return {
msg : 'hello,world!'
}
}
})
var vm = new Vue({
el : '#app',
data : {
}
});
script>
组件中的data必须是一个方法,这样组件中data数据就是组件私有的了,不会影响到其他组件!
<template id="temp">
<div>
<h3>{{num}}h3>
div>
template>
<div id="app">
<mycom>mycom>
<hr>
<mycom>mycom>
<hr>
<mycom>mycom>
<hr>
div>
<script>
var dataObj = {num : 0}
Vue.component('mycom',{
template : '#temp',
data(){
return dataObj
},
methods : {
increment : function(){
console.log(this.num)
this.num++;
}
}
})
var vm = new Vue({
el : '#app'
});
script>
如果像这样,组件中的data数据就不是私有的了,多次引用同一个组件mycom,其中一个变化,其他组件中的data数据也会随之变化,所以组件中的data必须是一个方法
<template id="temp">
<div>
<h3>{{num}}h3>
div>
template>
<div id="app">
<mycom>mycom>
<hr>
<mycom>mycom>
<hr>
<mycom>mycom>
<hr>
div>
<script>
Vue.component('mycom',{
template : '#temp',
data(){
return {
num : 0
}
},
methods : {
increment : function(){
console.log(this.num)
this.num++;
}
}
})
var vm = new Vue({
el : '#app'
});
script>
方式一:使用v-if和v-else结合flag进行切换
<template id="login">
<h1>登录h1>
template>
<template id="register">
<h1>注册h1>
template>
<div id="app">
<login v-if="flag">login>
<register v-else="flag">register>
div>
<script>
Vue.component('login',{
template : '#login'
})
Vue.component('register',{
template : '#register'
})
var vm = new Vue({
el : '#app',
data : {
flag : true
}
})
script>
方式二:使用Vue提供的component元素实现组件切换
vue提供了component元素来展示对应名称的组件
<template id="login">
<h1>登录h1>
template>
<template id="register">
<h1>注册h1>
template>
<div id="app">
<component :is="comName">component>
div>
<script>
Vue.component('login',{
template : '#login'
})
Vue.component('register',{
template : '#register'
})
var vm = new Vue({
el : '#app',
data : {
comName : 'login'
}
})
script>
方式三:应用切换动画和model方式
直接用
包裹
组件标签,
标签有一个属性mode
,通过mode属性设置组件切换时候的方式,如out-in
是先离场,后进场
<style>
.v-enter,
.v-leave-to {
opacity: 0;
transform: translateY(150px);
}
.v-enter-active,
.v-leave-active{
transition: all 1s ease;
}
style>
<body>
<template id="login">
<h1>登录h1>
template>
<template id="register">
<h1>注册h1>
template>
<div id="app">
<transition mode="out-in">
<component :is="comName">component>
transition>
div>
<script>
Vue.component('login',{
template : '#login'
})
Vue.component('register',{
template : '#register'
})
var vm = new Vue({
el : '#app',
data : {
comName : 'login'
}
})
script>
body>
父向子组件传值
子组件,默认不能够直接访问到父组件data中的数据和methods中的方法
父组件,可以在引用子组件的时候,通过属性绑定(v-bind)的形式,把需要传递给子组件的数据,以属性绑定的形式,传递到子组件内部,供子组件使用
注意:组件中的所有props中的数据,都是通过父组件传递给子组件的
props 中的数据都是只读的,无法重新赋值,data中的数据都是可读可写的
<div id="app">
<com1 :parentmsg="msg">com1>
div>
<script>
var vm = new Vue({
el : '#app',
data : {
msg : '123 父组件中的数据'
},
components : {
// 子组件,默认不能够直接访问到父组件data中的数据和methods中的方法
com1 : {
template : '这是子组件---{{parentmsg}}
',
// 注意:组件中的所有props中的数据,都是通过父组件传递给子组件的
// props 中的数据都是只读的,无法重新赋值,data中的数据都是可读可写的
// 把父组件传递过来的 parentmsg 属性,现在props 数组中,定义一下,这样,才能使用这个数据
props:['parentmsg'],
data(){
return {
parentmsg : 'hello'
}
}
}
}
})
script>
父组件把方法传递给子组件,子组件通过事件调用向父组件传值
v-on:
当我们自定义了一个事件属性之后,那么子组件就能通过某些方式来调用传递进去的这个方法了this.$emit('绑定的事件属性名')
来拿到并执行父组件的方法<template id="temp">
<div>
<h1>这是子组件h1>
<input type="button" @click="myclick" value="点击一下">
div>
template>
<div id="app">
<com1 @func="show">com1>
div>
<script>
// 定义了一个字面量类型的组件模板对象
var com1 = {
template : "#temp",
methods : {
myclick : function(){
// 当点击子组件按钮的时候 拿到父组件传递过来的方法并调用这个方法
// emit 触发
this.$emit('func',this.sonmsg,789)
}
},
data(){
return {
sonmsg : {id : 1 ,name : '唐嫣'}
}
}
}
var vm = new Vue({
el : '#app',
data : {
dataFromSon : ''
},
methods : {
show : function(arg1,arg2){
this.dataFromSon = arg1; // 把从子组件传递的数据存放到data中
console.log("调用了父组件的show方法~---------"+arg1.id+"----"+arg1.name+"--"+arg2);
}
},
components : {
com1 : com1
}
})
script>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
<link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.css">
<script type="text/javascript" src="https://unpkg.com/vue">script>
<style>
li {
border: 1px dashed #999;
margin: 5px;
line-height: 35px;
padding-left: 5px;
font-size: 12px;
width: 100%;
}
li:hover {
background-color: #999;
transition: all 0.4s ease;
}
.v-enter,
.v-leave-to {
opacity: 0;
transform: translateY(50px);
}
.v-enter-active,
.v-leave-active {
transition: all 1s ease;
}
.v-move {
transition: all 1s ease;
}
.v-leave-active {
position: absolute;
}
style>
head>
<body>
<template id="temp">
<div>
<div class="form-group">
<label>评论人:label>
<input type="text" class="form-control" v-model="user" v-focus>
div>
<div class="form-group">
<label>内容:label>
<textarea class="form-control" v-model="content">textarea>
div>
<div class="form-group">
<input type="button" value="发表评论" class="btn btn-primary" @click="add">
div>
div>
template>
<div id="app">
<comment-box @func="add">comment-box>
<transition-group appear tag="ul" class="list-group">
<li class="list-group-item" v-for="(item,index) in list" :key="item.id" @click="del(index)">
<span class="badge">评论人:{{item.user}}span>
{{item.content}}
li>
transition-group>
div>
<script>
var commentBox = {
template : '#temp',
data(){
return {
user : '',
content : ''
}
},
methods : {
add : function(){
var comment = {id:Date.now(),user:this.user,content:this.content};
var list = JSON.parse(localStorage.getItem('cmts') || '[]'); // 读取本地缓存 如果读去不到 则返回一个空数组
list.unshift(comment); // 向从本地缓存中读取到的数组添加
localStorage.setItem('cmts',JSON.stringify(list)); // 将添加后的新数组重新存储到本地缓存中
this.user=this.content="";
this.$emit('func');
}
},
props : []
}
Vue.directive('focus',{
inserted : function(el) {
el.focus();
}
})
var vm = new Vue({
el : '#app',
data : {
list : [
// {id:Date.now()+"1",user:'唐嫣',content:'天生我材必有用'},
// {id:Date.now()+"2",user:'陈乔恩',content:'千金散尽还复来'},
// {id:Date.now()+"3",user:'刘诗诗',content:'大漠孤烟直'},
// {id:Date.now()+"4",user:'关晓彤',content:'长河落日圆'},
// {id:Date.now()+"5",user:'刘亦菲',content:'劝君更进一杯酒,西出阳关无故人'}
]
},
methods : {
add : function(){
var list = JSON.parse(localStorage.getItem('cmts') || '[]');
this.list = list;
},
del : function(index){
var list = JSON.parse(localStorage.getItem('cmts') || '[]'); // 获取到本地缓存中的数组
list.splice(index,1); // 根据index 删除一个数据
localStorage.setItem('cmts',JSON.stringify(list)); // 把删除后的数据重新存储到本地缓存中
this.list=list;
// this.list.splice(index,1);
}
},
components : {
commentBox : commentBox
},
beforeCreate() {
},
created(){
this.add();
}
})
script>
body>
html>
子组件向父组件传值和父组件调用子组件方法,通过$ref
<div id="app">
<input type="button" value="获取元素" @click="getElement">
<h3 ref="myh3">哈哈哈,今天天气太好了!h3>
<hr>
<login ref="login">login>
div>
<script>
var login ={
template : '登录
',
data(){
return {
msg : 'son msg'
}
},
methods: {
show() {
console.log("调用了子组件的方法!")
}
}
}
var vm = new Vue({
el : '#app',
data : {
},
methods : {
getElement: function(){
// ref 是英文单词 reference
console.log(this.$refs)
this.$refs.login.show(); // 执行了子组件的show()方法
}
},
components : {
login : 'login'
}
})
script>
什么是路由?
**后端路由:**对于普通网站,所有的超链接都是URL地址,所有的URL地址都对应服务器上对应的资源
**前端路由:**对于单页面应用程序员来说,主要通过URL中的hash(#号)来实现不同页面之间的切换,同时,hash有一个特点:HTTP请求中不包含hash相关的内容,所以,单页面程序中的页面跳转主要用hash实现
在单页面应用程序中,这种通过hash改变来切换页面的方式,称作前端路由(区别于后端路由)
vue-router cdn:
<script src="https://unpkg.com/vue-router/dist/vue-router.js">script>
在引入vue-router之前,一定要先引入vue,因为vue-router依赖于vue
如果使用npm安装,在一个模块化工程中使用它,必须要通过Vue.use()
明确地安装路由功能
如果使用全局的script
标签,则无需手动安装
步骤:
导入vue-router.js
创建一个路由对象,当导入 vue-router包之后,在 window全局对象中,就有了一个路由的构造函数,叫做VueRouter,在 new 路由对象的时候,可以为构造函数,传递一个配置对象route,route 表示【路由匹配规则】的意思,每个路由规则都是一个对象,这个规则对象,有两个必须的属性:属性1:path,表示监听哪个路由链接地址;属性2:component,表示如果路由是前面匹配到的path,则暂时component属性对应的组件。component的属性值必须是一个组件的模板对象,不能是组件的引用名称(字符串)
将路由规则对象,注册到vm实例上,用来监听URL地址变化,然后展示对应的组件
router-link
用来实现路由跳转,是有vue-router提供,它有一个属性to
,用来指定组件的路径,
router-view
是vue-router提供的元素,专门用来当作占位符的,将来,路由规则匹配到的组件就会展示到这个router-view中
<div id="app">
<a href="#/login">登录a>
<a href="#/register">注册a>
<router-link to="/login">登录router-link>
<router-link to="/register">注册router-link>
<router-view>router-view>
div>
<script>
var login = {
template : '登录
'
}
var register = {
template : '注册
'
}
// 创建一个路由对象,当导入 vue-router包之后,在 window全局对象中,就有了一个路由的构造函数,叫做VueRouter
// 在 new 路由对象的时候,可以为构造函数,传递一个配置对象
var routerObj = new VueRouter({
//route // 这个配置对象中的route 表示【路由匹配规则】的意思
routes : [ // 路由匹配规则
mode: 'history', //去掉url中的#
// 每个路由规则都是一个对象,这个规则对象,有两个必须的属性:
// 属性1:path,表示监听哪个路由链接地址
// 属性2:component,表示如果路由是前面匹配到的path,则暂时component属性对应的组件
// component的属性值必须是一个组件的模板对象,不能是组件的引用名称(字符串)
{path:'/login',component:login},
{path:'/register',component:register}
]
})
var vm = new Vue({
el : '#app',
components : {
login : 'login',
register : 'register'
},
router:routerObj // 将路由规则对象,注册到vm实例上,用来监听URL地址变化,然后展示对应的组件
})
script>
可以使用这中方式来实现,跳转,在访问/
根路径的时候,会自动跳转到login
组件,但此时浏览器地址栏还是会显示/
根路径,所以不推荐这种方式
{path:'/',component:login}
我们可以通过,redirect
属性来实现重定向
{path:'/',redirect:'/login'}
方式一
在
标签被选中时,会自动加上两个类,router-link-active
和router-link-exact-active
所以我们可以给router-link-active
类添加样式,来实现选中时的高亮效果
<style>
.router-link-active {
color: red;
}
style>
这样,在被选中的
标签就会有高亮效果了
方式二
如果要修改链接激活时使用的css类名,默认值可以通过路由的构造选项linkActiveClass
来全局配置,如
var routerObj = new VueRouter({
routes : [
{path:'/login',component:login},
{path:'/register',component:register},
{path:'/',redirect:'/login'},
],
// 修改链接激活时的css类名,在链接选中时,就会自动为标签添加active类
linkActiveClass : 'active'
})
.active {
font-size: 80px;
}
直接给
标签包裹
标签就可以了!
<style>
.v-enter,
.v-leave-to {
opacity: 0;
transform: translateX(150px);
}
.v-enter-active,
.v-leave-active {
transition: all 0.5s ease;
}
style>
<transition mode="out-in">
<router-view>router-view>
transition>
使用query方式传递参数
如果在路由中,使用?问号拼接参数,给路由传递参数,则不需要修改路由规则的path属性
this.$route.query
可以获取到路由传递的参数,一般在组件的生命周期函数 created
函数中获取路由传递的参数
<router-link to="/login?id=10&name=zs">登录router-link>
var login = {
template : '登录---{{id}}----{{name}}
',
data(){
return {
id : '',
name : ''
}
},
created(){ // 组件的生命周期钩子函数
this.id = this.$route.query.id ; // this.$route.query 可以获取到路由传递的参数
this.name = this.$route.query.name;
}
}
这种方式,有缺点,参数名,和参数值全部暴露在浏览器地址栏中了
使用params方式传递参数
很像restful风格
this.$route.params
可以获取到路由传递的参数,一般在组件的生命周期函数 created
函数中获取路由传递的参数
/:参数名
routes : [
{path:'/login/:id/:name',component : login}
],
<router-link to="/login/20/zs">登录router-link>
var login = {
template : '登录----{{id}}---{{name}}
',
data(){
return {
id : '',
name : ''
}
},
created(){
this.id = this.$route.params.id; // 通过 this.$route.params 获取路由传递的参数
this.name = this.$route.params.name;
}
}
子组件 路由路径要写在父组件路径下
在children中 定义的子组件的路由规则 path属性 不要加 /
<template id="temp">
<div>
<h1>这是account组件h1>
<router-link to="/account/login">登录router-link>
<router-link to="/account/register">注册router-link>
<router-view>router-view>
div>
template>
<div id="app">
<router-link to="/account">Accountrouter-link>
<router-view>router-view>
div>
<script>
var account = {
template : '#temp'
}
var login = {
template : '登录
'
}
var register = {
template : '注册
'
}
var routerObj = new VueRouter({
routes : [
{
path : '/account',
component : account,
children : [
// 定义子组件路由 path 不用加 /
{path:'login',component:login},
{path:'register',component:register}
]
}
]
});
var vm = new Vue({
el : '#app',
data : {
},
components : {
account,
login,
register
},
router : routerObj
})
script>
在一个页面需要多个组件时,就需要给
标签添加name属性,来指定对应的组件
在定义路由规则时,访问 /
根路径时,将多个组件共同显示出来,就要使用components
来定义一个路径下多个组件
<div id="app">
<router-view>router-view>
<router-view name="left">router-view>
<router-view name="main">router-view>
div>
<script>
var header = {
template : 'Header头部区域
'
}
var leftBox = {
template : 'leftBox左侧侧边栏区域
'
}
var mainBox = {
template : 'mainBox右侧主体区域
'
}
var routerObj = new VueRouter({
routes :[{
path : '/',
components :{
'default' : header,
'left': leftBox,
'main' : mainBox
}
}]
});
var vm = new Vue({
el : '#app',
components : {
header,
leftBox,
mainBox
},
router : routerObj
});
script>
<template id="temp">
<div>
<h1>组件一h1>
<slot name="s1">slot>
<slot name="s2">slot>
div>
template>
<div id="app">
<com>
<s1 slot="s1">s1>
<s2 slot="s2">s2>
com>
div>
<script>
Vue.component('com',{
template : '#temp'
})
Vue.component('s1',{
template : 's1s1s1
'
})
Vue.component('s2',{
template : 's2s2s2
'
})
var vm = new Vue({
el : '#app'
});
script>
使用这个属性 可以监视data中指定数据的变化,然后触发这个watch中对应的function处理函数
<div id="app">
<input type="text" placeholder="firstname" v-model="firstname" >
<input type="text" placeholder="lastname" v-model="lastname">
<input type="text" placeholder="name" v-model="name">
div>
<script>
var vm = new Vue({
el : '#app',
data : {
lastname : '',
firstname: '',
name : ''
},
watch : {
// 使用这个属性 可以监视data中指定数据的变化,然后触发这个watch中对应的function处理函数
firstname : function(){
// 当firstname的值改变时,就会执行该函数
this.name = this.firstname + this.lastname;
},
lastname : function(){
// 当lastname的值改变时,就会执行该函数
this.name = this.firstname + this.lastname;
}
}
});
script>
watch
属性中的方法中 有两个参数:
参数一:newVal
参数二:oldVal
watch : {
// 使用这个属性 可以监视data中指定数据的变化,然后触发这个watch中对应的function处理函数
firstname : function(newVal,oldVal){
// 当firstname的值改变时,就会执行该函数
this.name = newVal + this.lastname;
},
lastname : function(newVal,oldVal){
// 当lastname的值改变时,就会执行该函数
this.name = newVal + this.lastname;
}
}
监听路由的改变
watch : {
'$route.path' : function(newVal,oldVal){
console.log(newVal);
console.log(oldVal);
if(newVal == '/login'){
console.log("欢迎进入登录页面~~");
}
}
}
作用:提供了一些最常用的NPM包镜像地址,能够让我们快速的切换安装包时候的服务器地址
什么是镜像:原来包刚一开始是只存在于国外的NPM服务器,但是由于网络原因,经常访问不到,这时候,我们可以在国内,创建一个和官网完全一样的NPM服务器,只不过,数据都是从人家那里拿过来的,除此之外,使用方式完全一样
npm i nrm -g
全局安装nrm
包nrm ls
查看当前所有可用的镜像地址以及当前所使用的镜像的地址nrm use npm
或 nrm use taobao
切换不同的镜像源地址换成国内的淘宝镜像,可以提高装包时的速度
注意:nrm只是单纯的提供了几个常用的下载包的URL地址,并能够让我们在这几个地址之间很方便的进行切换,但是我们每次装包的时候,使用的装包工具还是npm
npm i cnpm -g
安装 cnpm 装包工具
在网页中会引用哪些常见的静态资源?
网页中引入的静态资源多了以后有什么问题?
如何解决上诉问题?
什么是webpack?
webpack安装的两种方式
npm i webpack -g
是全局安装webpack,这样能在全局使用webpack的指令npm i webpack --save-dev
安装到项目依赖中npm init
初始化项目,会生成一个package.json
的文件在index.html中我们只引入main.js,不再引入其他js文件,在main.js中,引入其他所有的js文件
在index.html中引入main.js
使用cnpm i jquery --save
安装jquery类库
这样就会生成一个node_modules
目录和package-lock.json
文件,jquery就在node_modules
中
在mian.js
中引入jquery
import xx from xx
为ES6中导入模块的方式
import $ from 'jquery'
这样我们就可以使用jquery来编写代码了
由于import xx from xx
属于ES6的语法,浏览器不能够解析,所以我们需要使用webpack
webpack 要打包的资源路径 输出路径
,如
webpack .\src\main.js .\dist\bundle.js
,将 main.js打包,输出到dist目录下,命名为bundle.js
这样,在index.html中,我们就不能够直接引入main.js,我们需要引入bundle.js
注意:如果是webpack4 可能会出现错误!
解决错误:
如果提示Cannot find module 'webpack-cli'
我们需要先全局安装 webpack-cli
,执行命令 npm i webpack-cli -g
这样在执行webpack .\src\main.js -o .\dist\bundle.js
就成功了!
这样就在dist目录下,生成了bundle.js文件
webpack处理了JS文件的相互依赖关系
webpack能够处理js的兼容性问题,把高级的,浏览器不识别的语法,转为低级的浏览器能正常识别的语法
我们想只执行webpack
命令,就可以让其将main.js
打包成bundle.js
我们需要在项目根目录下建一个配置文件webpack.config.js
在配置文件中进行配置
// 这个配置文件,其实就是一个js文件,通过Node中的模块操作,向外暴露了一个配置对象
const path = require('path')
module.exports = {
// 指定入口,main.js
entry : path.join(__dirname,'./src/main.js'), // 入口,表示要使用webpack打包哪个文件
output : {
path : path.join(__dirname,'./dist'), // 指定打包好的文件,输出到哪个目录中去
filename : 'bundle.js' // 指定输出的文件的名称
}
}
这样,我们只需要输入webpack
,就会自动帮我们打包main.js
,输出到bundle.js
使用webpack-dev-server这个工具,来实现自动打包编译的功能
在项目内执行命令 npm i webpack-dev-server -D
把这个工具安装到项目的本地开发依赖
安装完毕后,这个工具的的用法和webpack的命令的用法完全一样
由于,我们是在项目本地安装的webpack-dev-server
,所以无法把它当作脚本命令在powershell终端中直接运行 (只有那些安装到全局 -g 的工具才能在终端中执行)
所以,我们可以在package.json
文件中进行配置
配置完成后,我们直接执行命令npm rund dev
,就可以通过localhost:8080进行访问了
但是,这是,我们在index.html引入的js文件不能再是../dist/bundle.js
了,要改为
<script src="/bundle.js">script>
这样,我们再修改main.js
中的代码时,就不用再去单独的执行打包命令了!!
webpack-dev-server帮我们打包生成的bandle.js文件,并没有存放到实际的物理磁盘上,直接托管到了内存中!
方式一(推荐)
在package.json
中的配置
"dev":webpack-dev-server --open
,自动打开浏览器
"dev":webpack-dev-server --open --port 3000
,自动打开浏览器,同时运行的端口为 3000
"dev":webpack-dev-server --open --port 3000 --contentBase src
,自动打开浏览器,同时运行的端口为 3000,并且打开页面为src下的index.html
"dev":webpack-dev-server --open --port 3000 --contentBase src --hot
,自动打开浏览器,同时运行的端口为 3000,并且打开页面为src下的index.html,不重新生成bundle.js文件,只生成局部更新的文件
方式二
不在package.json
中进行配置,在webpack.config.js
中进行配置
devServer : {
// 这是配置dev-server命令参数的第二种形式
open : true, // 自动打开浏览器
port : 3000, // 设置启动时的运行端口
contentBase : 'src', // 指定托管的根目录
hot : true // 启用热部署
}
作用:在内存中,根据我们的index模板页面生成一个内存中的首页,我们就可以访问内存中的页面了
运行npm i html-webpack-plugin --save-dev
安装到开发环境
修改配置文件webpack.config.js
// 导入在内存生成html页面的插件
// 只要是插件,都一定要放到plugins节点中去
const htmlWebpackPlugin = require('html-webpack-plugin');
在配置文件webpack.config.js,中的plugins节点中配置
plugins : [
new htmlWebpackPlugin({
// 创建一个在内存中生成html页面的插件
template : path.join(__dirname,'./src/index.html'), // 指定模板页面,将来会根据指定的页面路径,去生成内存中的页面
filename : 'index.html' // 指定生成的页面的名称
})
当使用了html-webpack-plugin之后,我们不需要手动处理bundle.js路径了,因为这个插件,已经帮我们自动创建了一个合适的script标签,并且,引用了正确的路径
如果想要打包处理css文件,需要安装npm i style-loader css-loader -D
打开webpack.config.js配置文件,在里面新增一个配置节点module
,它是一个对象,在这个对象上,有一个rules
属性,这个属性是个数组,这个数组中,存放了所有第三方文件 匹配和处理规则
module : { // 这个节点,用于配置所有的第三方模块加载器
rules : [
// 所有第三发模块的匹配规则
{test: /\.css$/,use:['style-loader','css-loader']}, //配置处理.css文件的第三方loader规则
]
}
在main.js中导入css文件
import './css/index.css'
这样,我们的css文件就被打包一起导入了
loader配置处理less文件
安装less npm i less-loader -D
和 npm i less -D
打开webpack.config.js配置文件,在里面进行配置
module : { // 这个节点,用于配置所有的第三方模块加载器
rules : [
// 所有第三发模块的匹配规则
{test: /\.css$/,use:['style-loader','css-loader']}, //配置处理.css文件的第三方loader规则
{test: /\.less$/,use:['style-loader','css-loader','less-loader']}, //配置处理.css文件的第三方loader规则
]
}
在main.js中导入less文件
import './css/index.less'
默认情况下,webpacke无法处理css文件中的url地址,不管是图片还是字体库,只要是url地址都无法处理
安装url-loader和file-loader npm i url-loader file-loader -D
在webpack.config.js中进行配置
{test:/\.(jpg|png|gif|bmp|jpeg)$/,use:'url-loader?limit=1024&name=[hash:8]-[name].[ext]'} // 处理图片路径的loader,通过?传递参数,当图片小于1024kb的时候,以base64编码的方式加载,大于1024kb的时候以url的方式加载;图片的名字等于打包之前图片的名字前加上一个八位的hash且后缀名也相同
作用:处理高级的ES6语法
在webpack中,默认只能处理一部分ES6的新语法,一些更高级的ES6语法或者ES7语法,webpack是无法处理的,这时候就要借助于第三方的loader,把高级的语法转为低级的语法后,会把结果交给webpack去打包到bundle.js
通过bable可以帮我们将高级的语法转换为低级的语法
在webpack中,可以运行如下两套命令,安装两套包,去安装babel相关的loader功能:
第一套包
npm i babel-core babel-loader babel-plugin-transform-runtime -D
第二套包
npm i babel-preset-env babel-preset-stage-0 -D
在webpack的配置文件中,在moudle节点下的rules数组中,添加一个新的匹配规则
{test:/\.js$/,use:'babel-loader',exclude:/node_modules/} // 排除掉node——modules中的包
在项目根目录中,新建一个叫做.babelrc 的babel配置文件,这个配置文件属于JSON格式,所以在写.babelrc配置的时候,必须符合json语法规范:不能写注释,字符串必须用双引号
在.babelrc写如下配置:
{
"presets":["env","stage-0"],
"plugins":["transform-runtime"]
}
使用components 的话,是将组件放入id为app的容器内,使用render是把id为app的容器替换为指定的组件
<div id="app">
<login>login>
div>
<script>
var login = {
template : '这是登录组件
'
}
var vm = new Vue({
el : '#app',
render : function(createElements){ //createElements 是一个方法,调用它能把指定的组件模板渲染为html结构
return createElements(login); // 注意:这里的return的结果,会替换页面中el指定的那个容器
// 使用components 的话,是将组件放入id为app的容器内,使用render是把id为app的容器替换为指定的组件
}
});
script>
安装vue npm i vue -S
在main.js中导入vue
import Vue from 'vue'
注意:在webpack中,使用import Vue from ‘vue’ 导入的Vue构造函数,功能不完整,只提供了 runtime-only的方式,并没有提供像script标签导入vue那样的使用方式
解决办法:
方法一:在package.json配置文件中修改main的值"main":"dist/vue.js"
方法二:在导入时,指定vue的路径import Vue from '../node/node_modules/vue/dist/vue.js'
方法三:在webpack.config.js中,新增一个节点resolve,进行配置
resolve : {
alias : {
// 修改vue被导入时候的包的路径
'vue$':'vue/dist/vue.js'
}
}
在login.vue中
这是登录组件,使用.vue文件定义出来的
在main.js中
import Vue from 'vue'
import login from './login.vue'
var vm = new Vue({
el : '#app',
data : {
msg : '123'
},
render :function(createElements) {
// 在webpack中,如果想要通过vue,把一个组件放入页面中去展示,vm实例中的render函数可以实现
return createElements(login);
}
})
默认情况下webpack无法打包.vue文件,需要安装相关的loader
npm i vue-loader vue-template-compiler -D
在配置文件webpack.config.js中,新增loader配置对象
{test : '/\.vue$/',use : 'vue-loader'} // 处理 .vue文件的loader
使用exprot default 和 export 向外暴露成员
在.vue中
注意:export default 向外暴露的成员,可以使用任意的变量来接收
在一个模块中,export default 只允许向外暴露一次
在一个模块中,可以同时使用和export default 和 export 向外暴露成员
export var name : 'zs'
export var age : '23'
在接收时,
import {name,age} from 'xxx'
注意:使用export向外暴露的成员,只能使用{ }
的形式来接收,这种形式,叫做【按需导出】
注意:使用export导出的成员,必须严格按照导出时候的名称,来使用 { }
按需接收
可以使用 as
来取别名
import {name as name123} from 'xxx'
导包 npm install vue-router
如果在一个模块化工程中使用它,必须要通过Vue.use()
明确地安装路由功能
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
如果使用全局的script
标签,则无需手动安装
scoped:使style标签内的样式,只作用于该组件
<style scoped>style>
普通的style标签只支持普通的样式,如果要启用scss或less,需要为style标签元素,添加lang属性
<style lang="less">style>
这样,在组件中的style中,就可以写less了
导入 axios npm i axios -S
import Vue from 'vue'; //导入vue模块
import axios from 'axios'; //导入axios
axios.defaults.baseURL = 'http://www.xxxxx.cn'; //配置根域名
//Vue.prototype.$ajax = axios; //把axios挂载到Vue的原型上
安装vue npm i vue -S
在main.js中导入vue
import Vue from 'vue'
注意:在webpack中,使用import Vue from ‘vue’ 导入的Vue构造函数,功能不完整,只提供了 runtime-only的方式,并没有提供像script标签导入vue那样的使用方式
解决办法:
方法一:在package.json配置文件中修改main的值"main":"dist/vue.js"
方法二:在导入时,指定vue的路径import Vue from '../node/node_modules/vue/dist/vue.js'
方法三:在webpack.config.js中,新增一个节点resolve,进行配置
resolve : {
alias : {
// 修改vue被导入时候的包的路径
'vue$':'vue/dist/vue.js'
}
}
在login.vue中
这是登录组件,使用.vue文件定义出来的
在main.js中
import Vue from 'vue'
import login from './login.vue'
var vm = new Vue({
el : '#app',
data : {
msg : '123'
},
render :function(createElements) {
// 在webpack中,如果想要通过vue,把一个组件放入页面中去展示,vm实例中的render函数可以实现
return createElements(login);
}
})
默认情况下webpack无法打包.vue文件,需要安装相关的loader
npm i vue-loader vue-template-compiler -D
在配置文件webpack.config.js中,新增loader配置对象
{test : '/\.vue$/',use : 'vue-loader'} // 处理 .vue文件的loader
使用exprot default 和 export 向外暴露成员
在.vue中
注意:export default 向外暴露的成员,可以使用任意的变量来接收
在一个模块中,export default 只允许向外暴露一次
在一个模块中,可以同时使用和export default 和 export 向外暴露成员
export var name : 'zs'
export var age : '23'
在接收时,
import {name,age} from 'xxx'
注意:使用export向外暴露的成员,只能使用{ }
的形式来接收,这种形式,叫做【按需导出】
注意:使用export导出的成员,必须严格按照导出时候的名称,来使用 { }
按需接收
可以使用 as
来取别名
import {name as name123} from 'xxx'
导包 npm install vue-router
如果在一个模块化工程中使用它,必须要通过Vue.use()
明确地安装路由功能
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
如果使用全局的script
标签,则无需手动安装
scoped:使style标签内的样式,只作用于该组件
<style scoped>style>
普通的style标签只支持普通的样式,如果要启用scss或less,需要为style标签元素,添加lang属性
<style lang="less">style>
这样,在组件中的style中,就可以写less了
导入 axios npm i axios -S
import Vue from 'vue'; //导入vue模块
import axios from 'axios'; //导入axios
axios.defaults.baseURL = 'http://www.xxxxx.cn'; //配置根域名
//Vue.prototype.$ajax = axios; //把axios挂载到Vue的原型上
组件之间共享数据的方式
父向子传值:v-bind 属性绑定
子向父传值:v-on 事件绑定 或 this.$refs
兄弟组件之间数据共享:EventBus
Vuex是什么?
Vuex是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间的数据的共享
使用Vuex统一管理状态的好处:
什么样的数据适合存储到vuex中?
一般情况下,只有组件之间共享的数据,才有必要存储到vuex中,对于组件中私有的数据,依旧存储在组件自身的data中即可
安装vuex的依赖包 npm install vuex --save
导入vuex包
import Vuex from 'vuex'
Vue.use(Vuex)
创建store对象
const store = new Vuex.Store({
// state 中存放的就是全局共享的数据
state : {count : 0}
})
将stroe对象挂载到vue实例中
import store from '...'
new Vue({
el : '#app',
data : {},
router,
// 将创建的共享数据对象,挂载到Vue实例中
// 所有的组件,就可以直接从store中获取全局的数据了
store
})
安装vue-cli
npm install @vue/cli -g
使用vue ui
来创建一个项目
State 提供唯一的公共数据源,所有共享的数据都要统一放到Store的State中进行存储
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
export default new Vuex.Store({
state : {
// State 提供唯一的公共数据源,所有共享的数据都要统一放到Store的State中进行存储
count : 0
},
mutations :{},
actions : {}
})
组件中访问State中数据的第一种方式:
this.$store.state.全局数据名称
<h1>当前最新的count值为:{{$store.state.count}}h1>
第二种方式:
从vuex中按需导入mapState函数
通过刚才导入的mapState函数,将当前组件需要的全局数据,映射为当前组件的computed计算属性
import {mapState} from 'vuex'
export default {
data(){
return {
}
},
computed : {
...mapState(['count']) // ...为展开运算符,这样就拿到了全局数据 count
}
}
</script>
Mutation用于变更Store中的数据
组件通过调用Mutation中的函数来实现对全局数据的改变
export default new Vuex.Store({
state : {
// State 提供唯一的公共数据源,所有共享的数据都要统一放到Store的State中进行存储
count : 0
},
mutations :{
// 用mutation来操作数据,组件电泳mutations中的方法来操作数据
add(state){
state.count++
},
del(state){
state.count--
}
},
actions : {}
})
调用Mutation中的方法
this.$store.commit(‘函数名字’);
export default {
data(){
return {
}
},
methods : {
add(){
this.$store.commit('add'); // 调用mutation中的函数
}
}
}
Mutation传递参数
在Mutation中定义了方法
mutations :{
// 用mutation来操作数据,组件电泳mutations中的方法来操作数据
addN(state,step){ // 第二个是要传递的参数
state.count=state.count+step
}
},
组件中调用Mutation中方法时,传递参数
addn(){
this.$store.commit('addN',3); // 传递了一个参数 3
}
在组件中调用Mutation中函数的第二种方式
从vuex中按需导入mapMutations函数
通过刚才导入的mapMutations函数,将需要的mutations函数,映射为当前组件的methods方法
methods:{
...mapMutations(['del']),
deleteNum(){
this.del();
}
}
注意:在Mutations的函数中不能写异步的代码!!
Action用于处理异步任务
如果通过异步操作变更数据,必须通过Action,而不能使用Mutation,但是在Action中还是要通过触发Mutation的方式间接变更数据
actions : {
addAsync(context){
setTimeout(function(){ // 延时1秒执行add函数
context.commit('add')
},1000)
}
}
触发Action
methods : {
add(){
this.$store.dispatch('addAsync')
}
}
触发Action异步任务时传递函数
actions : {
addAsync(context,arg){
setTimeout(function(){ // 延时1秒执行add函数
context.commit('add',arg)
},1000)
}
}
触发Action
methods : {
add(){
this.$store.dispatch('addAsync',5)
}
}
触发Action函数的第二种方式
从vuex中按需导入mapActions 函数
import {mapActions} from 'vuex'
methods : {
...mapActions(['addAsync'])
}
Getter 用于对Store中的数据进行加工处理形成新的数据
定义Getter
new Vue.Store({
state: {
count = 0
},
getters : {
showNum : state => {
return '当前最新的数量是【'+state.count+'】'
}
}
})
使用getter的第一种方式:
this.$store.getters.名称
this.$store.getters.showNum
使用getter的第二种方式:
import {mapGetters} from 'vuex'
computed : {
...mapGetters(['showNum'])
}