Vue.js

作者: DragonRat | 来源:发表于2018-06-23 19:01 被阅读4次

    作者:烨竹

    本文参考:
    https://vuejs.org/v2/guide/list.html
    http://www.runoob.com/vue2/vue-forms.html

    Vue.js(读音 /vjuː/, 类似于 view)是一个构建数据驱动的 web 界面的库。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件
    生命周期详解:https://blog.csdn.net/qq_25186543/article/details/79470184

    基本语法:

    一、结构:
    Vue.js 是个专注在视图层(View) 的框架,帮助开发者切分前端的资料状态和运作逻辑;(类似土豆变葡萄,土豆是一个整体,而葡萄想吃哪部分都容易,由你决定各自独立运作或是相连)


    葡萄自然有个供应养分的起始点,也就是根。让我们三秒看完长怎样

    //挂载点为#app,内容为data里面的内容
    <div id="app">
        {{ message }}
    </div>
    
    <script>
    var app = new Vue({
        el: '#app',
        data: {
            message: 'Hello Vue!'
        }
    });
    </srcipt>
    

    我们可以从根向下延伸,长出更多颗葡萄,这一个个葡萄皆可个别定义,称为元件(Component)。
    下面例子加了menu 和description 两个元件

    <div id="app">
        {{ message }}
        <menu-section></menu-section>
        <description-section></description-section>
    </div>
    
    <script>
    var app = new Vue({
        el: '#app',
        data: {
            message: 'Hello Vue!'
        },
        components: {
            'menu-section': {
                template: '<ul><li v-for="item in menuItems">{{ item.text }}</li></ul>',
                data: function() {
                    return {
                        menuItems: [{
                            text: 'About me'
                        }, {
                            text: 'Articles'
                        }, {
                            text: 'contact'
                        }]
                    }
                }
            },
            'description-section': {
                template: '<p>{{ text }}</p>',
                data: function() {
                    return {
                        text: 'Hello, I am Ralph.'
                    }
                }
            }
        }
    });
    </script>
    

    二、写法(两种)
    1.直接引入Vue.js(template与html混编)

    //<menu-section>为例
    <body>
        <div id="app">
            {{ message }}
            <menu-section></menu-section>
        </div>
        
        <template id="menuTemplate">
            <ul>
                <li v-for="item in menuItems">{{ item.text }}</li>
            </ul>
        </template>
        
        <script>
            var app = new Vue({
                el: '#app',
                data: {
                    message: 'vue rock!'
                },
                /* 局部註冊 (Local Registration) */
                components: {
                    'menu-section': {
                        template: '#menuTemplate', /* 樣板選取器 */
                        data: function() {
                        return {
                            menuItems: [{
                                text: 'About me'
                            }, {
                                text: 'Articles'
                            }, {
                                text: 'contact'
                            }]
                        }
                     }
                  }
                }
            })
        </script>
    </body>
    

    2.透过Vue-loader 编译(官方工具Vue-cli)

    /* Menu.vue */
    <template>
        <ul>
            <li v-for="item in menuItems">{{ item.text }}</li>
        </ul>
    </template>
    
    <script>
    export default {
        data: function() {
            return {
                menuItems: [{
                text: 'About me'
              }, {
                text: 'Articles'
              }, {
                text: 'contact'
              }]
           }
       }
    }
    </script>
    
    <style>
    /* 樣式也可以包進來 ._. */
    .original-white {
        color: #fff;
    }
    </style>
    
    //使用官方工具Vue-cli,透过几行指令生成基本的专案环境
    # 全域安装 vue-cli,當成系統命令用
    $ npm install --global vue-cli
    
    # 建立webpack樣板專案
    $ vue init webpack my-project
    # 若你剛開始學或不需要測試,簡化版本比較好懂
    $ vue init webpack-simple my-project
    
    # 安裝所需模組
    $ cd my-project
    $ npm install
    
    # 開啟 http server
    $ npm run dev
    

    三、挂载点(Vue Instance)

    const vm = new Vue({
        el: 'app',             /* 掛載點 */
        data: { /* ... */ },   /* 初始資料 */
        methods: { /* ... */}, /* 方法 */
    });
    

    四、资料绑定(模板相关语法)

        <!-- 文字绑定 -->
        <p>{{ msg }}</p>
        
        <!-- 单次绑定 (仅更新一次) -->
        <p v-once>{{ msg }}</p>
        
        <!-- 把內容當成 HTML 解析 -->
        <p v-html="raw_html"></p>
        
        <!-- 属性綁定 -->   
        <a href="{{ pageLink }}"></a>
        <a v-bind:href="pageLink"></a>
        
        <div v-bind:id="dynamicId"></div>
        <button v-bind:disabled="isDisabled">Submit</button>
        
        <!-- 缩写 -->
        <a :href="pageLink"></a>
        <div :id="dynamicId"></div>
        <button :disabled="isDisabled">Submit</button>
        
        <!-- Filters 过滤器 -->
        {{ data | json }}
        {{ username | capitalize }}
    

    五、指令
    1.样式套用
    能取到的Vue属性都能当作传入参数(v-bind)
    i.绑定Class

    ①.简单

    //基本写法以JSON传入,当对应的数值为true时套用,false时移除该类别
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
    <script src="https://cdn.bootcss.com/vue/2.2.2/vue.min.js"></script>
    <style>
    .active {
        width: 100px;
        height: 100px;
        background: green;
    }
    </style>
    </head>
    <body>
    <div id="app">
      <div v-bind:class="{ active: isActive }"></div>
    </div>
    
    <script>
    new Vue({
      el: '#app',
      data: {
        isActive: true
      }
    })
    </script>
    </body>
    </html>
    

    ②、复杂(class并非固定,可改用Array传入)

    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
    <script src="https://cdn.bootcss.com/vue/2.2.2/vue.min.js"></script>
    <style>
    .text-danger {
        width: 100px;
        height: 100px;
        background: red;
    }
    .active {
        width: 100px;
        height: 100px;
        background: green;
    }
    </style>
    </head>
    <body>
    <div id="app">
        <div v-bind:class="[errorClass ,isActive ? activeClass : '']"></div>
    </div>
    
    <script>
    new Vue({
      el: '#app',
      data: {
        isActive: true,
        activeClass: 'active',
        errorClass: 'text-danger'
      }
    })
    </script>
    </body>
    </html>
    

    ii、绑定inline-style

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
    <script src="https://cdn.bootcss.com/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="app">
      <div v-bind:style="[baseStyles, overridingStyles]">菜鸟教程</div>
    </div>
    
    <script>
    new Vue({
      el: '#app',
      data: {
        baseStyles: {
          color: 'green',
          fontSize: '30px'
        },
        overridingStyles: {
          'font-weight': 'bold'
        }
      }
    })
    </script>
    </body>
    </html>
    

    2.条件显示
    UI流程常有特定情况才出现/隐藏DOM 或Component 的需求,Vue 对应写法是
    v-if / v-show
    v-else
    v-else-if

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
    <script src="https://cdn.bootcss.com/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="app">
        <div v-if="type === 'A'">
          A
        </div>
        <div v-else-if="type === 'B'">
          B
        </div>
        <div v-else-if="type === 'C'">
          C
        </div>
        <div v-else>
          Not A/B/C
        </div>
    </div>
        
    <script>
    new Vue({
      el: '#app',
      data: {
        type: 'a'
      }
    })
    </script>
    </body>
    </html>
    

    v-if,v-show区别
    v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——在条件第一次变为真时才开始局部编译(编译会被缓存起来)
    相比之下,v-show 简单得多——元素始终被编译并保留,只是简单地基于 CSS 切换。
    一般来说,v-if 有更高的切换消耗而 v-show 有更高的初始渲染消耗。因此,如果需要频繁切换 v-show 较好,如果在运行时条件不大可能改变 v-if 较好
    3、列表渲染( v-for又称循环语句)

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
    <script src="https://cdn.bootcss.com/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="app">
      <ul>
        <template v-for="site in sites">
          <li>{{ site.name }}</li>
          <li>--------------</li>
        </template>
      </ul>
    </div>
    
    <script>
    new Vue({
      el: '#app',
      data: {
        sites: [
          { name: 'Runoob' },
          { name: 'Google' },
          { name: 'Taobao' }
        ]
      }
    })
    </script>
    </body>
    </html>
    
    //对象
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
    <script src="https://cdn.bootcss.com/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="app">
      <ul>
        <li v-for="(value, key, index) in object">
         {{ index }}. {{ key }} : {{ value }}
        </li>
      </ul>
    </div>
    
    <script>
    new Vue({
      el: '#app',
      data: {
        object: {
          name: '菜鸟教程',
          url: 'http://www.runoob.com',
          slogan: '学的不仅是技术,更是梦想!'
        }
      }
    })
    </script>
    </body>
    </html>
    
    //整数
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
    <script src="https://cdn.bootcss.com/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="app">
      <ul>
        <li v-for="n in 10">
         {{ n }}
        </li>
      </ul>
    </div>
    
    <script>
    new Vue({
      el: '#app'
    })
    </script>
    </body>
    </html>
    

    4、事件处理(v-on)

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
    <script src="https://cdn.bootcss.com/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="app">
      <button v-on:click="say('hi')">Say hi</button>
      <button v-on:click="say('what')">Say what</button>
    </div>
    
    <script>
    new Vue({
      el: '#app',
      methods: {
        say: function (message) {
          alert(message)
        }
      }
    })
    </script>
    </body>
    </html>
    

    5、表单输入绑定( v-model )

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
    <script src="https://cdn.bootcss.com/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="app">
      <p>input 元素:</p>
      <input v-model="message" placeholder="编辑我……">
      <p>消息是: {{ message }}</p>
        
      <p>textarea 元素:</p>
      <p style="white-space: pre">{{ message2 }}</p>
      <textarea v-model="message2" placeholder="多行文本输入……"></textarea>
    </div>
    
    <script>
    new Vue({
      el: '#app',
      data: {
        message: 'Runoob',
        message2: '菜鸟教程\r\nhttp://www.runoob.com'
      }
    })
    </script>
    </body>
    </html>
    
    //复选框
    <div id="app">
      <p>单个复选框:</p>
      <input type="checkbox" id="checkbox" v-model="checked">
      <label for="checkbox">{{ checked }}</label>
        
      <p>多个复选框:</p>
      <input type="checkbox" id="runoob" value="Runoob" v-model="checkedNames">
      <label for="runoob">Runoob</label>
      <input type="checkbox" id="google" value="Google" v-model="checkedNames">
      <label for="google">Google</label>
      <input type="checkbox" id="taobao" value="Taobao" v-model="checkedNames">
      <label for="taobao">taobao</label>
      <br>
      <span>选择的值为: {{ checkedNames }}</span>
    </div>
    

    六、过滤器
    2.0版本中,过滤器只用于插入文本中({{}})

    {{ message | capitalize }}
    

    自定义过滤器

    <template>
        <div>
            <input v-model="filterText"/>
           <ul>
               <li v-for="item in obj">
                   <span>{{myfilter(item.label)}}</span>
               </li>
           </ul>
        </div>
    </template>
    <script>
        export default {
            data: function () {
                return{
                    obj:[
                        {value:0,label:"男子十年盗窃被抓9次"},
                        {value:1,label:"中国人拯救地球"},
                        {value:2,label:"张艺谋电影"},
                        {value:3,label:"科幻电影排行榜"},
                        {value:4,label:"香港武打片电影"},
                        {value:5,label:"zhangwenwu的博客"}
                    ],
                    filterText:""
                }
            },
            methods:{
                myfilter(value){
                    if(value.indexOf(this.filterText)>-1){
                        return value
                    }
                }
            }
        };
    </script>
    

    七、Watch
    简单理解:我们希望变数改变时,也有人叫对应的处理器起床做事,这就是Watch 的用途

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
        <script src="https://cdn.bootcss.com/vue/2.4.2/vue.min.js"></script>
    </head>
       <body>
          <div id = "computed_props">
             千米 : <input type = "text" v-model = "kilometers">
             米 : <input type = "text" v-model = "meters">
          </div>
           <p id="info"></p>
          <script type = "text/javascript">
             var vm = new Vue({
                el: '#computed_props',
                data: {
                   kilometers : 0,
                   meters:0
                },
                methods: {
                },
                computed :{
                },
                watch : {
                   kilometers:function(val) {
                      this.kilometers = val;
                      this.meters = val * 1000;
                   },
                   meters : function (val) {
                      this.kilometers = val/ 1000;
                      this.meters = val;
                   }
                }
             });
             // $watch 是一个实例方法
            vm.$watch('kilometers', function (newValue, oldValue) {
                // 这个回调将在 vm.kilometers 改变后调用
                document.getElementById ("info").innerHTML = "修改前值为: " + oldValue + ",修改后值为: " + newValue;
            })
          </script>
       </body>
    </html>
    

    八、计算属性(computed)
    特性:当我们定义一个computed,其相依data 一变,computed 也会随之更新。好处:收纳Template中的逻辑

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
    <script src="https://cdn.bootcss.com/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="app">
      {{ message.split('').reverse().join('') }}
    </div>
    
    <script>
    new Vue({
      el: '#app',
      data: {
        message: 'Runoob!'
      }
    })
    </script>
    </body>
    </html>
    

    computed vs methods
    computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值;而使用 methods (其相依的data改变,computed也随之更新),在重新渲染的时候,函数总会重新调用执行

    九、组件(Component)
    使用组件有三个步骤:宣告建构子(Constructor);注册组件(Regist Component) (建立组件(Create Component));挂载组件(Mount Component)
    1、注册(组件存在意义是为了拆解逻辑、使得结构清晰好懂)
    全局组件:所有实例都能用全局组件

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
    <script src="https://cdn.bootcss.com/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="app">
        <runoob></runoob>
    </div>
    
    <script>
    // 注册
    Vue.component('runoob', {
      template: '<h1>自定义组件!</h1>'
    })
    // 创建根实例
    new Vue({
      el: '#app'
    })
    </script>
    </body>
    </html>
    

    局部组件

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Vue 测试实例 - 菜鸟教程(runoob.com)</title>
    <script src="https://cdn.bootcss.com/vue/2.2.2/vue.min.js"></script>
    </head>
    <body>
    <div id="app">
        <runoob></runoob>
    </div>
    
    <script>
    var Child = {
      template: '<h1>自定义组件!</h1>'
    }
    
    // 创建根实例
    new Vue({
      el: '#app',
      components: {
        // <runoob> 将只在父模板可用
        'runoob': Child
      }
    })
    </script>
    </body>
    </html>
    

    Vue.extend

    <div id="app1">
        <menu-section></menu-section>
    </div>
    <div id="app1">
        <my-menu></my-menu>
    </div>
    
    <script>
    var MenuItem = Vue.extend({
        template: '<ul><li v-for="item in menuItems">{{ item.text }}</li></ul>',
        data: function() {
            return {
                menuItems: [{
                    text: 'About me'
                }, {
                    text: 'Articles'
                }, {
                    text: 'contact'
                }]
            };
        }
    });
    
    var app1 = new Vue({
        el: '#app1'
        components: {
            'menu-section': MenuItem
        }
    });
    var app2 = new Vue({
        el: '#app2',
        components: {
            'my-menu': MenuItem
        }
    });
    </script>
    

    2、prop
    原本功能间的协同运作都在同一层,拆成组件后,变成各个独立的状态了,我们仍然需要维持彼此间沟通畅通,如同所有漂亮的JavaScript 模组一样,需要订出漂亮的对外介面(Interface),使其改动内部逻辑的同时,又不失其重用性(环保可回收),方便传入外部资料;官方建议使用props down, events up,透过prop传入资料、透过组件事件(event)传递消息,template用于呈现资料

    对上图的解释:
    右边:data (宣告内部状态);props (宣告对外介面- 用于传入资料);prop:接收父组件传递的值;
    左边:自用,$emit (组件内的事件);对外,$broadcast (父对子,向下传递),$dispatch (子对父,向上传递)

    <div id="counter-event-example">
      <p>總來客量: {{ total }}</p>
      <button-counter door="前門" v-on:increment="incrementTotal"></button-counter>
      <button-counter door="後門" v-on:increment="incrementTotal"></button-counter>
        <!-- 來客數不計算工作人員 -->
      <button-counter door="工作人員專用門"></button-counter>
    </div>
    
     <script src="vue.min.js"></script>
    
     <script type="text/javascript">
    Vue.component('button-counter', {
      template: '<button v-on:click="increment">{{ door }}來客+1 ( {{ counter }} )</button>',
      props: ['door'],
      data: function () {
        return {
          counter: 0
        }
      },
      methods: {
        /* 來客+1 */
        increment: function () {
          this.counter += 1
          /* 通知主任,多了一人來客 */
          this.$emit('increment')
        }
      },
    })
    new Vue({
      el: '#counter-event-example',
      data: {
        total: 0
      },
      methods: {
        /* 主任得知來客+1,總來客量+1 */
        incrementTotal: function () {
          this.total += 1
        }
      }
    })
     </script>
    

    template
    要怎么让组件样板具有弹性
    解法一 具名<slot>

    <template>
        <div class="modal fade">
            <div class="modal-dialog" role="document">
                <div class="modal-content">
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
                        <slot name="modal-header">
                    </div>
                    <div class="modal-body">
                        <slot name="modal-body">
                    </div>
                    <div class="modal-footer">
                        <slot name="modal-footer">
                    </div>
                </div><!-- /.modal-content -->
            </div><!-- /.modal-dialog -->
        </div><!-- /.modal -->
    </template>
    
    <modal>
        <h4 slot="modal-header" class="modal-title">Modal title</h4>
        
        <p slot="modal-body">One fine body&hellip;</p>
        
        <button slot="modal-footer" type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
        <button slot="modal-footer" type="button" class="btn btn-primary">Save changes</button>
    </modal>
    

    解法二- inline-template(这种作法会完全覆盖掉<app>原始内容)

    <app inline-template>
      <div>
        <p>These are compiled as the component's own template.</p>
        <p>Not parent's transclusion content.</p>
      </div>
    </app>
    
    <!-- <app>模板原始內容不见了 -->
      <div>
        <p>These are compiled as the component's own template.</p>
        <p>Not parent's transclusion content.</p>
      </div>
    

    3、挂载
    透过模板(template)的基本挂载:

    <script>
    Vue.component('viewer', require('./components/Example.vue'));
    Vue.component('editor', require('./components/Editor.vue'));
    
    var app = new Vue({
        el: '#app',
        data: {
            state: 'viewer'
        },
        methods: {
            toggle: function() {
                return (this.state === 'viewer') ? 'editor' : 'viewer';
            }
        }
    });
    </script>
    

    is屬性动态挂载:

    <div id="app">
        <button type="button" @click="toggle">{{ state }}</button>
        <div is="state"></div>
        <div is="state"></div>
        
        <!-- state: 'viewer' -->
        <!--
        <viewer></viewer>
        <viewer></viewer>
        -->
        
        <!-- state: 'editor' -->
        <!--
        <editor></editor>
        <editor></editor>
        -->
        
    </div>
    

    透过Vue建构子或$mountAPI:

    <!-- 宣告建構子 -->
    var Example = Vue.extend({
     template: '<div>Here is Example</div>'
    });
    
    透过建构子挂载
    <!-- 這會把#app內容完全換掉 -->
    new Example({ el: '#app' })
    
    挂载前的等效样板
    
    <div id="app">
        <example></example>
        <example></example> 
    </div>
    
    挂载后
    
    <div id="app">
        <!-- 前面兩個 <example> 都不見了 -->
        <example></example>
    </div>
    

    给$mount挂载点

    new Example().$mount('#app');
    跟(1)相同,完全换掉#app内容
    

    当你加上新的组件,又不想盖掉原内容,参考这种做法
    4、其他
    i、组件(component)间的其他连结
    ①、$parent/$children/$root
    第一个直接连结是父子组件间的交互参照
    父组件可透过$children直接存取其下一层的子组件。
    子组件可透过$parent直接存取其上一层的父组件。
    不论父子组件都可透过$ root,直接存取最顶层的Vue Instance
    ②、ref属性& $refs
    第二个直接连结是组件的自订索引名- ref,用于父组件对子组件的参照。

    <div id="parent">
      <user-profile ref="profile"></user-profile>
    </div>
    

    定义好的索引名,可以透过父组件的$refs取得

    var parent = new Vue({ el: '#parent' })
    /* 存取子組件 */
    var child = parent.$refs.profile
    

    若是搭配v-for,$refs对应的索引名也会取得阵列/JSON

    <div id="parent">
      <user-profile v-for="user in users" ref="profile"></user-profile>
    </div>
    typeof parent.$refs.profile /* Array */
    

    这个属性在画面渲染完才会更新,资料可能不同步,只适合当备用方案
    ii、
    加速组件编译

    • v-once
      一次性编译,用于不会改变的静态资料
    • v-pre
      跳过不编译,用于不会改变的静态样板

    相关文章

      网友评论

        本文标题:Vue.js

        本文链接:https://www.haomeiwen.com/subject/htfdyftx.html