分类 学习笔记 下的文章

Vue 学习笔记

初学Vue,存在不严谨内容欢迎批评指正。本文持续更新中...

Vue官方文档

1.插值表达式、v-text与v-html

以下 dataname 均为Vue中data对象的属性。
  • 插值表达式形如{{ dataname }} 前后可以添加字符串例如:你好,{{ dataname }}!

    • 闪烁问题可以使用v-cloak解决。需要使用属性选择器将其隐藏:

      <style>
      [v-cloak]{
          display: none;
      }
      </style>
  • v-text指令:<span v-text="dataname">。不存在闪烁问题,但是标签内数据会被覆盖
  • v-html指令:<div v-html="dataname"></div>。此处的dataname会被解析成html代码

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>&emsp;<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>&emsp;<button @click="$store.commit('reduceAge')">减少年龄</button>&emsp;<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
})