# Class 与 Style 绑定

# 绑定 Class

# 对象语法

我们可以传给 v-bind:class 一个对象,以动态地切换 class

<div v-bind:class="{ active: isActive }"></div>

上面的active类名,而isActive是一个变量,它有布尔特性

什么布尔特性?

  1. ''隐式解析为false
  2. 0隐式解析为false
  3. null隐式解析为false
  4. false
  5. undefined隐式解析为false
  6. NaN隐式解析为false
  7. 比较运算也产生布尔值

综合例子

<style>
button.active{
  color: red;  
}
</style>
<div id="root">

    <button 
    v-for="p in 5"
    v-bind:class="{active:p==page}"
    v-on:click="goPage(p)"
    >{{p}}</button>

</div>

<script>
var root = new Vue({
    el:'#root',
    data: {
        page: 3
    },
    methods:{
        goPage(p){
            this.page = p;
        }
    }
})
</script>

综合例子2

<style>
div.box{
  width: 220px;
  height: 500px;
  background-color: #000;
  transition: all .3s ease-in;
}
div.box.active{
    width: 0;
    transition: all .3s ease-out;
}
button{
    position: fixed;
    right: 20px;
    top: 20px;
}
</style>
<div id="root">
    <div class="box" :class="{active:opened}"></div>
    <button v-on:click="opened = !opened">切换导航</button>
</div>

<script>
var root = new Vue({
    el:'#root',
    data: {
        opened: false
    }
})
</script>

# 绑定 Style 样式

# 对象语法

<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>

综合例子

<div id="root">

    <h4 :style="h4Style">标题</h4>

    <input type="number" v-model="size">

    <select v-model="font">
        <option value="">请选择</option>
        <option value="华文行楷">华文行楷</option>
        <option value="方正舒体">方正舒体</option>
    </select>

</div>

<script>
var root = new Vue({
    el:'#root',
    data: {
        font: '',
        size: 24
    },
    computed: {
        h4Style(){
            return {fontSize: this.size+'px',fontFamily: this.font};
        }
    }
})
</script>

拖拽效果演示

<style>
.box{
    position: fixed;
    background-color: red;  
}
</style>

<div id="root">

    <div 
    class="box"
    :style="boxStyle"
    @mousedown = "drag"
    ></div>

</div>

<script>
var root = new Vue({
    el:'#root',
    data: {
        width: 100,
        height: 100,
        left: 20,
        top: 20
    },
    computed: {
        boxStyle(){
            return {
                width: this.width+'px',
                height: this.height+'px',
                left: this.left+'px',
                top: this.top+'px'
            }
        }
    },
    methods:{
        drag(e){
            var startX = e.clientX;
            var startY = e.clientY;
            var left = this.left;
            var top = this.top;
            var maxLeft = window.innerWidth - this.width;
            var maxTop = window.innerHeight - this.height;
            document.onmousemove = function(e){
                e.preventDefault();
                var distX =  left + (e.clientX - startX);
                var distY =  top + (e.clientY - startY);

                if(distX<=0)distX=0;
                if(distY<=0)distY=0;

                if(distX>=maxLeft)distX=maxLeft;
                if(distY>=maxTop)distY=maxTop;

                this.left = distX;
                this.top = distY;
            }.bind(this);
            document.onmouseup = function(){
                document.onmousemove = null;
                document.onmouseup = null;
            }
        }  
    }
})
</script>

滑块效果演示

<style>
.range{
    position: relative;
    background-color: #ccc;
    overflow: hidden;
}
.range i,
.range b{
    display: block;
}
.range b{
    height: 100%;
    background-color: green;
}
.range i{
    position: absolute;
    height: 100%;
    background-color: black;
}
</style>
<div id="root">

    <div class="range" :style="rangeStyle">
        <i :style="iStyle" @mousedown="drag"></i>
        <b :style="bStyle"></b>
    </div>

</div>

<script src="js/vue.js"></script>
<script>
var root = new Vue({
    el:'#root',
    data: {
        radius: false,
        rWidth: 800,
        rHeight: 100,
        iWidth: 100,
        left: 0
    },
    computed: {
        rangeStyle(){
            return {
                borderRadius:  this.radius && (this.rHeight/2 + 'px'),
                width: this.rWidth+'px',
                height: this.rHeight+'px',
            }
        },
        iStyle(){
            return {
                borderRadius:  this.radius && '50%',
                width: this.iWidth+'px',
                left: this.left+'px'
            }
        },
        bStyle(){
            return {
                width: this.left+(this.iWidth/2)+'px'
            }
        }
    },
    methods:{
        drag(e){
            var startX = e.clientX;
            var left = this.left;
            var maxLeft = this.rWidth - this.iWidth;
            document.onmousemove = function(e){
                var _left = left + (e.clientX - startX);
                if(_left<=0)_left=0;
                if(_left>=maxLeft)_left=maxLeft;

                this.left = _left;
            }.bind(this)

            document.onmouseup = function(){
                document.onmousemove = null;
                document.onmouseup = null;
            }
        }
    }

})
</script>

