| style与class
| computed、directive、filter
| watch 侦听Data数据的变化
| 生命周期: beforeCreate、create、beforeMount、mounted、beforeUpdate、updated、destroyed
| this.$refs、$el、$data、$watch
| v-bind缩写:、v-on缩写@

Vue2.0

一、Vue的MVVM实现的原理

    ViewModel是Vue.js的核心,Vue实例是作用于某一个HTML元素上的,这个元素可以是HTML的body元素,也可以是指定了id的某个元素

    DOM Listeners 和 Data Bindings看作两个工具,它们是实现双向绑定的关键。

    从view层来看,ViewModel中的DOM Listeners工具会帮我们监测页面上DOM元素的变化,如果有变化,则更改Model中的数据;

    从Model层来看,当我们更新Model中的数据时,Data Bindings工具会帮我们更新页面中的DOM元素。


二、安装

    $ npm i vue --save-dev

    $ npm i vue-cli 脚手架

生命周期

一、构造器

    1、每个构造器都是通过创建一个Vue的实例启动的

        var vm = new Vue({
            // ...    
        })

    2、扩展构造器

        通过扩展构造器可以创建可复用的组件构造器

        var MyComponent = Vue.extend({
            // 扩展选项
        })


二、生命周期

    1、beforeCreate(): 实例初始化,数据观测(data observer)和事件(event/watcher)配置之前被调用

    2、created(): 实例创建完后被调用,完成了数据观测(data observer)和事件(event/watcher)回调,但还挂载还没开始$el属性不可见

    3、beforeMount(): 在挂载开始之前调用,render()函数被调用

    4、mounted(): el被创建的vm.$el替换,挂载到实例上调用钩子

    5、beforeUpdate(): 数据更新时调用,在虚拟DOM重新渲染

    6、updated(): 数据更改导致虚拟DOM重新渲染

    7、destroyed(): 卸载组件

数据绑定

一、文本绑定:  <p>{{ data.name }}</p>

二、html绑定:  <p v-html="data"></p>

三、绑定属性的值 

    <div id="item-{{id}}"></div>

    <div :id="userId"></div>

四、表达式:  {{ dat.num == 1 }}、 {{ num ? 'yes' : 'no' }}、 {{if(ok) {return message} }}

五、过滤器:  {{ message | capitalize }}

    连续过滤器:  {{ message | filterA | filterB }}

常用指令

指令: 以 v- 开头

    <div v-if="greeting == 1"></div>

    带参数: <a v-bind:href="url"></a>

一、v-if、v-else-if、v-else条件渲染:

    <div v-if="type === 'A'">A</div>
    <div v-else-if="type === 'B'">B</div>
    <div v-else>Not A/B/C</div>

二、v-show: 显示还是隐藏元素,用的display

三、v-for 循环

    $index: 索引        $key: 

    * 数组
        <li v-for="item in items" :key="item">{{ item.message }}</li>

    * 数组对象
        <li v-for="(val, index) in objList" :key="index">
            {{index}}. {{key}} : {{val.type}}
        </li>

        ** 注意:key,如果key没有改变不会重新渲染组件,问题在于子组件中存在于绑定

    * filterBy()、orderBy()过滤器

四、v-model: 绑定值,这也是MVVM的关键点

    可以对文本表单、单选框 、多选框、下拉菜单进行绑定值

        1、lazy: 不是输入时就进行同步而是在change的时候才对数据进行同步

            <input type="text" v-model="msg" lazy /> {{msg}}

        2、number: 将用户输入的转成Number型,如果返回NaN那就返回原值

        3、debounce: 设置一个最小延时,否则如果输入是ajax请求,每次敲击都会去请求

            <input type="text" debounce="500" v-model="msg">        // 按完键500毫秒后在进行

    获取checkbox值:

        <input type="checkbox" v-model="toggle" v-bind:true-value="a" v-bind:false-value="b">

        // 当选中时
        vm.toggle === vm.a

        // 当没有选中时
        vm.toggle === vm.b

五、v-bind: 绑定到HTML元素上,v-bind:class="active",缩写 ":" <a :href='url'></a>

六、v-on: 监听DOM事件 v-on缩写: "@" <div @click="doSomeing"></div>

七、ref: 访问子组件

    <div ref="box">xxxx</div>
    <el-button type="primary" slot="append" @click="getRefs">发送</el-button>
    </div>

    {
        methods:{
            getRefs(){
                console.log(this.$refs.box.innerHTML);        // 获取 $refs
            }
        }
    }

    如果绑定一个元素使用 :ref='item'
    <p v-for="item in items" :ref="item"></p>

八、v-pre: 跳过这个元素和它的子元素的编译过程,这样加快了编译的速度

    <div v-pre>{{ 这里不用框架来编译 }}</div>

九、v-cloak:

十、v-once: 只渲染元素和组件一次,之后的渲染都会跳过次元素

    <span v-once>xxxxx</span>

过滤器

过滤器,对绑定值进行处理

一、自定义过滤器

    在一个组件中定义过滤器:
        <span v-text="message | reverse 'addText' "></span>
        export default {
            filters: {
                capitalize: function (value) {
                    value = value.toString();
                    return value.charAt(0).toUpperCase() + value.slice(1)
                }
            }
        }

    定义全局过滤器:
        filters.js
        Vue.filter('datetime', function (value, format) {
            if (!value) {
                return 
            }
            return moment(value).format(format || 'YYYY-MM-DD HH:mm:ss');
        });

        main.js
        import './filters.js'        // 引用


二、内置过滤器

    1、uppercase: 字母转成大写

    2、lowercase: 字母转成小写

    3、capitalize: 首字母转成大写

    4、filterBy: 过滤内容

    5、limitBy: 过滤数据从开始到指定位置结束的内容

    6、orderBy: 过滤排序

    7、currency: 货币过滤

    8、debounce: 延迟过滤


三、双向过滤器

    模型的值显示在视图之前转换它

    <input v-mode="money | formatMoney">
    <div>{{ money | formatMoney }}</div>

    Vue.filter('formatMoney', {

        // model -> vlew过程  在更新<input> 元素之初化值
        read: function(val){
            return '$' + val.toFixed(2);
        },

        // vlew -> model过程 在写回数据之前格式化值
        write: function(val){
            var number = +val.replace(/[^\d.]/g, '');
            return isNaN(number) ? 0 : parseFloat(number.toFixed(2));
        }
    })


四、动态参数

    参数用空格格开
    <input type="text" v-model="userInput">
    <span>{{msg | concat userInput}}</span>

    Vue.filter('concat', function (value, input) {
        // `input` === `this.userInput`
        return value + input;
    })


五、filterBy过滤器

    <div id="app">
        <div>过滤数据里包含 蛋糕 字符 </div>
        <div class="box">
            <ul>
                <li v-for="user in users | filterBy '蛋糕' ">{{ user.name }}</li>
            </ul>
        </div>

        <div style="margin-top: 30px" >过滤出输入的字符</div>
        <input type="text" name="" v-model="searchKey" />
        <div class="box">
            <ul>
                <li v-for="user in users | filterBy searchKey in 'name'">{{ user.name }}</li>
            </ul>
        </div>
    </div>

    <script src="../../js/vue.js"></script>
    <script type="text/javascript">
        var vm = new Vue({
            el: '#app',
            data: {
                searchKey: '',
                users:[
                    {
                        name: '外卖',
                        tag: 1
                    },
                    {
                        name: '鲜花',
                        tag: 5
                    },
                    {
                        name: '蛋糕',
                        tag: 4
                    },
                    {
                        name: '水果',
                        tag: 2
                    },
                    {
                        name: '茶点',
                        tag: 3
                    }
                ]
            }
        })
    </script>


六、orderBy排序

    <div id="app">
        <input type="text" name="" v-model="searchKey" />
        <div class="box">
            <ul>
                <li v-for="user in users | orderBy 'tag'">{{ user.name }}</li>
            </ul>
        </div>
    </div>

    <script type="text/javascript">
        var vm = new Vue({
            el: '#app',
            data: {
                searchKey: '',
                users:[
                    {
                        name: '外卖',
                        tag: 1
                    },
                    {
                        name: '咖啡',
                        tag: 5
                    },
                    {
                        name: '餐厅订座',
                        tag: 4
                    },
                    {
                        name: '蛋糕',
                        tag: 2
                    },
                    {
                        name: '票务',
                        tag: 3
                    }
                ]
            }
        })
    </script>

指令

一、钩子函数

    el:指令所绑定的元素,可以用来直接操作 DOM 。
    binding:一个对象,包含以下属性:
    name:指令名,不包括 v- 前缀。
    value:指令的绑定值,例如:v-my-directive="1 + 1" 中,绑定值为 2。
    oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
    expression:字符串形式的指令表达式。例如 v-my-directive="1 + 1" 中,表达式为 "1 + 1"。
    arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 "foo"。
    modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
    vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
    oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

二、对象字面量

    <div v-demoA="{ color: 'white', text: 'hello'}"></div>

    Vue.directive('demoA', function(el, value){
        console.log(value.color);
        console.log(value.text);
    })

三、元素指令,相当于angular的E指令

    Vue.elementDirective('my-directive', {
        bind: function(){
            // 操作this.el
        }
    })

    <my-directive></my-directive>            // 不能这么写<div v-my-directive></div>

四、高级选项

    params: 自动提取绑定元素的这些特性.

    <div v-example a="hi"></div>
    Vue.directive('example', {
        params: ['a'],
        bind: function () {
            console.log(this.params.a);         // -> "hi"
        }
    })

computed 计算属性

计算属性当依赖属性发生变化时,属性的值会自动更新,相关的DOM也会同步更新

一、计算属性的getter

    <div id="app">
        <p>user_inof={{ userInfo }}</p>
    </div>

    <script>
        var vm = new Vue({
            el: '#app',
            data: {
                "user_name": "lulu",
                "user_age": "20"
            },
            computed: {
                // 一个计算属性getter
                userInfo: function(){
                    return '姓名: '+ this.user_name +' 年龄: '+ this.user_age;
                }
            }
        })
    </script>

二、计算属性的setter

    var vm = new Vue({
        el: '#app',
        data: {
            "user_name": "lulu",
            "user_age": "20"
        },
        computed: {
            userInfo: function(){
                get: function(){
                    return '姓名: '+ this.user_name +' 年龄: '+ this.user_age;
                },
                set: function(newValue){        // 这里当
                    this.userInfo = newValue;
                }
            }
        }
    })

watch 侦听器

watch 侦听data下指定数据的变化 

watch:{
    message: function(newValue){
        return newValue + 1;        // 如果message变化值加1
    }
}

// 写在实例化下侦听数据变化
// vm.$watch('message', function(newVal, oldVal){
//    console.log(newVal, oldVal);
//    this.message = newVal.replace(/s|g/g, '*');
// })

class和style的绑定

一、class

    // 对象
    <div :class="{ 'active': isActive }"></div>
    var vm = new Vue({
        el: '#app',
        data: {
            isActive: true
        }
    })

    // 数组
    <div :class="[activeClass, errorClass]"></div>        // 三元 <div v-bind:class="[isActive ? activeClass : '', errorClass]"></div>
    data: {
        activeClass: 'active',
        errorClass: 'text-danger'
    }    

二、style

    <div :style="[crm, hk]"> 或 <div :style="{color: activeColor, fontSize: fontSize+'px'}">

    var vm = new Vue({
        el: '#app',
        data: {
            activeColor: 'red',
            fontSize: 30,
            crm: {
                color: '#000',
                fontSize: '16px'
            },
            hk: {
                color: '#fff',
                fontSize: '18px'
            }
        }
    })

事件

一、@click

    <div @click="say"></div>
    <div @click="say('hi')"></div>
    <div @click="content + 1"></div>

    <!-- 阻止单击事件冒泡 -->
    <a v-on:click.stop="doThis"></a>

    <!-- 提交事件不再重载页面 -->
    <form v-on:submit.prevent="onSubmit"></form>

    <!-- 修饰符可以串联  -->
    <a v-on:click.stop.prevent="doThat"></a>

    <!-- 只有修饰符 -->
    <form v-on:submit.prevent></form>

    <!-- 添加事件侦听器时使用事件捕获模式 -->
    <div v-on:click.capture="doThis">...</div>

    <!-- 只当事件在该元素本身(而不是子元素)触发时触发回调 -->
    <div v-on:click.self="doThat">...</div>

二、按键别名

    .enter、.tab、.delete (捕获 “删除” 和 “退格” 键)、.esc、.space、.up、.down、.left、.right、.ctrl、.alt、.shift、.meta

三、once: 只处理一次点击  <a v-on:click.once="doThis"></a>

四、修饰符 <input v-on:keyup.13="submit">

模板语法

Vue在底层将模板编译成虚拟DOM渲染函数,也可以不用模板直接写render函数,可选JSX语法

常见问题

