Vue基础

作者: hellomyshadow | 来源:发表于2019-01-06 17:55 被阅读0次

VueJs

Vue.js:渐进式的、MVVM模式的JavaScript框架,所谓渐进式,其实就是Vue核心库+插件;
    1. 编码简洁,体积小,运行效率高,适合移动端/PC端开发;
    2. Vue本身只关注UI,可以轻松引入Vue插件或其他第三方库;
    3. 借鉴Angular.js的模板和数据绑定技术,借鉴React的组件化和虚拟DOM技术;
    4. 不兼容<=IE8,因为IE8无法模拟的ES5特性,但它支持所有兼容ES5的浏览器。
1. Vue扩展插件:
    1. vue-cli(vue脚手架)、vue-resource(即axios,ajax请求)、vue-router(路由)
    2. vuex(状态管理)、vue-lazyload(图片懒加载)、vue-scroller(页面滑动相关)
    3. 基于vue的UI组件库:mint-ui(移动端)、element-ui(PC端)
2. MVVM:
    1. Model:模型,数据对象
    2. View:视图,模板页面,动态的HTML页面,包含一些JS语法代码,如{{xx}}、v-xx
    3. ViewModel:视图模型,对应Vue实例,new Vue({})
    4. ViewModel通过Vue[DOM监听、数据绑定]关联Mode与View
3. Vue是声明式开发方式,遵循对应的语法即可,而命令式开发需要关心整个实现的流程。

Vue语法

1. 创建实例:
    const vm = new Vue({
        el: '#app', --> 管理的一块区域,通过CSS选择器查找管理的区域
        data: { --> 所管理区域内需要的数据Model
            msg: '<a href="https://www.baidu.com/">go</a>',
            name: 'A',
            imgUrl: 'https://www.abc.cn/a.jpg',
        },
        methods: { --> 管理区域内的方法(ES6)
            test1(){ alert("hehe!") },
            test2(a){ alert(a) }
        },
        computed: { --> 属性计算,this指向data
            full1() { return "Hello " + this.msg; }
        },
        watch: { --> 监视属性的变化,this指向data
            name: function(newVal, oldVal){ --> name发生改变的回调函数
                this.msg = "Hello " + newVal; --> 动态修改属性msg
            }
        }
    })
2. 双大括号表达式:<div>{{变量/JS表达式}}</div>
    <div id="app">
        <p>{{msg}}</p> ===> 不管msg是不是一个标签,都会当成一个普通的字符串
        <p>{{msg.toUpperCase()}}</p> ===> 把msg转为大写字母
    </div>
3. v-xxx:自定义标签
    1. <p v-text="msg"></p>:更新标签内的字符串文本textContent;
    2. <p v-html="msg"></p>:如果msg是一个标签,则以标签显示,类似于innerHTML;
    3. <img v-bind:src="imgUrl" />:强制数据绑定,把imgUrl作为一个表达式解析;
    等效于:<img :src="imgUrl" />
    4. <button v-on:click="test1">:无参的绑定事件监听,等效于 @click="test"
    5. <button v-on:click="test2('test')">:有参的绑定事件;也可以直接使用data中
    的属性:<button @click="test2(msg)">
    6. v-model:双向绑定,<input type="text" v-model="msg"/>
    msg变化,输入框中的内容也会变化,同理,输入框中的内容发生变化,msg也随之变化;
4. 计算属性:computed
    <input type="text" v-model="full1"/>,输入框中的值就是full1的返回值,
    任何地方的msg变化,full1()会重新计算,返回值变化,进而输入框中的值随之变化。
5. 监视属性:watch,监视的属性name发生变化,回调对应的函数;
    1. 深度监视:如果监听的属性是一个数组,普通监听无法监听到数组内的变化
    watch: {
        属性名: { --> 启用深度监听,数组内的任何变化,都会被监听到
            deep: true,
            handler: function(newVal, oldVal) { ... }
        }
    }
    2. 监视属性的方法不能使用箭头函数,因为箭头函数仍然沿用上一级作用域的this,已经不再
    指向Vue组件对象.
