vue是法语中视图的意思,Vue.js是一个轻巧、高性能、可组件化的MVVM库。 MV*可能大家都经常听说,我们先来理解一下MV*的概念。
MVC开始是存在于桌面程序中的,但由于后端的mvc框架的v层越来越重,后端的MVC思想就搬移到了前端。随着前端代码越来越重,能力越来越大,重前端的系统越来越多地涌现出来。前端为主的MV*时代中,前端在MVC的结构指导下分为model(模型), view(视图), controller(控制器)三部分。而controller慢慢演化为presenter和viewmodel。MVC, MVP, MVVM框架不断涌现。
MVC(model-view-controller),如backbone, angular(较高版本是mvvm, 也许说它是MVW更准确)。 View: 与页面上元素直接相关的部分,包括html,CSS和一部分直接控制页面元素的JS。它可以从Model中得到数据,并将其显示到页面上。 Model: 与后端的沟通、AJAX请求以及对数据的处理。Model本身不知道谁是View,谁是Controller。它只提供一些方法供View和Controller调用,并且将变更通知给它的观察者。 Controller: Model和View的粘合剂。Controller将View方面的请求转发给合适的Model,作为Model的观察者,获取Model的变更,在必要时更新View。
MVP(model-view-presenter)使用此模型的框架不多,现在几乎倒向MVVM。MVP 模式将 Controller 改名为 Presenter,同时改变了通信方向。 Presenter,与Controller一样,接收View的命令,对Model进行操作;与Controller不同的是Presenter会反作用于View,Model的变更通知首先被Presenter获得,然后Presenter再去更新View。
MVVM(model-view-viewmodel)如Vue.js。将Controller改为ViewModel。它与MVP的区别是,它采用双向绑定(data-binding):View的变动,自动反映在ViewModel。 下图来自对MVC、MVP、MVVM的理解,清晰地说明它们之间的区别下图是vue.js官网上的双向绑定的小例子。首先是VM -> V,VM中的data里的message变化,会自动反映在V中的p标签里大括号内的message;V -> VM,V中input里输入的值,会自动反映到VM中的message值。所以,你在输入框中输入的文字会被实时显示成上方的文字。
安装步骤vue.js官网上介绍得十分清楚。这里我推荐先安装淘宝镜像,再进行安装Vue.js官方命令行工具,这样会更快。
1 2 3 4 5 6 7 8 9 10 # 全局安装 cnpm淘宝镜像 $ npm install -g cnpm --registry=https://registry.npm.taobao.org # 全局安装 vue-cli $ cnpm install -g vue-cli # 创建一个基于 "webpack" 模板的新项目 $ vue init webpack my-project # 安装依赖,走你 $ cd my-project $ cnpm install $ npm run dev用法:在表单控件(<input>、<select>、<textarea>)上创建双向绑定。 例子:输入框中初始化文字是”hello vue.js”,而你在输入框中输入的文字会被实时显示成上方的文字。
1 2 3 4 <div id="app"> <p>{{newItem}} </p> <input v-model="newItem"/> </div> 1 2 3 4 5 6 new Vue({ el: '#app', data: { newItem: 'hello vue.js.' } });用法:基于源数据将元素或模板块重复数次,简单来说就是列表渲染。如果之前学过Angular会觉得很相似。 例子:会显示列表,列表中有”No.1”、”No.2”。
1 2 3 4 5 <ul> <li v-for="item in items"> {{item.label}} </li> </ul> 1 2 3 4 5 6 7 8 9 10 new Vue({ el: '#app', data: { newItem: 'hello vue.js.', items: [ {label: "No.1",isFinished: false}, {label: "No.2",isFinished: true} ] } });用法:绑定事件监听器。事件类型由参数指定。表达式可以是一个方法的名字或一个内联语句,如果没有修饰符(如.stop、.prevent等)也可以省略。 例子:<li>标签上绑定了点击事件,每次点击会改变item的isFinished属性。v-on:click可以缩写成@click。
1 2 3 4 5 <ul> <li v-for="item in items" v-on:click="toggleFinish(item)"> {{item.label}} </li> </ul> 1 2 3 4 5 6 7 new Vue({ methods: { toggleFinish: function(item) { item.isFinished = !item.isFinished } } });用法:动态地绑定一个或多个 attribute,或一个组件prop到表达式。在绑定 class 或 style 时,支持其它类型的值,如数组或对象;在绑定 prop 时,prop 必须在子组件中声明。可以用修饰符指定不同的绑定类型。 例子:如果<li>的数据item.isFinished是true,<li>的class就是finished,文字颜色就会变成#ccc。v-bind:class可以缩写成:class。
1 2 3 4 5 <ul> <li v-for="item in items" v-bind:class="{finished: item.isFinished}" v-on:click="toggleFinish(item)"> {{item.label}} </li> </ul> 1 2 3 .finished { color: #ccc; }例子:App.vue为父,引入componetA组件之后,则可以在template中使用标签(注意驼峰写法要改成componet-a写法,因为html对大小写不敏感,componenta与componentA对于它来说是一样的,不好区分,所以使用小写-小写这种写法)。而子组件componetA中,声明props参数’msgfromfa’之后,就可以收到父向子组件传的参数了。例子中将msgfromfa显示在<p>标签中。 App.vue中
1 <component-a msgfromfa="(Just Say U Love Me)"> </component-a> 1 2 3 4 5 6 7 8 import componentA from './components/componentA' export default { new Vue({ components: { componentA } }) }componentA.vue中
1 <p>{{ msgfromfa }} </p> 1 2 3 export default { props: [ 'msgfromfa'] }用法:vm.$broadcast( event, […args] )广播事件,通知给当前实例的全部后代。因为后代有多个枝杈,事件将沿着各“路径”通知。 例子:父组件App.vue中<input>绑定了键盘事件,回车触发addNew方法,广播事件”onAddnew”,并传参this.items。子组件componentA中,注册”onAddnew”事件,打印收到的参数items。 App.vue中
1 2 3 <div id="app"> <input v-model="newItem" @keyup.enter="addNew"/> </div> 1 2 3 4 5 6 7 8 9 10 import componentA from './components/componentA' export default { new Vue({ methods: { addNew: function() { this.$broadcast( 'onAddnew', this.items) } } }) }componentA.vue中
1 2 3 4 5 6 7 8 import componentA from './components/componentA' export default { events: { 'onAddnew': function(items){ console.log(items) } } }用法:vm.$emit( event, […args] ),触发当前实例上的事件。附加参数都会传给监听器回调。 例子:App.vue中component-a绑定了自定义事件”child-say”。子组件componentA中,单击按钮后触发”child-say”事件,并传参msg给父组件。父组件中listenToMyBoy方法把msg赋值给childWords,显示在<p>标签中。 App.vue中
1 2 <p>Do you like me? {{childWords}} </p> <component-a msgfromfa="(Just Say U Love Me)" v-on:child-say="listenToMyBoy"> </component-a> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import componentA from './components/componentA' export default { new Vue({ data: function () { return { childWords: "" } }, components: { componentA }, methods: { listenToMyBoy: function (msg){ this.childWords = msg } } }) }componentA.vue中
1 <button v-on:click="onClickMe">like! </button> 1 2 3 4 5 6 7 8 9 10 11 12 13 import componentA from './components/componentA' export default { data: function () { return { msg: 'I like you!' } }, methods: { onClickMe: function(){ this.$emit( 'child-say', this.msg); } } }用法:vm.$dispatch( event, […args] ),派发事件,首先在实例上触发它,然后沿着父链向上冒泡在触发一个监听器后停止。 例子:App.vue中events中注册”child-say”事件。子组件componentA中,单击按钮后触发”child-say”事件,并传参msg给父组件。父组件中”child-say”方法把msg赋值给childWords,显示在<p>标签中。 App.vue中
1 2 <p>Do you like me? {{childWords}} </p> <component-a msgfromfa="(Just Say U Love Me)"> </component-a> 1 2 3 4 5 6 7 8 9 10 import componentA from './components/componentA' export default { new Vue({ events: { 'child-say' : function(msg){ this.childWords = msg } } }) }componentA.vue中
1 <button v-on:click="onClickMe">like! </button> 1 2 3 4 5 6 7 8 9 10 11 12 13 import componentA from './components/componentA' export default { data: function () { return { msg: 'I like you!' } }, methods: { onClickMe: function(){ this.$dispatch( 'child-say', this.msg); } } }这里只提及了一些指令,更多功能建议在官网上刷一遍API文档。
用以上的指令写一个简单的demo。实现添加事情,删除事情,点击事情表示事情已完成,点赞等功能。代码思路源自慕课网教程,我作了一些修改。 详细代码如下:
完成后如下图: