基本上是按照官網的Guide 全部梳理了一遍:http://vuejs.org/guide/index.html 這裡我們以一個Todo List 應用為例來把相關的只是都串起來,這篇裡面的全部代碼都在github上 https://github.com/lihongxun945/vue-todolist
Vue 實例
一個Vue 應用是由一個root vue instance 開機啟動的,而Vue instance 是這麼創建的:instance 是這麼一個創的: instance 其實就是MVVM 中的一個VM。 傳入的設定物件中data裡的所有屬性都會被掛載到 instance上,而為了避免命名衝突,Vue 內建方法都會以 $ 開頭的屬性掛載到 instance 上。
instance 從創建到銷毀會經歷如下生命週期:
在初始化的時候大致經過三步:
•綁定資料監聽,即對data 的監聽•編譯模板
•插入document或替換對應dom🎠 Vue 基本語法
資料綁定
Vue 使用的是一種類別mastache 語法。常用綁定語法分這麼幾類:
•mastache 語法,如{{ data }} {{ data | filter}}
• v-on 綁定事件, 例如v-on:click, v-on:submit
其中v-* 都是directive
範例:
屬性計算
Vue 支援一個很有趣的屬性計算語法,可以指定一個屬性由其他屬性計算出來,這樣就不用透過$watch 來實現了:
var vm = new Vue({ // options })## 流程# 流程#控制和清單相關的語法包括`v-if`, `v-show`, `v-else`, `v-for`
表單
雙向資料綁定:
## 動畫動畫的實作方式和Angular 以及React 都是一樣的,都是透過新增和刪除class 來實現的。 # Component
元件的基本使用
Component 的定義包括兩個部分:
var vm = new Vue({ el: '#example', data: { a: 1 }, computed: { // a computed getter b: function () { // `this` points to the vm instance return this.a + 1 } } })2 註冊一個名稱:
var Profile = Vue.extend({ template: "<div> Lily </div>" });
;
這樣我們就可以透過tagname 來使用這麼元件了:
<div id="todo"> <my-profile></my-profile> <form v-on:submit="add" v-on:submit.prevent> <input type="text" v-model="input"/> <input type="submit" value='add' /> </form> ... </div>
var vm = new Vue({ el: "#todo", components: { "my-profile": Profile }, ... }其中因為我們的Vue 實例是綁定在todo 元素上的,所以如果把my-profile 放在這個元素外面是無效的,只有放在這個裡面才會被Vue 的這個實例引導初始化。 注意事項:
Vue 構造函數可以傳的參數基本上可以用在Vue.extend 上,但是對el 和data 兩個參數需要注意,為了避免不同實例間共享同一個對象,總是要通過function 回傳一個新的物件比較可靠:
var MyComponent = Vue.extend({ data: function () { return { a: 1 } } })
因為參數都一樣,其實他們兩個就是同一個東西,不過一個是元件,一個是用來引導Vue啟動的。
<table> <tr is="my-component"></tr> </table>Props 傳遞資料在Vue 中每個元件都是獨立的,不能也不應該直接存取父類別的data。所以我們透過 props 來向子元件傳遞數據,是不是跟 React 的方式很像? 不同於React,在Vue 中子元件需要先宣告自己的props 才行:
var Profile = Vue.extend({ props: ["name"], template: ` <h2>{{name}}'s Todo List</h2> <h4>{{name}} is a good girl</h4> ` });然後我們可以在使用Profile 的時候這樣傳遞參數:
這種是透過字面量傳遞參數,所以傳遞的值一定是字串。還有一種方式是動態傳參,透過v-bind 來傳遞參數,可以雙向綁定資料或傳非字串參數:
Vue 還可以明確指定單向還是雙向的資料綁定:
<!-- default, one-way-down binding --> <child :msg="parentMsg"></child> <!-- explicit two-way binding --> <child :msg.sync="parentMsg"></child> <!-- explicit one-time binding --> <child :msg.once="parentMsg"></child>
var Profile = Vue.extend({ input: { type: String } });父子組件通訊
上面讲到的 props 其实就是父组件向子组件传递消息的一种方式。
在子组件中有一个 this.$parent 和 this.$root 可以用来方法父组件和根实例。不过,现在我们应该避免这么做。因为组件本身就是为了封装独立的逻辑,如果又去直接访问父组件的数据就破坏了组件的封装性。
所以我们应该还是应该通过父组件向子组件传递 props 的方式来通信。
当然 props 其实只能做回调。在 React 中就探讨过这个问题,React 的做法就是通过 props 来做,传一个回调函数给子组件。其实我不是很喜欢这种把回调函数传来传去的方式,我更喜欢的是事件的方式。Vue 中子组件可以通过通过事件和父组件进行通信的。向父组件发消息是通过 this.$dispatch,而向子组件发送消息是通过 this.$boardcast,这里都是向所有的父亲和孩子发送消息,但是一旦执行一个回调之后就会停止,除非这个回调函数显式返回了 true。
我们把之前的Todo List拆成不同的组件来实现,这样可以体验下如何进行组件的双向通信,我们拆分出两个组件,分别是 List 和 Form 。
Form 负责处理用户输入,并在提交表单的时候向父组件发送一个 add 消息,代码如下:
var Form = Vue.extend({ props: { username: { type: String, default: "Unnamed" } }, data: function() { return { input: "", }; }, template: ` <h1>{{username}}'s Todo List</h1> <form v-on:submit="add" v-on:submit.prevent> <input type="text" v-model="input"/> <input type="submit" value='add' /> </form> `, methods: { add: function() { this.$dispatch("add", this.input); //这里就是向父组件发送消息 this.input = ""; } } });
List 只负责展示列表和处理用户勾选操作,它接收到 add 消息之后会在自己上添加一个条目:
var List = Vue.extend({ template: ` <ul> <li v-for='todo in list'> <label v-bind:class="{ done : todo.done }" > <input type="checkbox" v-model="todo.done"/> {{todo.title}} </label> </li> </ul>`, props: { initList: { type: Array } }, data: function() { return { list: [] } }, events: { add: function(input) { if(!input) return false; this.list.unshift({ title: input, done: false }); } } });
然后,因为这是两个组件,当然需要一个 Vue 实例来引导启动,我们的实例如下:
var vm = new Vue({ el: "#todo", components: { "todo-form": Form, "todo-list": List }, events: { add: function(input) { this.$broadcast("add", input); } } });
注意,其实 Form 和 List 在逻辑上是平级的组件,所以他们没有父子关系,他们共同都是 vm 的孩子。这里 vm 接到 Form 的消息之后会转发给 List。
html 代码就更简单了:
<div id="todo"> <todo-form username='Lily'></todo-form> <todo-list></todo-list> </div>
Slot
通过 Slot 可以实现把父组件渲染出来的HTML插入到子组件中,目前还不清楚什么时候会需要这样做,而且这么做对子组件的侵入性太大。
动态切换组件
这个功能感觉有点多余,感觉很多情况下我们应该是通过逻辑代码来实现切换,而不是通过Vue内置的动态组件来切换。不过用来实现一个类似 tab 切换的功能还是很方便的。
我们这里给 Todo List 增加一个 about 页面。那么首先我们需要把 vm 改成一个组件,这个组件叫 Todo,它就是整个 Todo 页面:
var Todo = Vue.extend({ template: ` <div id="todo"> <todo-form username='Lily'></todo-form> <todo-list></todo-list> <slot>not show</slot> </div> `, components: { "todo-form": Form, "todo-list": List }, events: { add: function(input) { this.$broadcast("add", input); } } });
其实改动就第一行。
然后我们需要创建一个 About 组件:
var About = Vue.extend({ template: ` <div id="about"> <p>About Todo List V0.1.0</p> <p>Content here</p> </div>` });
接下来是重点了,我们要创建一个实例 vm,这vm要负责切换这两个页面:
var vm = new Vue({ el: "body", data: { currentView: "todo" }, components: { "todo": Todo, "about": About } });
这里我们定义了一个 currentView 字段,当然可以是任意名称,然后通过特殊的 component 标签来进行组件切换:
<component :is="currentView"></component> <ul> <li><label><input type="radio" name='page' value='todo' v-model='currentView'> Home</label></li> <li><label><input type="radio" name='page' value='about' v-model='currentView'> About</label></li> </ul>
上面的代码有两处需要注意:
•通过 component这个特殊标签,然后用 :is 属性来进行组件的切换。
•radio 通过双向绑定来修改 currentView 字段,从而实现点击之后就可以进行切换。
数据绑定的实现原理
Vue 把双向绑定称作 reactive,可以翻译为响应式数据绑定。内部是通过 ES5 定义的 getter 和 setter 方法实现的,所以不支持 IE8 及以下浏览器,这种实现方式有两个容易犯错的地方:
•如果在 data 上直接添加和删除属性是无法被检测到的,一般删除是不会的,但是可能会动态添加,这个时候应该通过 vm.$set(“name”, value) 的方式来添加。
•无法检测到对象内部的变化,也就是只能检测 data 的属性变化,如果 data.a 是一个对象,那么 data.a.b = 1 这种变化是无法被检测到的。这种情况下应该创建一个新的对象并赋值给 data.a 就行了。
异步更新机制
Vue 对DOM的更新是异步的! 这个异步是在一个异步队列中进行的,不过这个异步队列会在当前的 Event Loop 中执行完,所以如果修改了 Data 立刻去DOM中做查询操作是不对的,这个时候DOM还没有更新,正确的做法是这样做:
vm.msg = 'new message' // change data vm.$el.textContent === 'new message' // false Vue.nextTick(function () { vm.$el.textContent === 'new message' // true })
或者这样:
vm.$nextTick(function () { this.$el.textContent === 'new message' // true })
花了半天时间才看完组件,下面应该去看一下另一个重点: Directive
本文已被整理到了《Vue.js前端组件学习教程》,欢迎大家学习阅读。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持PHP中文网。
更多X深入探讨Vue.js组件和组件通信相关文章请关注PHP中文网!