一、props传值子元素不会接收

    问题1: 封装tab标签来加载不同子组件,当同一组件重新被打开时,应先消毁之前的相同组件在加载新的组件,但在子组件中destroyed()来侦听消毁缺没有回调

     // 打开新页面
    openTabPage(tabPage, cb) {
        // 先关闭存在的同名的,再打开
        if (this.pages.some(item => item.name === tabPage.name)) {
            this.handleRemove(tabPage.name);
        }
        this.$nextTick(()=>{                // 使用$nextTick 进行重新渲染
            this.pages.push(tabPage);
            this.activeName = tabPage.name;
        })

        if (cb && typeof cb === 'function') {
            cb(this.activeName)
        }

        if (this.tabCreate) {
            this.tabCreate(tabPage)
        }
    },

    问题2: 这种加了一层会对相同子组件进行消毁在重建

        <template slot="tabcreate">
    <create-data-config ref="createDataConfig" :create-prop="createProp"></create-data-config>
  </template>

        openTab(tabName, row){
            // this.createProp['detailInfo'] = row || '';            这种写法子组件watch不到createProp的变化 

            this.createProp = {
                detailInfo: row || ''
            }
  }

        子组件
        watch:{
            createProp: function(){
                debugger;
            }
        }


二、v-bind 内联字符串连接

    data(){
        return {
            addString: '加入内容'
        }
    }

    1.x版本 写法  <div attr="xxxx{{addString}}">
    2.x版本 写法  <div v-bind="'xxxx'+ addString">


三、checkbox动态创建绑定

    // v-model="item.check" 绑定的值要相同
    <p v-for="item in checkList">
        <input type="checkbox" name="cb" v-model="item.check" /> {{item.name}}
    </p>

    data(){
        return{
            checkList:[
                {check: false, name: 'aa'},
                {check: false, name: 'bb'},
                {check: false, name: 'cc'}
            ]
        }
    }


四、vue使用jxs语法

    new Vue({
        el: '#demo',
        render (h) {
            return (    // 使用这种jsx语法
                <AnchoredHeading level={1}>
                    <span>Hello</span> world!
                </AnchoredHeading>
            )
        }
    })

    安装插件
    $ npm install babel-plugin-syntax-jsx babel-plugin-transform-vue-jsx babel-helper-vue-jsx-merge-props babel-preset-en   --save-dev

    .babelrc:
        {
            "presets": ["env"],
            "plugins": ["transform-vue-jsx"]
        }

    https://github.com/vuejs/babel-plugin-transform-vue-jsx


五、vue键盘事件不起作用

    @keyup.enter.native="login"   // 如果不加.native是不起作用有


六、$nextTick 页面某一块数据渲染完成后在执行其它操作

    queryBindBank(){
        let that = this;

        common.ajax({
            url: '/business/web/v1/paytool/payCardList',
            method: 'post',
            data: {},
            dataType: 'json',
            success: function(res) {
                that.showLoading = false;
                if (res && res.data) {

                    // 渲染数据表
                    that.bindBankData = res.data.list;

                    // 需要数据表渲染完后在执行其它操作
                    that.$nextTick(function(){
                        cardList.forEach(function(item, idx, arr){                    
                            if(item.designAbled){
                                that.$refs.multipleTable.toggleRowSelection(item);
                            }
                        })
                    })

                    that.bindBankData.forEach((bank, idx, arr) => {
                        if(bank.designAbled){
                            that.selectedRadio = bank.bankCard;
                        }
                    })
                }
      }
        });
    }

| http://www.jianshu.com/p/95b2caf7e0da // vue-cli
| http://cn.vuejs.org/guide/ // Vue中文官网
| https://github.com/vuejs/vue // github
| http://vuefe.cn/guide/installation.html // 2.0
| http://router.vuejs.org/zh-cn/ // vue-router2.0
| https://github.com/vuejs // Vue组件列表
| http://www.cnblogs.com/dh-dh/p/5606596.html // binding原理,vue的数据
| https://github.com/vuejs/awesome-vue#libraries--plugins
| http://vuex.vuejs.org/zh-cn/ // Vuex 2.0文档
| https://github.com/vuejs/vuex/blob/1.0/docs/zh-cn/intro.md
| http://www.cnblogs.com/keepfool/category/845804.html
| http://www.jianshu.com/p/f8e21d87a572
| https://github.com/pablohpsilva/vuejs-component-style-guide/blob/master/README-CN.md#%E5%9F%BA%E4%BA%8E%E6%A8%A1%E5%9D%97%E5%BC%80%E5%8F%91 // Vue代码规范
| https://juejin.im/book/5a36661851882538e2259c0f/section/5a37bbb35188257d167a4d64 源码