Vue 学习笔记
初学Vue,存在不严谨内容欢迎批评指正。本文持续更新中...
Vue官方文档
1.插值表达式、v-text与v-html
以下 dataname 均为Vue中data对象的属性。
2.v-bind
常被用于绑定属性,例如:<input type="button" value="Button" v-bind:title="dataname">
。
dataname可以是Vue中data对象的属性,也可以是js表达式。v-bind也可以简写成“:”,例如:<input type="button" value="Button" :title="'我是' + dataname">
。
3.v-on
用于绑定事件,例如:<input type="button" value="Button" v-on:click="methodsname">
。
methodsname 是Vue中methods对象中的函数名。定义函数:
...
methods:{
methodsname: function(){
alert("Hello!")
}
}
...
v-on可以缩写为“@”,例如:<input type="button" value="Button" @click="methodsname">
。
v-on的修饰符
在事件后面添加,允许串联,例如:<input type="button" value="Button" @click.stop.once="methodsname">
。
- .stop 阻止冒泡,防止触发外层相同的事件
- .prevent 阻止默认行为(例如防止a标签跳转)
- .capture 使用捕获机制触发事件,首先触发外层div事件(需将此修饰符添加到外层div上)
- .self 自身触发事件,防止通过冒泡或捕获触发事件
- .once 只触发一次事件处理函数
注意.stop与.self的区别,.stop阻止了全部的冒泡,.self只阻止了所在对象上的冒泡。
4.v-model
用于表单元素的双向数据绑定,例如:<input type="test" v-model="dataname">
。常见表单元素:
- input
- select
- checkbox
- textarea
- ...
5.Vue使用样式
设置class类样式
<style>
.red{
color: #f00;
}
.thin{
font-weight: 100;
}
.italic{
font-style: italic;
}
.active{
letter-spacing: 0.5em;
}.
</style>
- 数组:
<h1 :class="['red','thin']">这是一个示例标签。</h1>
- 数组中使用三元表达式:
<h1 :class="['red','thin',isactive?'active':'']">这是一个示例标签。</h1>
- 数组中嵌套对象:
<h1 :class="['red','thin',{'active':isactive}]">这是一个示例标签。</h1>
- 直接使用对象:
<h1 :class="{red:true,italic:true,active:true,thin:true}">这是一个示例标签。</h1>
使用内联样式
- 直接使用对象:
<h2 :style="{color:'red',font-size:'40px'}">这是一个示例标签。</h2>
- 在data中定义样式对象
h2StyleObj:{color:'red',font-size:'40px'}
,然后绑定到style属性:<h2 :style="h2StyleObj">这是一个示例标签。</h2>
,这里的style也可以是数组形式:<h2 :style="[h2StyleObj,h2StyleObj2]">这是一个示例标签。</h2>
6.v-for
- 基本用法:
<p v-for="item in dataname">{{ item }}</p>
,这里的dataname是数组名 - 遍历数组:
<p v-for="(item,i) in dataname">第{{ i }}个元素是{{ item }}</p>
,这里i为索引 - 遍历对象:
<p v-for="(val,key,i) in dataname">第{{ i }}个Key是{{ key }},对应的值是{{ val }}</p>
- 迭代数字:
<p v-for="count in 10">这是第{{ count }}次循环。</p>
,注意count从1开始
注意:从2.2.0+版本以后,使用v-for必须绑定key属性,这里的key必须是唯一的string或number类型的,例如:<p v-for="item in dataname" :key="item.id"><input type="checkbox">{{ item.name }}</p>
。这里的item是一个对象。
7.v-if与v-show
- v-if:
<p v-if="isshow"></p>
,只有当isshow为真时才展示这个p标签 - v-show:用法同v-if,但不会进行Dom删除的操作,只是添加了display:none的样式
v-if 有较高的切换性能消耗,建议不频繁切换展示或隐藏时使用;v-show有较高的初始渲染消耗,建议频繁切换展示或隐藏时使用。
8.过滤器
只能用于插值表达式和v-bind表达式中。
这里示例一个过滤器,将管道前字符串中的ABC替换为DEF,使用方法:{{ msg | msgFormat('DEF') }}
。
全局过滤器
// 参数1是过滤器名
// 参数2是函数
Vue.filter('msgFormat',function(msg,str){
return msg.replace(/ABC/g,str)
})
私有过滤器
...
filters:{
msgFormat:function(msg,str){
return msg.replace(/ABC/g,str)
}
}
...
函数中第一个参数永远是管道前的字符串。过滤器可以传递多个参数,也可以多次调用,例如:{{ msg | msgFormat1 | msgFormat2 }}
。
过滤器存在就近原则,同名私有过滤器优先调用。
9.按键修饰符
用于绑定特定按键的事件,例如:<input type="text" v-model="dataname" @keyup.enter="funname">
。
全部按键别名:
- .enter
- .tab
- .delete
- .esc
- .space
- .up
- .down
- .left
- .right
- KeyCode
可以自定义按键码:Vue.config.keyCodes.f1 = 112
,这样在键盘事件后可以直接使用.f1来绑定按键。
10.自定义指令
这里示例一个获取焦点的自定义指令,使用方法:<input type="text" v-focus>
。
全局自定义指令
//参数1是指令名
//参数2是对象
Vue.directive('focus',{
inserted:function(el){
el.focus()
}
})
私有自定义指令
...
directives:{
'focus':{
inserted:function(el){
el.focus()
}
}
}
...
每个函数中第一个参数永远是el,表示被绑定了指令的元素。可以绑定的事件有:
- bind:当指令绑定到元素身上时会触发这个事件,只触发1次
- inserted:当元素插入到DOM中时会触发这个事件,只触发1次
- updated:当VNode更新的时候会触发这个事件,可能会触发多次
第二个参数是binding可以获取自定义指令的一些属性:
- name:指令名,不包含v-前缀
- value:指令的绑定值,例如:
v-color="1+1"
则value为2 - oldValue:指定绑定的前一个值
- expression:指令绑定的值的字符串,例如:
v-color="1+1"
则expression为字符串形式的“1+1” - arg:指令的参数,例如:
v-color:red
- modifiers:包含修饰符的对象,例如:
v-color.front.back
,则modifiers对象为{ front:true,back:true }
这个参数的内容一般为只读属性,不建议修改它们的值。
11.生命周期
创建阶段:
- beforeCreate:实例被完全创建之前会执行
- created:实例被完全创建之后会执行,最早要在这里操作data里的数据或methods里的函数
- beforeMount:模板已经编译完成,但尚未渲染至页面中时会执行
- Mounted:内存中的模板已挂在完成后执行,最早要在这里操作DOM节点
运行阶段:
这里的触发条件是data数据被改变时。
- beforeUpdate:新的data数据被重新渲染至页面之前执行
- updated:新的data数据被重新渲染至页面之后执行
销毁阶段:
- beforeDestroy:实例的data与methods等尚处于可用状态并即将销毁时执行
- destroy:实例被完全销毁后执行,此时的data与methods等均已被销毁
12.使用vue-resource实现数据请求
除了vue-resource之外还可以使用第三方包axios实现数据请求。
http数据请求文档
这里示例一个post请求:
...
postTest:function(){
this.$http.post('http://vue.studyit.io/api/post',{},{ emulateJSON:true }).then(result=>{
//数据请求成功
},result=>{
//数据请求失败
})
}
...
发送post请求时建议将第三个参数设置为{emulateJSON:true}
。
13.Vue中的动画
基本使用
<style>
.v-enter,
.v-leave-to{
opacity: 0;
transform: translateX(100px);
}
.v-enter-active,
.v-leave-active{
transition: all 0.8s ease;
}
/* 这两个类是固定写法,用于普通位移时的动画 */
.v-move{
transition: all 0.6s ease;
}
.v-leave-active{
position: absolute;
}
</style>
在使用时,需要用<transition>
标签将需要播放动画的元素包裹起来,
如果过渡元素是通过v-for渲染出来的时候,需要使用<transition-group>
来包裹,同时必须为每个元素绑定key属性。
这里示例一个在ul列表中渲染动画:
<ul>
<transition-group appear tag="ul">
<li></li>
<li></li>
</transition-group>
</ul>
其中appear可以让元素首次渲染时播放动画,tag属性可以指定transition-group渲染时的标签。
自定义前缀
<style>
.my-enter,
.my-leave-to{
opacity: 0;
transform: translateY(100px);
}
.my-enter-active,
.my-leave-active{
transition: all 0.8s ease;
}
</style>
使用方法:<transition name="my"><!-- 需要播放动画的元素 --></transition>
。
第三方动画库使用方法
这里示例一个animate.css的使用方法:<transition enter-active-class="animated bounceIn" leave-active-class="animated bounceOut" :duration="400"><!-- 需要播放动画的元素 --></transition>
,使用duretion可以统一设置动画播放的时长(毫秒),也可以分开设置时长 ,例如::duration="{ enter:200,leave:400 }"
。
动画生命周期
使用动画钩子函数可以细化动画过程,这里示例一个动画开始之后的样式:<transition @enter="enter"></transition>
methods:{
//参数1是el,表示执行动画的DOM元素
//参数2可以是done,它是一个函数,实际上它就是afterEnter函数的引用
enter:function(el){
//下面这句会强制刷新动画
el.offsetWidth
}
}
可以使用的动画钩子函数:
- before-enter="beforeEnter",动画入场之前的样式
- enter="enter",动画结束时的样式
- after-enter="afterEnter",动画结束之后的样式
- enter-cancelled="enterCancelled"
- before-leave="beforeLeave"
- leave="leave"
- after-leave="afterLeave"
- leave-cancelled="leaveCancelled"
14.Vue组件
组件化是为了方便前端模块的重用。
全局组件
//参数1是组件名
//参数2是使用extend创建的模板对象
Vue.component('myCom1',Vue.extend({
template:'<h3>这是使用Vue.extend创建的组件。</h3>'
}))
//参数2也可以直接传递一个模板对象
Vue.component('myCom2',{
template:'<h3>这是使用Vue.conponent创建的组件。</h3>'
})
私有组件
...
components:{
myCom3:{
template:'<h3>这是一个私有组件。</h3>'
}
}
...
组件的template属性指向的模板内容必须是有且只有唯一的根元素。
使用方法:<my-com1></my-com1>
,注意驼峰命名需要在驼峰处加“-”,并把大写转小写。
template属性也可以传递一个id,例如:
Vue.component('myCom3',{
template:'#tmpl'
})
它在使用时需要在Vue所控制的el外用<template>
标签创建模板结构,例如:
<template id="tmpl">
<h3>这是使用template创建的组件。</h3>
</template>
组件中的data与methods
组件中的data必须是一个返回值为对象的函数,这样能够保证每个组件之间的数据互不影响。
Vue.component('myCom4',{
template:'<h3>这是使用Vue.conponent创建的组件。</h3>',
data:function(){
reutrn {
msg:'这是组件中的data数据'
}
},
methods:{
showMsg:function(){
console.log(this.msg)
}
}
})
除了data的定义方式外,其他的与Vue对象内的data与methods使用方式一样。
父子组件之间的传值
可以通过属性绑定的形式传值,例如:<my-com4 v-bind:parentmsg="msg"></my-com4>
。
在子组件中使用时,需要在props数组中定义一下,例如:
...
data:{
msg = "这是父组件的msg"
}
...
components:{
myCom4:{
template:'<h3>这是一个子组件,父组件的数据是“{{ parentmsg }}。”</h3>',
props:['parentmsg']
}
}
...
props内所定义的数据不建议被修改。
函数可以使用v-on传递,例如:<my-com5 v-on:parentfunc="func"></my-com5>
。
父组件的methods中要定义func方法,在子组件中使用时调用this.$emit('parentfunc')
来执行。$emit从第二个参数开始可以向父组件中的方法内传递参数。
通过$refs可以获取子组件的数据,例如:
...
components:{
myCom6:{
template:'',
data:function(){
return {
msg:'我是子组件的msg'
}
},
methods{
showMsg:function(){
console.log(this.msg)
}
}
}
}
...
子组件需要添加ref属性,例如:<my-com6 ref="com6"></my-com6>
在父组件中可以调用this.$refs.com6.msg
获取msg,也可以直接执行方法this.$refs.com6.showMsg()
。
此外,$refs也可以用于获取Dom节点,例如:<h3 ref="myh3">你好,我是h3</h3>
,可以调用this.$refs.myh3.innerText
获取到h3内的的内容。
15.Vue-Router
Vue-Router官方文档
路由用于分发和管理前端页面。
var login = {
template:'<h2>这是一个登陆组件</h2>'
}
var register = {
template:'<h2>这是一个注册组件</h2>'
}
var routerObj = new VueRouter({
//route代表路由匹配规则
//routes是一个路由匹配规则的数组
//每一条路由规则都是一个对象,它身上有两个属性
//属性1是path,表示监听的路由地址
//属性2是component,它必须是一个组件的模板对象,表示如果匹配到了属性1中的path,则展示此属性对应的组件
routes:[
//使用redirect可以将默认页面强制切换到指定path
{ path:'/',redirect:'/login' },
{ path:'/login',component:login },
{ path:'/register',component:register }
],
//配置自己的激活类
linkActiveClass:'myactiveclass'
})
var app = new Vue({
el:'#app',
data:{},
methods:{},
//将路由规则对象注册到vm实例上用于监听URL地址变化,然后展示对应的组件
router:routerObj
})
使用时需要添加容器标签:<router-view></router-view>
,它用于展示路由匹配到的组件。
使用路由进行页面切换时可以使用<a href="#/login"></a>
,但是官方更加推荐我们使用所提供的标签:
<router-link to="/login">登录</router-link>
<router-link to="/register" tag="span">注册</router-link>
to属性指向展示的模板,tag属性用于修改标签,默认router-link渲染为a标签。
在页面切换时,激活的router-link会携带.router-link-active类,可以为它添加样式,用于高亮显示,也可以在VueRouter对象中配置自己的激活类。
路由规则中的参数
使用查询字符串可以给路由传递参数:<router-link to="/login?id=10">登录</router-link>
。
使用路由对象中的query属性获取参数:
var login = {
template:'<h2>这是一个登陆组件,传递过来的id是{{ $route.query.id }}</h2>',
created(){
console.log(this.$route.query)
}
}
也可以在router中传递参数:<router-link to="/login/10">登录</router-link>
。
使用路由对象中的params属性获取参数:
var login = {
template:'<h2>这是一个登陆组件,传递过来的id是{{ $route.params.id }}</h2>'
}
var router = new VueRouter({
routes:[
{ path:'/login/:id',component:login }
]
})
var app = new Vue({
el:'#app',
data:{},
methods:{},
//属性名与属性值一样可以简写
router
})
路由嵌套
var router = new VueRouter({
routes:[
{
path:'/account',
component:account,
children:[
//子路由path前面不带“/”
{ path:'login',component:login }
]
}
]
})
命名视图
...
<router-view></router-view>
<router-view name="left"></router-view>
<router-view name="right"></router-view>
...
<script type="text/javascript">
var router = new VueRouter({
routes:[
{ path:'/account',
components:{
'default':header,
'left':leftBox,
'right':mainBox
}
}
]
})
</script>
...
16.watch属性与computed属性
watch属性可以监听Vue实例中data数据的变化并执行相应的函数。
watch:{
//参数1是改变后的值
//参数2是改变前的值
'inputValue':function(newVal,oldVal){
//使用this输出变化后的值
console.log(this.inputValue)
//使用参数输出变化后的值
console.log(newVal)
}
}
它也可以用于监听路由地址的变化:
watch:{
'$route.path':function(newVal,oldVal){
console.log('当前路由地址是' + newVal)
}
}
computed属性是一个计算属性,它的本质是一个方法,但不会将它以方法形式调用。
只要这个属性中用到的任何数据发生了变化,就会触发这里的方法以重新计算值。
计算的最终结果会缓存起来,如果使用到的数据未发生变化,那么就会直接调用缓存起来的值而不会重新计算。
computed:{
'valueC':function(){
return this.valueA + this.valueB
}
}
17.Vuex
Vuex官方文档
Vuex用于管理数据状态。
这里示例一个在组件中获取store中状态的例子,使用了上文所学的computed方法。
<template id="myvuex">
<div>
<h3>这是一个Vuex的例子</h3>
<ul>
<li v-for="user in users">
<span>姓名:{{ user.name }},年龄:{{ user.age }}</span>
</li>
</ul>
</div>
</template>
var storeObj = new Vuex.Store({
state:{
users:[
{name:"李白",age:30},
{name:"白居易",age:32},
{name:"陶渊明",age:44}
]
}
});
var app = new Vue({
el:'#app',
data:{},
methods:{},
components:{
myCom:{
template:'#myvuex',
computed:{
users(){
return this.$store.state.users;
}
}
}
},
store:stroeObj
})
Getters
Getters用于获取(也可以修改)state里的状态,类似computed属性,上述例子可改为:
<template id="myvuex">
<div>
<h3>这是一个Vuex的例子</h3>
<ul>
<li v-for="user in fullusers">
<span>姓名:{{ user.name }},年龄:{{ user.age }}</span>
</li>
</ul>
</div>
</template>
var storeObj = new Vuex.Store({
state:{
users:[
{name:"小柱",age:18},
{name:"铁蛋",age:32},
{name:"大锤",age:44}
]
},
getters:{
fullusers:(state) =>{
var fullUsers = state.users.map(user =>{
return{
name:"王"+user.name,
age:user.age+"岁"
}
});
return fullUsers;
}
}
});
var app = new Vue({
el:'#app',
data:{},
methods:{},
components:{
myCom:{
template:'#myvuex',
computed:{
'users':function(){
return this.$store.state.users;
},
'fullusers':function(){
return this.$store.getters.fullusers;
},
}
}
},
store:storeObj
})
Mutations
Mutations用于修改state里的状态,类似methods属性。
执行Mutations时要调用store对象下的commit方法。
上述例子可改为:
<template id="myvuex">
<div>
<h3>这是一个Vuex的例子</h3>
<button @click="$store.commit('addAge')">增加年龄</button> <button @click="$store.commit('reduceAge')">减少年龄</button>
<ul>
<li v-for="user in users">
<span>姓名:{{ user.name }},年龄:{{ user.age }}</span>
</li>
</ul>
</div>
</template>
var storeObj = new Vuex.Store({
state:{
users:[
{name:"小柱",age:18},
{name:"铁蛋",age:32},
{name:"大锤",age:44}
]
},
mutations:{
addAge:function(state){
state.users.forEach(user =>{
user.age++;
})
},
reduceAge:function(state){
state.users.forEach(user =>{
user.age--;
})
}
}
});
var app = new Vue({
el:'#app',
data:{},
methods:{},
components:{
myCom:{
template:'#myvuex',
computed:{
'users':function(){
return this.$store.state.users;
}
}
}
},
store:storeObj
})
commit方法也可以传递参数,例如:
<button @click="$store.commit('addAge',10)">增加年龄</button>
addAge:function(state,n){
state.users.forEach(user =>{
user.age += n;
})
}
Actions
Actions类似于Mutations,但不同的是Actions主要提交commit来改变状态而非直接修改状态。
Actions允许异步而Mutations不允许异步。
触发Actions需要执行store对象下的dispatch方法。
上述例子可改为:
<template id="myvuex">
<div>
<h3>这是一个Vuex的例子</h3>
<button @click="$store.commit('addAge')">增加年龄</button> <button @click="$store.commit('reduceAge')">减少年龄</button> <button @click="$store.dispatch('addAge')">+1s</button>
<ul>
<li v-for="user in users">
<span>姓名:{{ user.name }},年龄:{{ user.age }}</span>
</li>
</ul>
</div>
</template>
var storeObj = new Vuex.Store({
state:{
users:[
{name:"小柱",age:18},
{name:"铁蛋",age:32},
{name:"大锤",age:44}
]
},
mutations:{
addAge:function(state){
state.users.forEach(user =>{
user.age++;
})
},
reduceAge:function(state){
state.users.forEach(user =>{
user.age--;
})
}
},
actions:{
addAge:function(state){
//示例异步,等待1秒才执行
setTimeout(() => {
state.commit('addAge')
}, 1000)
}
}
});
var app = new Vue({
el:'#app',
data:{},
methods:{},
components:{
myCom:{
template:'#myvuex',
computed:{
'users':function(){
return this.$store.state.users;
}
}
}
},
store:storeObj
})