Vue.js专区javaScritp程序员

Vue.js

2018-06-23  本文已影响4人  DragonRat

作者:烨竹

本文参考:
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、
加速组件编译

上一篇下一篇

猜你喜欢

热点阅读