6. Vue实例的方法都以"$"开头:
    vm.$watch('监视的属性名', function(newVal, oldVal){ -->动态添加属性监听
        this.msg = "Hello " + newVal;
    });
7. 计算属性-高级:getter/setter、缓存
    1. 通过getter/setter实现对属性数据的显示和监视,计算属性的方法只会调用一次,
    多次读取也只执行一次getter,是为了提高性能,计算之后做了缓存处理;
    2. 双向绑定v-model:
    computed: { --> 属性计算,this指向data
        full2: {
            get(){ --> 根据相关的属性,计算并返回当前属性值
                return this.msg
            },
            set(value){ --> 当属性值发生变化时,更新相关的属性
                this.msg=value
            }
        }
    }
    <input type="text" v-model="msg"/>
    <input type="text" v-model="full2"/> --> full2的getter/setter是根据msg
    计算的:msg的变化会引起getter的回调,手动输入内容又会回调setter,进而改变msg
1. class与style的绑定
    .con1{ color: red; }  .con2{ color: blue; }  .con3{ font-size: 20px; }
    data: {
        cl: 'con1',
        isOne: true,
        isTwo: false,
        activeColor: 'red',
        activeSize: 30
    },
    methods: {
        update1(){
            this.cl = 'con2' --> 动态改变cl的值,即改变样式
        },
        update2(){
            this.isOne = !this.isOne --> 改变true/false,也就改变了应用
            this.isTwo = !this.isTwo --> 的样式
        }
    }
    1. class绑定::class="'样式名'",:class='xxx'
    <p :class="'con1'">PPP</p> ==> 等效于:class="con1"
    <p :class="cl">PPP</p> ==> 绑定cl变量,动态控制样式
    <p :class="cl" class="con3">PPP</p> ==> :class和原生class配合使用
    <p :class="{con1: isOne, con2: isTwo}">PPP</p> ==>对象的方式
    <p :class="[con1, con3]">PPP</p> ==> 数组的方式
    2. style绑定::style="{ }"
    <p :class="{color: activeColor, fontSize: activeSize+'px'}">PPP</p>
    ==> 属性名就是样式名,带"-"的属性名,后面的首字母大写,属性值是data的属性;
2. 条件渲染指令:v-if、v-else、v-show
    var vm = new Vue({
        el: '#app',
        data: { isOk: true, }
    });
    <p v-if="isOk">vif</p> <p v-else>velse</p>
    <p v-show="isOk">vshow1</p> <p v-show="!isOk">vshow2</p> 
    <button @click="isOk=!isOk">Change</button>
    1. v-if、v-else是真正的条件渲染,作用的标签会被销毁与创建,且v-if是惰性的,
            如果初始条件为false,则什么也不错;只有在条件第一次为true时,才会在DOM中局部渲染;
    2. v-show只是设置内联样式display:none; 实现隐藏,标签并没有被销毁;
    3. 如果切换频繁,v-show的效率会更高一些;而如果不希望标签存在于DOM中,则使用v-if。
