Vue基本api

257 阅读5分钟

插值表达

  • {{msg}}
  • v-bind / :
  • Vue 实例内通过 this.msg 获取
<div id="app">
    <!-- 文本 -->
    <div>{{msg}}</div>

    <!-- attribute -->
    <!-- 指令 v-bind -->
    <div v-bind:test="test">{{msg}}</div>
    <!-- 简写 : -->
    <div :test="test">{{msg}}</div>

    <!-- 表达式 -->
    <!-- 运算 -->
    <div :test="test+'123123'">{{msg+"123123"}}</div>
    <!-- 三目运算 -->
    <div :test="true?test:''">{{true?msg:""}}</div>
</div>
const app = new Vue({
    el: "#app",
    data: {
        msg: "hello world",
        test: "vue"
    }
});

事件处理

  • v-on:click / @click 添加事件
  • methods 储存事件
  • .once 修饰符 只执行一次
<div id="app">
    <!-- 指令 v-on:click -->
    <button v-on:click="handleClick">按钮</button>
    <!-- 简写 @click -->
    <button @click="handleClick">按钮</button>

    <!-- 传参 -->
    <button @click="handleOptions(1, $event)">按钮</button>

    <!-- .once -->
    <button @click.once="handleOnce">按钮</button>
</div>
const app = new Vue({
    el: '#app',
    methods: {
        // e 对应 MouseEvent
        handleClick(e) {
            console.log(e);
        },
        handleOptions(num, e) {
            console.log(num, e)
        },
        handleOnce() {
            console.log("只生效一次")
        }
    }
});

计算属性

  • 为了解决 {{msg + "123" + "456" + "789"}} 表达式繁琐,破坏可读性

  • components

  • computed 和 methods 区别是什么?

    1. 更清晰的表达

    2. 缓存

    • 以下呆码 reverseMsg1 、 reverseMsg2 都可实现 reverseMsg 效果
    • 所依赖响应式参数 msg 改变时才发生改变
    • 一般情况下用 computed 性能更优
      1. app.reverseMsg1 -> "dlrow olleh"
      2. app.reverseMsg2() -> 222 "dlrow olleh" 会重新执行函数
      3. 因为 computed 会利用缓存对性能进行优化,使得重复读取 reverseMsg1 时不会重复计算,而 methods 则会重复执行降低性能
  • 如何写好呆码

    1. 表达好呆码的意图(命名,可读性)
    2. 写测试
    3. 减少重复
<div id="app">
    <!-- data -->
    <div>{{msg.split("").reverse().join("")}}</div>

    <!-- components -->
    <div>{{reverseMsg1}}</div>
    <div>{{reverseMsg1}}</div>

    <!-- methods -->
    <div>{{reverseMsg2()}}</div>
    <div>{{reverseMsg2()}}</div>
</div>
const app = new Vue({
    el: '#app',
    data: {
        msg: 'hello world'
    },
    computed: {
        reverseMsg1() {
            console.log(111);
            return this.msg.split('').reverse().join('');
        }
    },
    methods: {
        reverseMsg2() {
            console.log(222);
            return this.msg.split('').reverse().join('');
        }
    }
});

watch

  • 观察依赖参数,当依赖参数改变时,进行处理

  • watch 与 components 区别是什么?

    • watch 观察 一个依赖 更新对应 多个值: 1 的关系
    • components 多个依赖其中一个 更新对应 一个值: 1 的关系
  • 可写成对象形式

    • handler 为执行事件
    • immediate 为 true 时,立刻执行
  • 当观察的依赖为 对象 时,默认不会观察对象深度,如需观察加上 deep: true

  • 需要观察 对象的某个key 时,可通过 "obj.key" 进行观察

<div id="app">
    <div>{{msg}}</div>
    <div>{{msg1}}</div>
    <div>{{msg2}}</div>
    <div>{{msg3}}</div>
    <hr />
    <div>{{info.a}}</div>
    <div>{{info.b}}</div>
    <hr />
    <button @click="handleClick1">改变msg</button>
    <button @click="handleClick2">改变info.a</button>
    <button @click="handleClick3">改变info.b</button>
</div>
const app = new Vue({
    el: '#app',
    data: {
        msg: 'hello world',
        msg1: '',
        msg2: '',
        msg3: '',
        info: {
            a: 'infoA',
            b: 'infoB'
        }
    },
    watch: {
        // 写法一
        msg(newValue, oldValue) {
            console.log(newValue, oldValue);

            this.msg1 = newValue + '1';
            this.msg2 = newValue + '2';
            this.msg3 = newValue + '3';
        },
        // 写法二
        msg: {
            handler(newValue, oldValue) {
                console.log(newValue, oldValue);

                this.msg1 = newValue + '1';
                this.msg2 = newValue + '2';
                this.msg3 = newValue + '3';
            },
            immediate: true // 为 true 时,立刻执行
        },
        // 对象
        info: {
            handler(newValue, oldValue) {
                console.log(newValue, oldValue);
            },
            deep: true // 为 true 时,观察对象深度
        },
        // 只观察对象某个 key 时
        // 观看效果需要把上面对 info 的观察进行注释
        'info.a': {
            handler(newValue, oldValue) {
                console.log(newValue, oldValue);
            }
        }
    },
    methods: {
        handleClick1() {
            this.msg = 'watch'
        },
        handleClick2() {
            this.info.a = 'infoAWatch'
        },
        handleClick3() {
            this.info.b = 'infoBWatch'
        }
    },
});

条件渲染

  • 条件的处理与 js 无异,无非就是 if elseif else,不过在 Vue 里我们需要加上 v- ,不过呢,Vue 还有一个 v-show
  • v-if vs v-show
    • v-if 在被隐藏的时候会留下一个 <!----> 注释
    • v-if 是真正的条件渲染,它会确保在切换过程中,条件块内的事件监听器和子组件适当的被销毁和重建
    • v-if 也是懒惰的,如果在初次渲染中条件为 false 时,他会什么都不做,知道条件第一次为 true 时,才会开始渲染
    • v-show 不管条件是什么,元素都会进行渲染,因为他只是简单的基于 css的display 切换
    • 一般情况下,v-if 有更高的切换开销,v-show 有更高的初次渲染开销
    • 如果代码块需要频繁的切换,使用 v-show 会比较好
    • 如果代码块很少进行改变,那么使用 v-if 会更好
<div id="app">
    <div v-if="age === 18">花一样的年龄</div>
    <div v-else-if="age > 18">成年人</div>
    <div v-else>未成年</div>

    <div v-show="true">show</div>
</div>
const app = new Vue({
    el: '#app',
    data: {
        age: 18
    }
});

循环

  • v-for: (item,index) in arrList | (val,key,index) in objList
  • Vue 统一了处理接口 in ,没有 js 这么多循环方法
  • 优化策略 key
    • 非强制,不写会有小警告,不影响使用
    • 为了 diff 优化,使更新DOM的时候性能更好
    • key 不能重复,重复则会出现性能问题,也会发生一些状态 bug
    • 最好不使用 index 值,会造成重复 有空写个bug出来
<div id="app">
    <ul>
        // 对象
        <li v-for="(val,key,index) in objList" :key="'objList'+val.id">index:{{index}} -- key:{{key}} -- name:{{val.name}} -- age:{{val.age}}</li>
        <hr />
        // 数组
        <li v-for="(item,index) in arrList" :key="'arrList'+item.id">index:{{index}} -- name:{{item.name}} -- age:{{item.age}}</li>
    </ul>
</div>
const app = new Vue({
    el: '#app',
    data: {
        // 对象
        objList: {
            a: {
                id: 1,
                name: '小黑',
                age: 18
            },
            b: {
                id: 2,
                name: '小白',
                age: 18
            }
        },
        // 数组
        arrList: [
            {
                id: 1,
                name: '小黑',
                age: 18
            }, {
                id: 2,
                name: '小白',
                age: 24
            }
        ]
    }
});

class & style

  • class 可通过 :class 绑定
    • 对象:key 为 className ,通过 value: true | false 控制是否有 class
    • 数组:可使用 三元表达式 控制是否有 class
    • 数组对象:两者结合
  • style 可通过 :style 绑定
    • 对象:key 需要使用 小驼峰命名法
    • 数组对象
.red {
    color: red;
}

.size {
    font-size: 50px;
}
<div id="app">
    <div :class="classes">css</div>
    <div :style="styleInfo">style</div>
</div>
const app = new Vue({
    el: '#app',
    data: {
        // 对象
        classes: {
            red: true,
            size: true,
        },
        // 数组
        classes: [
            true ? 'red' : '',
            { size: true }
        ],
        // 对象
        styleInfo: {
            color: 'red',
            fontSize: '50px'
        },
        // 数组
        styleInfo: [{
            color: 'blue'
        }, {
            fontSize: '50px'
        }]
    }
});

input表单

  • 使用 methods 与数据进行绑定
<div id="app">
    <input type="text" @input="handleInput" />
    <div>{{msg}}</div>
    <input type="checkbox" @input="handleChange" />
    <div>{{isCheckBox}}</div>
</div>
const app = new Vue({
    el: '#app',
    data: {
        msg: '',
        isCheckBox: false
    },
    methods: {
        handleInput(e) {
            console.log(e.target.value);
            this.msg = e.target.value;
        },
        handleChange(e) {
            this.isCheckBox = e.target.checked;
        }
    }
});
  • 我们发现使用 methods 会比较麻烦
    • 需要 监听 input => 处理事件监听 => 拿到 input 的值 => 进行数据的更新 => 更新视图
    • 但是我们实际工作中这种需求场景比较多,使得代码更加繁琐
  • 这个时候 Vue 就给我们带来了一个内置的语法糖 v-model
    • 它可以直接写入我们需要绑定的值,即可完成我们上面的一系列操作
    • v-model 看起来像是一个 双向数据流,实际上只是内置语法糖,简化了写法
    • v-model 在内部为不同的输入元素使用不同的 property 并抛出不同的事件
      1. text 和 textarea 元素使用 value property 和 input 事件
      2. checkbox 和 radio 使用 checked property 和 change 事件
      3. select 字段将 value 作为 prop 并将 change 作为事件
    • 可通过修饰符 .number 转换成 number 类型,下面案例通过 watch 观察他的类型
    • 除此外还有 .lazy .trim 修饰符
<div id="app">
    <input type="text" v-model="msg" />
    <div>{{msg}}</div>
    <input type="number" v-model.number="num" />
    <div>{{num}}</div>
    <input type="checkbox" v-model="isCheckBox" />
    <div>{{isCheckBox}}</div>
</div>
const app = new Vue({
    el: '#app',
    data: {
        msg: '',
        isCheckBox: false,
        num: ''
    },
    watch: {
        num(newValue, oldValue) {
            console.log(typeof newValue);
        }
    },
});

小示例

<div id="app">
    <ul>
        <li v-for="(product,index) in products" :key="index">
            {{product.name}} -- {{product.count}}
            <span v-if="product.count === 0">卖没辣</span>
            <span v-else>还有货</span>
            <button @click="product.count++">+1</button>
            <button @click="--product.count<0?product.count=0:''">-1</button>
        </li>
    </ul>
    总数:{{totalCount}}
</div>
const app = new Vue({
    el: '#app',
    data: {
        products: [{
            count: 1,
            name: '苹果'
        }, {
            count: 0,
            name: '香蕉'
        }, {
            count: 1,
            name: '雪梨'
        }]
    },
    computed: {
        totalCount() {
            return this.products.reduce((total, item) => {
                return total + item.count
            }, 0)
        }
    }
});