# 条件渲染

<div id="root">
    <h2 v-if="visible">标题2</h2>
    <button @click="visible = !visible">显隐</button>
</div>

<script>
var root = new Vue({
    el:'#root',
    data:{
        visible: false
    }
})
</script>

# v-if 和 v-show的区别

v-if会重建节点,它是惰性的,也就是说如果条件为假,那么它什么也不做,不会渲染节点。

v-show无论条件真或假,它都会渲染节点。

一般来说,v-if性能开销大一点,v-show性能开销少一些。

<div id="root">
    <h2 v-if="visible">标题v-if</h2>
    <h2 v-show="visible">标题v-show</h2>
    <button @click="visible = !visible">显隐</button>
</div>

<script>
var root = new Vue({
    el:'#root',
    data:{
        visible: false
    }
})
</script>

# v-else 否则

否则语句,注意不需要条件

v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别。

# v-else-if 否则如果

否则如果

类似于 v-elsev-else-if 也必须紧跟在带 v-if 或者 v-else-if 的元素之后。

# template 标签在条件语句中的应用

template标签不会被浏览器解析出来,它在v-ifv-for中很实用。

<div id="root">
    <template v-if="num==0">
        <h2>标题1</h2>
        <p>段落1</p>
    </template>
    <template v-if="num==1">
        <h2>标题2</h2>
        <p>段落2</p>
    </template>
</div>
<script>
var root = new Vue({
    el:'#root',
    data:{
        num: 0
    }
})
</script>

# key 特性

Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做使 Vue 变得非常快。

但这样也不总是符合实际需求,所以 Vue 为你提供了一种方式来表达“这两个元素是完全独立的,不要复用它们,那就是定义key

<div id="root">

    <button @click="type='email'">邮箱</button>
    <button @click="type='mobile'">手机</button> <br><br>

    <div v-if="type=='email'">
        <label>邮箱登录</label>
        <input type="text" placeholder="请输入邮箱" key="emial">
    </div>

    <div v-if="type=='mobile'">
        <label>手机登录</label>
        <input type="text" placeholder="请输入手机" key="mobile">
    </div>

</div>

<script>
var root = new Vue({
    el:'#root',
    data:{
        type: 'email'
    }
})
</script>

# 循环语句

# 循环数字

循环从1开始计数,注意不支持小数步进

<div id="root">
    <button v-for="p in 5">{{p}}</button>
</div>

<script>
var root = new Vue({
    el:'#root'
})
</script>

# 循环数组

<div id="root">
    <ul>
        <li v-for="item in ['苹果','香蕉']">{{item}}</li>
    </ul>
</div>

<script>
var root = new Vue({
    el:'#root'
})
</script>

上面的代码让模板变得过重,难于阅读,应该把数组提取到data中去

<div id="root">
    <ul>
        <li v-for="item in shuiguo">{{item}}</li>
    </ul>
</div>

<script>
var root = new Vue({
    el:'#root',
    data: {
        shuiguo: ['苹果','香蕉']
    }
})
</script>

# 如何拿到数组的索引值

<div id="root">
    <ul>
        <li v-for="item,index in shuiguo">
            {{index}} - {{item}}
        </li>
    </ul>
</div>

<script>
var root = new Vue({
    el:'#root',
    data: {
        shuiguo: ['苹果','香蕉']
    }
})
</script>

一个非常典型的循环数据示例

<div id="root">
    <ul>
        <li v-for="item in navs">
            <a :href="item.url">{{item.title}}</a>
        </li>
    </ul>
</div>

<script>
var root = new Vue({
    el:'#root',
    data: {
        navs: [
            { id:1, title:'首页', url: 'index.html'},
            { id:2, title:'关于我们', url: 'about.html'},
            { id:3, title:'联系我们', url: 'contact.html'}
        ]
    }
})
</script>

# 循环对象

<div id="root">
    <p v-for="val,key,index in person">
        {{index}} - {{key}} - {{val}}
    </p>
</div>
<script>
var root = new Vue({
    el:'#root',
    data: {
        person: {
            name: '李四',
            age: 33,
            habby: '骑行'
        }
    }
})
</script>

# template在循环中的应用

<div id="root">
    <template v-for="item in person">
        <h2>{{item.name}}</h2>
        <p>
            年龄:{{item.age}}<br>
            爱好:{{item.habby}}
        </p>
    </template>
</div>
<script>
var root = new Vue({
    el:'#root',
    data: {
        person: [
            {
                name: '张三',
                age: 28,
                habby: '唱歌'
            },
            {
                name: '李四',
                age: 33,
                habby: '骑行'
            }
        ]
    }
})
</script>

# 数组更新检测

# 数组变异的方法有那些

  1. push 尾部追加,返回数组长度。
  2. unshift 开头追加,返回数组长度。
  3. pop 删除尾部成员,返回被删除的成员。
  4. shift 删除头部成员,返回被删除的成员。
  5. sort 排序,返回排序后的数组。
  6. splice增删改数组管理
  7. reverse 反转,返回改变后的数组。

# 数组非变异的方法有那些

  1. concat 连接数组,返回新数组。
  2. slice 切割数组,切割出新数组。
  3. map 映射数组,映射出新数组。
  4. filter 筛选数组,筛选出新数组。

# 事件处理

<div id="root">
    <button v-on:click="count++">❤ {{count}}</button>
</div>

<script>
var root = new Vue({
    el:'#root',
    data:{
        count: 1
    }
})

</script>

# html5本地存储

# 应用场景

  1. 购物车
  2. 浏览记录
  3. 记住密码或者用户名
  4. 保存登录令牌token
  5. 离线缓存数据

# sessionStorage 会话存储

指页面打开的时候数据都在,一旦页面关闭,数据清除。

# sessionStorage.setItem 设置存储
sessionStorage.setItem('存储名','存储值');
# sessionStorage.getItem 获取已经存储的值
sessionStorage.getItem('存储名');
# sessionStorage.removeItem 移除已经存储的值
sessionStorage.removeItem('存储名');
# sessionStorage.clear 清空所有的值
sessionStorage.clear();

# localStorage 会话存储

本地永久存储,也就是说除非你人为手动去清除,一般它都在。

# localStorage.setItem 设置存储
localStorage.setItem('存储名','存储值');
# localStorage.getItem 获取已经存储的值
localStorage.getItem('存储名');
# localStorage.removeItem 移除已经存储的值
localStorage.removeItem('存储名');
# localStorage.clear 清空所有的值
localStorage.clear();

综合示例

<div id="root">
    <button @click="add()">添加</button>
    <button @click="clear()">清空</button>
    <ul>
        <li v-for="item,index in list">
            {{item.name}} ---- {{item.age}} <button @click="del(index)">移除</button>
        </li>
    </ul>
</div>

<script>
var list = localStorage.getItem('list');
var root = new Vue({
    el:'#root',
    data:{
        list: list ? JSON.parse(list):[]
    },
    methods:{
        add(){
            var name = prompt('请输入商品!');
            var age = prompt('请输入价格!');
            this.list.push({name,age});
        },
        del(index){
            // alert(index)
            this.list.splice(index,1);
        },
        clear(){
            this.list = [];
        }
    },
    updated(){
        //注意如果是对象的话,要转成字符串,不然会出问题
        var str = JSON.stringify( this.list );
        localStorage.setItem('list', str );
    }
})

</script>

# 事件修饰符

# once 只触发一次

<div id="root">
    <button v-on:click.once="danji">按钮</button>
</div>
<script>
var root = new Vue({
    el:'#root',
    methods:{
        danji(){
            alert('只能弹出一次哦!');
        }
    }
})
</script>

# capture 使用捕获模式

<div id="root">

    <button @click.capture="dj1">
        <b @click="dj2">按钮</b>
    </button>
</div>

<script>
var root = new Vue({
    el:'#root',
    methods:{
        dj1(){
            console.log('btn');
        },
        dj2(){
            console.log('b');
        }
    }
})
</script>

# self 只在当前元素触发

<div id="root">

    <button >
        <b @click.self="dj1">按钮</b>
    </button>
</div>

<script>
var root = new Vue({
    el:'#root',
    methods:{
        dj1(){
            console.log('btn');
        }
    }
})
</script>

# 按键修饰符

  • enter:回车键
  • tab:换行键
<div id="root">
    <input type="text" ref="msg" @keyup.enter="submit">
</div>

<script>
var clipboard = new Clipboard('#btn');
var root = new Vue({
    el:'#root',
    methods:{
        submit(){
            this.$refs.msg.select();
        }
    }
})
</script>