3. 列表渲染:v-for
    1. 遍历数组
    data: {
        persons: [
            {name: 'Tom', age: 18}, {name: 'Jack', age: 16},
            {name: 'Bob', age: 19}, {name: 'Rose', age: 17},
        ],
        searchVal: '', --> 用于保存搜索框中的内容
        orderBy: 0 --> 排序的标识
    },
    methods: {
        deleteP(index){ --> 删除当前索引的元素
            this.persons.splice(index, 1);
        },
        changeP(index) { --> 更新失败
            this.persons[index] = {name: 'Any', age: 11};
        }
    }
    <ul>
        <li v-for="(p, index) in persons" :key="index"> ==>遍历persons
            {{index}}---{{p.name}}---{{p.age}}
            <button @click="deleteP(index)">Delete</button>
            <button @click="changeP(index)">Change</button>
        </li> ==>:key表示<li>的唯一标识,让Vue减少DOM更新,提高性能
    </ul>
    2. 由于JavaScript的限制,Vue不能检测以下变动的数组:
    a. 利用索引直接修改元素,如:vm.items[i] = val,delete vm.items[i];
    b. 修改数组的长度,如:vm.items.length = len; --> splice(len)可以解决
    所以changeP()执行后,虽然persons内部元素已经改变了,但界面没有任何变化;
    3. deleteP()能删除成功,是因为Vue重写了数组的部分方法,这些变异方法先执行了
    数组的原生方法,然后去更新UI,如push()、splice()、unshift()...;
    4. 而对于filter()、concat()、slice(),不会改变原数组,而是返回一个新数组;
    this.persons = this.persons.filter(function); --> 新数组替换旧数组
    5. 但如果更新的是数组中的对象,则可以被监听到,this.persons[index].age=20
    6. 遍历对象:v-for
    <li v-for="(value, key) in persons[0]" :key="key">
        {{value}}---{{key}}
    </li> ==> key表示对象中的属性名,value表示属性值
    7. 搜索与排序:搜索框中的内容变化,被遍历的数组随之改变
    methods:
        resetOrder(order){ this.orderBy = order; }
    computed:
        searchPerson(){
            let that=this; --> 保存this的指向
            let filterPerson = this.persons.filter(function(p){
                return p.name.indexOf(that.searchVal) !== -1;
            }); ---> 筛选
            if(this.orderBy !== 0) { --> 排序
                filterPerson.sort(function(p1, p2){
                    if(that.orderBy===1) { --> 升序排列
                        return p1.age - p2.age
                    } else { --> 降序排列
                        return p2.age - p1.age
                    }
                });
            }
            return filterPerson;
        }
    --------------------------------------------------------------
    <input type="text" v-model="searchVal" /> ==> 输入框绑定searchVal
    <ul>
        <li v-for="(p, index) in searchPerson" :key="index">
            {{index}}---{{p.name}}---{{p.age}}
        </li> ==> 被遍历的数组是动态计算的
    </ul>
    <button @click="resetOrder(1)">升序排列</button> --> 重置orderBy的值,
    <button @click="resetOrder(2)">降序排列</button> --> 将重新计算遍历的数组
    <button @click="resetOrder(0)">原本顺序</button>
    8. 还是由于JS的限制,Vue不能检测对象属性的添加或删除。
4. 事件处理
    1. 事件绑定:v-on在绑定事件时,对于无参的方法,会隐式传递默认参数event;
    对于有参的方法,希望获取参数event,则需要手动传递"$event"
    methods:
        test1(event){ console.log(event.target.innerHTML) },
        test2(num, event){ console.log(event.target.innerHTML) }
    ---------------------------------------------
    <button @click="test1">TEST1</button>
    <button @click="test2(45, $event)">TEST2</button>
    2. 阻止事件冒泡
    <div @click="test3">
        <div @click.stop="test4"> --> 阻止事件冒泡
    </div>
    3. 阻止默认行为
    <a href="http://www.baidu.com/" @click.prevent="test5">
    4. 按键事件,如按键松开:@keyup
    <input type="text" @keyup="test6"> --> 监听任何按键的松开事件
    <input type="text" @keyup.13="test6"> --> 监听keyCode为13的按键松开事件
    <input type="text" @keyup.enter="test6"> --> 少数按键可以直接使用名字
5. 表单:<form action="#" @submit="handleSubmit">
    1. 输入框直接使用"v-model"绑定即可;
    2. 单选框:v-model使用同一个data中的属性,其属性值是被选中的value属性值;
    3. 复选框:v-model也是使用同一个data中的属性,但该属性是一个数组,元素是复选框
    的value属性值,数组中的初始值,就是复选框的默认值;
    4. 如果只有一个复选框,只是判断是否被选中,则用v-model绑定一个boolean型的属性,
    或绑定一个带有getter/setter的计算方法:<input type="checkbox" v-model="b"/>
    b为true,则被选中,同理,如果手动取消选中,则b也会变为false;
    5. <select>下拉框:
    data: {
        city: [{id:1, name:'BJ'}, {id:2, name:'SH'}, {id:3, name:'XY'}],
        cityId: 0
    },
    <select v-model="cityId"> ==> v-model最终接收选择的值
        <option value="">未选择</option>
        <option :value="c.id" v-for="(c, index) in city" :key="index">
        {{c.name}}</option>
    </select>
    1. <option>的原生属性value会把属性值当作一个普通的文本,而不是一个表达式,
    所以用vue的":value",其实是"v-bind:value",v-bind可以省略;
    2. <option>上使用":key"也是为了唯一的标识。
6. 生命周期:又叫勾子函数
    1. 初始化显示:beforeCreate()、created()、beforeMount()、mounted()
    2. 更新显示:this.xxx = value --> beforeUpdate()、updated()
    3. 销毁Vue实例:vm.$destroy() --> beforeDestroy()、desroyed()
    1. mounted():挂载,初始化显示之后立即调用,页面已经渲染完成;
    2. beforeDestroy():调用vm.$destroy(),销毁Vue实例之前回调;
    data: {
        show: true
    },
    mounted() { --> 初始化Vue实例时调用
        let that = this;
        this.intervalId = setInterval(function(){
            that.show = !that.show;
        }, 1000); --> 初始化时开启一个定时器
    },
    beforeDestroy() { -->销毁时清除定时器,否则定时器一直存在,导致内存泄露
        clearInterval(this.intervalId);
    },
7. 过滤器
    1. 定义过滤器
    Vue.filter('filterName', function(value, arg, ...){
        //数据处理 ...
        return newValue
    });
    2. 使用过滤器:
    <div>{{myData | filterName}}</div> ==> 无参数
    <div>{{myData | filterName(arg)}}</div> ==> 有参数
8. Vue指令
    1. 常用内置指令:v-text、v-html、v-model(双向数据绑定)、v-if、v-else、v-show、
    2. v-for、v-on(简写为'@')、v-bind(强制绑定解析表达式,可以省略)
    3. ref:指定唯一标识,vue对象通过"$refs"属性访问这个元素对象;
    <p ref="content">PPP</p>
    methods:
        hint(){
            const p = this.$refs.content --> 根据ref获取指定标签
            p.textContent --> 获取标签内容 
        }
    4. v-cloak:防止闪现,与CSS配合,[v-cloak]{display:none}
    <p>{{msg}}</p> --> 如果数据加载过慢,页面可能显示的是"{{msg}}"
    1. 指令属性在解析之前是存在的,但是解析之后就会从标签移除;
    <p v-cloak>{{msg}}</p>
    <style>
        [v-cloak] { --> 属性选择器
            display: none; --> 隐藏标签
        }
    </style>
    2. 页面解析之前,<p>上的属性选择器v-cloak是存在的,所以<p>被隐藏了;在页面解析
    之后,{{msg}}也已经被替换成真实数据了,指令属性会被移除,所以<p>会显示出来。
8. 自定义指令
    1. 注册全局指令
    Vue.directive('my-directive', function(el, binding){
        el.innerHTML = binding.value.toupperCase();
    }) --> el:标签元素对象,binding:包含指令相关信息数据的对象
    2. 注册局部指令:只在当前Vue实例的el范围内有效
    directives: {
        'my-directive': { ---> 简写为:'my-directive'(el, binding){ ... }
            bind(el, binding) {
                el.innerHTML = binding.value.toupperCase()
            }
        }
    }
    3. 使用指令:v-自定义指令名,<p v-my-directive="msg"></p>
9. Vue插件:按照Vue文档开发的一个js文件
    1. 创建MyPlugin.js:
    (function(){
        const MyPlugin = {}; --> 需要向外暴露的插件对象
        //--> 插件对象必须有一个install()
        MyPlugin.install() = function(Vue, options) { ... }
        window.MyPlugin = MyPlugin; --> 挂在到window对象上,向外暴露
    })()
    2. 声明使用插件:Vue.use(MyPlugin) --->即执行MyPlugin.install()

相关文章