赞
踩
狂神说
Vue (读音 /vjuː/,类似于 view) 是一套用于构建用户界面的渐进式JavaScript框架。与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue的核心库只关心视图层View,方便与第三方或既有项目整合;
遵循SoC原则关注点分离原则;
HTML + CSS + JS :视图,给用户看,刷新后台给的数据;
网络通信:Axios;
页面跳转:Vue-router
状态管理:Vuex
Vue-UI:ICE,Element UI
LESS
:基于NodeJS,通过客户端处理,使用简单。功能比SASS简单,解析效率也低于SASS,但在实际开发中足够了,所以后台人员如果需要的话,建议使用LESS。JavaScript一门弱类型脚本语言,其源代码在发往客户端运行之前不需经过编译,而是将文本格式的字符代码发送给浏览器由浏览器解释运行;
Native 原生 JS 开发
原生JS开发,也就是让我们按照ECMAScript 标准的开发方式,简称是ES,特点是所有浏览器都支持。截止到当前,ES 标准已发布如下版本:
ES3
ES4 (内部,未征式发布)
ES5 (全浏览器支持)
ES6 (常用,当前主流版本: webpack打包成为ES5支持! )
ES7
ES8
ES9 (草案阶段)
区别就是逐步增加新特性。
TypeScript 微软的标准
JavaScript框架
UI 框架
Ant-Design:阿里巴巴出品,基于React的UI框架
ElementUI、 iview、 ice: 饿了么出品,基于Vue的UI框架
Bootstrap:Twitter推出的一个用于前端开发的开源工具包
AmazeUI:又叫"妹子UI",一款HTML5跨屏前端框架
JavaScript 构建工具
混合开发 Hybrid App
微信小程序
NodeJS
的作者已经声称放弃NodeJS (架构做的不好再加上笨重的node_ modules),开始开发全新架构的Deno;Vue.js
iView
Element UI
ICE
VantUI
AtUI
CubeUI
混合开发
Flutter
lonic
mpvue
WeUI
为了降低开发的复杂度, 以后端为出发点, 比如:Struts、Spring MVC等框架的使用, 就是后端的MVC时代;
优点:
缺点:
前端开发重度依赖开发环境,开发效率低,这种架构下,前后端协作有两种模式:
前后端职责纠缠不清:模板引擎功能强大,依旧可以通过拿到的上下文变量来实现各种业务逻辑。这样,只要前端弱势一点,往往就会被后端要求在模板层写出不少业务代码,还有一个很大的灰色地带是Controller,页面路由等功能本应该是前端最关注的, 但却是由后端来实现。Controller本身与Model往往也会纠缠不清,看了让人咬牙的业务代码经常会出现在Controller层;
对前端发挥的局限性:性能优化如果只在前端做空间非常有限,于是经常需要后端合作,但由于后端框架限制,很难使用Comet、Big Pipe等技术方案来优化性能。
Ajax,Asynchronous JavaScript And XML,异步JavaScript和XML,即老技术新用法。自2005年被提出,并开始使用CDN作为静态资源存储,于是出现了JavaScript王者归来的SPA(Single Page Application)单页面应用时代。
这种模式下的优点在于:前后端分工清晰,前后端的关键协作点是Ajax接口。
但是,这好像与JSP时代区别不大,复杂度从服务端的JSP移到了浏览器的JavaScript,使得浏览器端变得复杂。
因此,类似Spring MVC,开始出现浏览器端的分层结构:
但这种模式也存在一下缺点:
此处的MV*模式如下:
为了降低前端开发复杂度,涌现了大量的前端框架,比如:Angular JS、React、Vue.js、Ember JS等,这些框架总的原则是先按类型分层,比如Templates、Controllers、Models, 然后再在层内做切分,如下图:
优点:
缺点
前端为主的MV*模式解决了很多很多问题, 但如上所述, 依旧存在不少不足之处。随着Node JS的兴起, JavaScript开始有能力运行在服务端。这意味着可以有一种新的研发模式,如下图所示。
在这种研发模式下,前后端的职责很清晰。对前端来说,两个UI层各司其职:
Front-end Ul layer
处理浏览器层的展现逻辑。通过CSS渲染样式, 通过JavaScript添加交互功能, HTML的生成也可以放在这层, 具体看应用场景。Back-end Ul layer
处理路由、模板、数据获取、Cookie等。通过路由, 前端终于可以自主把控URL Design,这样无论是单页面应用还是多页面应用,前端都可以自由调控。后端也终于可以摆脱对展现的强关注,转而可以专心于业务逻辑层的开发通过Node,WebServer层也是JavaScript代码, 这意味着部分代码可前后复用,需要SEO的场景可以在服务端同步渲染,由于异步请求太多导致的性能问题也可以通过服务端来缓解。前一种模式的不足,通过这种模式几乎都能完美解决掉。
与JSP模式相比,全栈模式看起来是一种回归,也的确是一种向原始开发模式的回归,不过是一种螺旋上升式的回归。
基于Node JS的全栈模式, 依旧面临很多挑战:
综上所述,模式也好,技术也罢,没有好坏优劣之分,只有适合不适合;前后端分离的开发思想主要是基于SoC
(关注度分离)原则,上面这种模式,都是让前后端的职责更加清晰,分工更加合理高效。
MVVM(Model-View-ViewModel)是一种软件架构设计模式,由微软WPF(用于替代WinForm,以前就是用这个技术开发桌面应用程序的)和Silverlight(类似于Java Applet,简单说就是在浏览器上运行的WPF)的架构师Ken Cooper和Ted Peters开发,是一种简化用户界面的事件驱动编程方式。由John Gossman(也是WPF和Sliverlight的架构师)与2005年在他的博客上发表。
MVVM源自于经典的MVC(Model-View-Controller)
模式。其核心是ViewModel
层,负责转换Model
中的数据对象来让数据变得更容易管理和使用。其作用如下:
MVVM模式和MVC模式一样,主要目的是分离视图View和模型Model,有以下好处:
低耦合:View可以独立于Model变化和修改,一个ViewModel可以绑定到不同的View上,当View变化的时候Model可以不变,当Model变化的时候View也可以不变;
可复用:可以把一些视图逻辑放在一个ViewModel里面,让很多View重复使用这段视图逻辑;
独立开发:开发人员可以专注于业务逻辑和数据的开发(ViewModel),设计人员可以专注于页面设计;
可测试:界面素来是比较难以测试的,而现在测试就可以针对ViewModel来写。
View
View是视图层,也就是用户界面。前端主要由HTML和CSS来构建,为了更方便地展现vi eu to del或者Hodel层的数据,已经产生了各种各样的前后端模板语言,比如FreeMarker、Thymeleaf等等,各大MVVM框架如Vue.js、Angular JS、EJS等也都有自己用来构建用户界面的内置模板语言。
Model
Model是指数据模型,泛指后端进行的各种业务逻辑处理和数据操控,主要围绕数据库系统展开。难点主要在于需要和前端约定统一的接口规则。
ViewModel
ViewModel是由前端开发人员组织生成和维护的视图数据层。在这一层,前端开发者对从后端获取的Model数据进行转换处理,做二次封装,以生成符合View层使用预期的视图数据模型。
需要注意的是,ViewModel所封装出来的数据模型包括视图的状态和行为两部分,而Model层的数据模型是只包含状态的。
视图状态和行为都封装在了ViewModel里。这样的封装使得ViewModel可以完整地去描述View层。由于实现了双向绑定,ViewModel的内容会实时展现在View层,这是激动人心的, 因为前端开发者再也不必低效又麻烦地通过操纵DOM去更新视图。
MVVM框架已经把最脏最累的一块做好了,开发者只需要处理和维护ViewModel,更新数据视图就会自动得到相应更新,真正实现事件驱动编程。
需要理解的是,View层展现的不是Model层的数据, 而是ViewModel层的数据, 由ViewModel负责与Model层交互,获取和更新数据, 这就完全解耦了View层和Model层, 这个解耦是至关重要的, 它是前后端分离方案实施的重要一环。
Vue是MVVM模式的实现者
在MVVM架构中,是不允许数据和视图直接通信的,只能通过ViewModel来通信,而View Model就是定义了一个Observer观察者:
综上,即Vue.js就是一个MVVM的实现者,其核心是实现了DOM监听与数据绑定。
轻量级、体积小。Vue.js压缩后只有20+Kb
移动优先,更适合移动端
易上手,学习曲线平稳,文档齐全
吸取了Angular模块化和React虚拟DOM的长处,并拥有自己独特的功能,如计算属性
开源、社区活跃度高
在IDEA中安装Vue.js插件
下载
编写代码
创建一个HTML文件demo01.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--View层:模板--> <div id="app"> {{message}} </div> <!--1.导入Vue.js--> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> <script> var vm = new Vue({ /*绑定元素*/ el : "#app", //Model层:数据 data : { message:"Hello,Vue!" } }); </script> </body> </html>
测试
运行该Vue应用程序,此时就可以在控制台直接输入vm.message
来修改值,中间是可以省略data的,在这个操作中,并没有主动操作DOM,就让页面的内容发生了变化,这就是借助了Vue的数据绑定功能实现的;MVVM模式中要求ViewModel层就是使用观察者模式来实现数据的监听与绑定,以做到数据与视图的快速响应。
根据上述创建的第一个Vue应用程序,看起来这跟渲染一个字符串模板非常类似,但是 Vue 在背后做了大量工作。现在数据和 DOM 已经被建立了关联,所有东西都是响应式的。在控制台操作对象属性,界面可以实时更新!
注意我们不再和 HTML 直接交互了。一个 Vue 应用会将其挂载到一个 DOM 元素上 (对于上述例子是 #app
) 然后对其进行完全控制。那个 HTML 是我们的入口,但其余都会发生在新创建的 Vue 实例内部。
除了文本插值,还可以使用v-bind
来绑定元素attribute!
<div id="app2">
<span v-bind:title="message">
鼠标悬停几秒查看此处动态绑定的提示信息
</span>
</div>
var vm2 = new Vue({
el : "#app2",
data : {
message : "Hello"
}
})
v-bind
attribute 被称为指令。指令带有前缀 v-
,以表示它们是 Vue 提供的特殊 attribute。它们会在渲染的 DOM 上应用特殊的响应式行为。在这里,该指令的意思是:将这个元素节点的 title
attribute 和 Vue 实例的 message
property 保持一致。app2.message = 'new message'
,就会再一次看到这个绑定了 title
attribute 的 HTML 已经进行了更新。v-if
v-else
代码示例demo02.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--view层 模板--> <div id="app"> <h1 v-if="ok">Yes</h1> <h1 v-else>No</h1> </div> <!--1.导入Vue.js--> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> <script> var vm = new Vue({ el : "#app", //Model层:数据 data : { ok: true } }); </script> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--for循环获取数据--> <div id="app"> <li v-for="(text,index) in allTexts"> {{text.message}}---{{index}} </li> </div> <!--1.导入Vue.js--> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> <script> var vm = new Vue({ el:"#app", data : { allTexts : [ {message : "1"}, {message : "2"}, {message : "3"}, ] } }); </script> </body> </html>
v-on
指令可以监听DOM事件,并在触发时运行一些JavaScript代码。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <button v-on:click="counter += 1">Add 1</button> <p>The button above has been clicked {{counter}} times.</p> </div> <!--1.导入Vue.js--> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> <script> var vm = new Vue({ el : "#app", data : { counter : 0 } }) </script> </body> </html>
测试
代码示例2:事件处理方法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <!--事件绑定--> <div id="app"> <button v-on:click="sayHi()">点我</button> </div> <!--1.导入Vue.js--> <script src="https://cdn.jsdelivr.net/npm/vue@2.5.21/dist/vue.js"></script> <script> let vm = new Vue({ el : "#app", data : { message : "ano" }, //方法必须定义在vue的methods对象中 methods : { sayHi : function() { alert(this.message); } } }); </script> </body> </html>
测试
Vue.js是一个MVVM框架,即数据双向绑定:**当数据发生变化时,视图也发生变化;当视图发生变化时,数据也随之同步变化。**这也算是Vue.js的精髓之处。
值得注意的是,我们所说的数据双向绑定,一定是对于UI控件来说的,非UI控件不会涉及到数据双向绑定。单向数据绑定是使用状态管理工具的前提,如果我们使用vuex
,那么数据流也是单向的,这时就会和双向数据绑定又冲突。
在Vue.js中,如果使用vuex,实际上数据还是单向的,之所以说是数据双向绑定,这是用的UI空间来说,对于处理表单,Vue.js的双向数据绑定用起来就特别舒服了。即两者并不排斥,在全局性数据流使用单向,方便跟踪;局部性数据流使用双向,简单易操作。
使用v-model
指令在表单<input>、<textarea>、及<select>
元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。
注意:v-model
会忽略所有表单元素的value、checked、selected特性的初始值而总将Vue实例的数据作为数据来源,因此,应该通过JavaScript在组件的data选项中声明初始值。
代码示例1:单行文本/多行文本
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> 输入的文本<input type="text" v-model="message"> {{message}} <textarea v-model:id="message"></textarea> {{message}} </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> <script> var vm = new Vue({ el:"#app", data : { message:"" } }); </script> </body> </html>
测试
代码示例2:单选框
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> 性别: <input type="radio" name="gender" value="man" v-model="checked">男 <input type="radio" name="gender" value="women" v-model="checked">女 <p> 选中的是:{{checked}} </p> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> <script> var vm = new Vue({ el:"#app", data : { checked:'' } }); </script> </body> </html>
测试:
代码示例3:下拉框
注意:如果v-model
表达式的初始值未能匹配任何选项,<select>
元素将被渲染为“未选中”状态,在IOS中,这会使得用户无法选择第一个选项,因为这样的情况下,IOS不会触发change事件。因此,推荐如下这样提供一个值为空的禁用选项作为第一个。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> 下拉框: <select v-model="selected"> <option value="" disabled>--请选择--</option> <option>A</option> <option>B</option> <option>C</option> <option>D</option> </select> <span>value:{{selected}}</span> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> <script> var vm = new Vue({ el:"#app", data : { selected:'' } }); </script> </body> </html>
测试:
代码示例4:复选框
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <!--复选框--> 爱好: <input type="checkbox" name="hobbies" value="sing" v-model="checked">唱歌 <input type="checkbox" name="hobbies" value="running" v-model="checked">跑步 <input type="checkbox" name="hobbies" value="basketball" v-model="checked">篮球 <input type="checkbox" name="hobbies" value="football" v-model="checked">足球 <input type="checkbox" name="hobbies" value="coding" v-model="checked">编程 <p> 选择的爱好:{{checked}} </p> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> <script> var vm = new Vue({ el:"#app", data : { checked:[] } }); </script> </body> </html>
测试:
组件是可复用的Vue
实例,即是一组可以重复使用的模板,跟JSTL的自定义标签、Thymeleaf的tg:fragment
等框架有着异曲同工之妙。通常一个应用会以一颗嵌套的组件树的形式来组织:
例如,有页头、侧边栏、内容区等组件,每个组件又包含了其他的像导航链接、博文之类的组件。
为了能在模板中使用,这些组件必须先注册以便Vue能够识别。通过Vue.component
全局注册:
Vue.component('my-component-name', {
// ... options ...
})
全局注册的组件可以用在其被注册之后的任何 (通过 new Vue
) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中。
因为组件是可复用的 Vue 实例,所以它们与 new Vue
接收相同的选项,例如 data
、computed
、watch
、methods
以及生命周期钩子等。仅有的例外是像 el
这样根实例特有的选项。
可以将组件进行任意次数的复用。
一个简单的代码示例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <demo></demo> <demo></demo> <demo></demo> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> <script> Vue.component('demo',{ data:function() { return { count : 0 } }, template:'<button v-on:click="count++">clicked {{count}} 次</button>' }); new Vue({ el:"#app", data : { } }) </script> </body> </html>
测试:
注意:
count
。因为每用一次组件,就会有一个它的新实例被创建。data
选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝。 Prop是可以在组件上注册的一些自定义attribute。当一个值传递给一个prop attribute的时候,它就变成了那个组件实例的一个property。
一个组件默认可以拥有任意数量的prop,任何值都可以传递给任何prop。
代码示例1:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <!--组件:传递给组件中的值:props--> <ano v-for="item in items" v-bind:course="item"></ano> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> <script> //定义一个Vue组件,"ano"为自定义组件名称 Vue.component("ano",{ //使用props属性传递参数;template为组件的模板 props:['course'], template: '<li>{{course}}</li>' }); var vm = new Vue({ el:"#app", data:{ items:["Java", "Linux", "Web"] } }); </script> </body> </html>
说明:
v-for="item in items"
:遍历Vue实例vm
中定义的数组items
,并创建同等数量的组件;v-bind:course="item"
:将遍历的数据item绑定到组件中props
定义的名为course
的属性上。测试:
代码示例2:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <blog-post v-for="post in posts" v-bind:key="post.id" v-bind:title="post.title"></blog-post> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> <script> Vue.component('blog-post',{ props:['title'], template: '<h3>{{title}}</h3>' }) var vm = new Vue({ el:"#app", data : { posts:[ {id:1,title:"One"}, {id:2,title:"Two"}, {id:3,title:"Three"}, ] } }); </script> </body> </html>
测试:
以上述代码示例2为例,当构建一个<blog-post>
组件时,其模板最终包含的东西不止一个title,至少还需要包含博文的正文content:
<h3>{{ title }}</h3>
<div v-html="content"></div>
但是如果在模板template
中尝试像以上这样写,Vue会显示一个错误every component must have a single root element
。因此,需要将模板的内容包裹在一个父元素内来修复这个问题,代码如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <blog-post v-for="post in posts" v-bind:key="post.id" v-bind:post="post"> </blog-post> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> <script> Vue.component('blog-post',{ props:['post'], template: ` <div class="blog-post"> <h3>{{post.title}}</h3> <div v-html="post.content"></div> </div> ` }) var vm = new Vue({ el:"#app", data : { posts:[ {id:1,title:"One",content:"----one content----"}, {id:2,title:"Two",content:"----two content----"}, {id:3,title:"Three",content:"----three content----"}, ] } }); </script> </body> </html>
Axios是一个开源的、可以用在浏览器端和NodeJS的异步通信框架,其主要作用就是实现Ajax异步通信,特点如下:
由于Vue.js
是一个视图层框架,并且作者(尤雨溪) 严格准守SoC(关注度分离原则),所以Vue.js
并不包含AJAX的通信功能;
为了解决通信问题,作者单独开发了一个名为vue-resource
的插件,不过在进入2.0版本以后停止了对该插件的维护并推荐了**Axios
**框架。尽量少用jQuery, 因为它操作Dom太频繁!
Vue实例有一个完整的生命周期,也就是从开始创建初始化数据、编译模板、挂载DOM、渲染一更新一渲染、卸载等一系列过程,称这是Vue的生命周期。通俗说就是Vue实例从创建到销毁的过程,即生命周期。
在Vue的整个生命周期中,它提供了一系列的事件,可以让我们在事件触发时注册JS方法,可以让我们用自己注册的JS方法控制整个大局,在这些事件响应方法中的this直接指向的是Vue的实例。
模拟一段JSON数据如下:
data.json
{ "name": "TOP", "url": "https://baike.baidu.com/item/T.O.P/12000579?fr=aladdin", "page": 1, "isNonProfit":true, "address": { "street": "YG", "city": "首尔", "country": "韩国" }, "links": [ { "name": "baidu", "url": "https://baike.baidu.com/item/T.O.P/12000579?fr=aladdin" }, { "name": "kpopping", "url": "https://kpopping.com/profiles/idol/T-O-P" }, { "name": "wikipedia", "url": "https://zh.wikipedia.org/wiki/T.O.P." } ] }
代码示例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <!--解决模板闪烁问题--> <style> [v-clock]{ display: none; } </style> </head> <body> <div id="app"> <div>{{info.name}}</div> <div>{{info.address.city}}</div> <div>{{info.links}}</div> <a v-bind:href="info.url">click me</a> </div> <!--使用cdn引入JS文件--> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script type="text/javascript"> var vm = new Vue({ el:"#app", data:function() { return { //请求的返回参数格式,必须和JSON字符串一样 info : { name:null, address:{ street:null, city:null, country:null }, url:null, links:[] } } }, mounted(){//钩子函数 链式编程 ES6新特性 axios.get('../data.json').then(response=>(this.info=response.data)); } }) </script> </body> </html>
测试
说明
v-bind
将a:href
的属性值与Vue实例中的数据进行绑定;axios
框架的get()
方法请求Ajax,并自动将数据封装进了Vue实例的数据对象中; 计算属性的重点突出在属性两个字上,首先它是一个属性,其次这个属性有计算的能力,这里的计算就是一个函数;简单点说,就是一个能够将计算结果存起来的属性,即将行为转化成了静态的属性,可以想象为缓存!
代码示例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="app"> <p>currentTime1 {{currentTime1()}}</p> <p>currentTime2 {{currentTime2}}</p> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script> <script> var vm = new Vue({ el:"#app", data:{ message:"Hello,Ano!" }, methods:{ currentTime1:function() { return Date.now();//返回当前时间戳 } }, computed:{//计算属性:methods、computed方法不能重名,重名后只会调用methods中的方法 currentTime2:function() { this.message;//这里的数据刷新后会重新计算时间戳,类似于缓存 return Date.now();//返回当前时间戳 } } }) </script> </body> </html>
测试
说明:
methods
:定义方法,调用方法使用currentTime1(),注意需要带括号;computed
:定义计算属性,调用属性使用currentTime2,注意不需要带括号;vm.message="hello"
更新数据,再次测试观察变化!结论:
调用方法时,每次都需要讲行计算,既然有计算过程则必定产生系统开销,那如果这个结果是不经常变化的呢?此时就可以考虑将这个结果缓存起来,采用计算属性可以很方便的做到这点,计算属性的主要特性就是为了将不经常变化的计算结果进行缓存,以节约我们的系统开销。
在Vue.js
中,使用<slot>
元素承载分发内容的出口,作者称其为插槽,可以应用在组合组件的场景中。
代码示例:
场景:制作一个待办事项组件(todo) ,该组件由**待办标题(todo-title)和待办内容(todo-items)**组成,但这三个组件又是相互独立的,该如何操作呢?
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="todoList"> <todo> <todo-title slot="todo-title" v-bind:title="title"></todo-title> <todo-items slot="todo-items" v-for="item in todoItems" v-bind:item="item"></todo-items> </todo> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.min.js"></script> <script> /*待办事项todo组件*/ Vue.component("todo", { //slot:插槽 template: ` <div> <slot name="todo-title"></slot> <ul> <slot name="todo-items"></slot> </ul> </div> ` }); /*待办标题组件*/ Vue.component("todo-title",{ props:['title'], template: ` <div>{{ title }}</div> ` }); /*待办内容组件*/ Vue.component("todo-items",{ props:['item'], template: ` <li>{{ item }}</li> ` }); let vue = new Vue({ el : "#todoList", data : { title:"书籍列表", todoItems:['Java','Linux','Python'] } }); </script> </body> </html>
说明:
上述代码示例中,组件todo-title
和todo-items
分别被分发到了组件todo
中的插槽todo-title
和todo-items
中。
测试:
场景:在上述代码示例中,增加一个功能:在待办内容组件中添加删除按钮,实现删除功能。
解析:数据项在Vue的实例中,但删除操作需要在组件中完成,而组件只能调用自身的方法。因此,Vue提供了自定义事件功能,从而解决这个问题。
this.$emit('自定义事件名称',参数)
代码如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="todoList"> <todo> <todo-title slot="todo-title" v-bind:title="title"></todo-title> <!--自定义事件remove绑定Vue实例中的removeItem方法--> <todo-items slot="todo-items" v-for="(item,index) in todoItems" v-bind:item="item" v-bind:index="index" v-on:remove="removeItem(index)"></todo-items> </todo> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.min.js"></script> <script> /*待办事项todo组件*/ Vue.component("todo", { //slot:插槽 template: ` <div> <slot name="todo-title"></slot> <ul> <slot name="todo-items"></slot> </ul> </div> ` }); /*待办标题组件*/ Vue.component("todo-title",{ props:['title'], template: ` <div>{{ title }}</div> ` }); /*待办内容组件*/ Vue.component("todo-items",{ props:['item','index'], //只能绑定当前组件的方法 template: ` <li>{{index}}----{{ item }} <button v-on:click="remove">删除</button></li> `, methods : { remove:function (index){ //调用Vue实例中的删除方法,通过this.$emit()实现自定义事件分发 this.$emit('remove', index) } } }); let vue = new Vue({ el : "#todoList", data : { title:"书籍列表", todoItems:['Java','Linux','Python','Web'] }, methods:{ //通过index删除 removeItem:function(index) { console.log("删除了"+this.todoItems[index]+"OK"); //一次只删除一个元素,删除当前元素 this.todoItems.splice(index,1); } } }); </script> </body> </html>
说明:
测试:
核心:数据驱动、组件化
优点:借鉴了Angula JS的模块化开发和React的虚拟DOM,虚拟DOM就是把DOM操作放到内存中执行。
常用属性:
@
:
组件化:
Vue.component('my-component-name', {
props:['attribute1','attribute2'],
template:`...`
})
组合组件slot
插槽
组件内部绑定事件需要使用this.$emit("事件名",参数)
计算属性的特性,缓存计算数据
Vue遵循SoC关注度分离原则,是纯粹的视图框架,并不包含如Ajax之类的异步通信功能,为了解决通信问题,需要使用Axios框架做异步通信。
说明:
Vue的开发都是要基于NodeJS,实际开发采用vue-cli
脚手架开发,vue-router
路由,vuex
做状态管理;Vue UI界面一般使用ElementUI
或者ICE
来快速搭建前端项目。
vue-cli
是vue.js
的一个脚手架,用于快速生成一个vue.js+webpack
的项目模板。
预先定义好的目录结构及基础代码,就好比在创建Maven项目时可以选择创建一个骨架项目,这个骨架项目就是脚手架,使得开发更加的快速。
确认Node.js安装成功:
node -v
#npm,就是一个软件包管理工具,类似于Linux下的apt软件安装
npm -v
安装Node.js淘宝镜像加速器(cnpm
)
# -g 就是全局安装
npm install cnpm -g
# 或使用如下语句解决npm速度慢的问题
npm install --registry=https://registry.npm.taobao.org
安装vue-cli
cnpm instal1 vue-cli-g
#测试是否安装成功#查看可以基于哪些模板创建vue应用程序,通常选择webpack
vue list
创建一个Vue项目,首先在电脑上建立一个空的文件夹;
创建一个基于webpack模板的vue应用程序;
#进入到对应的目录中
cd /d E:\JavaAno\code\Vue
#创建vue应用程序,这里的myvue是顶日名称
vue init webpack myvue
创建完成查看对应目录:
初始化并运行
#进入到vue项目的目录下
cd myvue
#初始化,安装所有依赖环境
npm install
#运行
npm run dev
使用IDEA打开该Vue项目,并在Terminal运行它:
访问:
Ctrl+C停止应用程序
Script标签
<script src = "module1.js"></script>
<script src = "module2.js"></script>
<script src = "module3.js"></script>
这是最原始的Javascript文件加载方式,如果把每一个文件看作是一个模块,那么它们的接口通常是暴露在全局作用域下,也就是定义在window对象中,不同模块的调用都是一个作用域。
这种原始的加载方式存在一些显而易见的弊端:
<script>
的书写顺序进行加载;CommonsJS
服务器端的NodeJS遵循CommonsJS规范,该规范的核心思想是,允许模块通过require
方法来同步加载所需依赖的其他模块,然后通过exports
或module.exports
来导出需要暴露的接口。
优点:
缺点:
实现:
AMD
Asynchronous Module Definition规范其实主要一个主要接口define(id?,dependencies?,factory);它要在声明模块的时候指定所有的依赖dependencies,并且还要当做形参传到factory中,对于依赖的模块提前执行。
define("module",["dep1","dep2"],functian(d1,d2){
return someExportedValue;
});
require(["module","../file.js"],function(module,file){});
优点:
缺点:
实现:
CMD
Commons Module Definition规范和AMD很相似,尽保持简单,并与CommonsJS和NodeJS的Modules规范保持了很大的兼容性。
define(function(require,exports,module){
var $=require("jquery");
var Spinning = require("./spinning");
exports.doSomething = ...;
module.exports=...;
});
优点:
缺点:
实现:
ES6模块
EcmaScript 6标准增加了JavaScript语言层面的模块体系定义。ES6模块的设计思想,是尽量静态化,使编译时就能确定模块的依赖关系,以及输入和输出的变量。Commons JS和AMD模块,都只能在运行时确定这些东西。
import "jquery"
export function doStuff(){}
module "localModule"{}
优点:
缺点:
实现:
npm install webpack -g
npm install webpack-cli -g
#查看安装是否成功
webpack -v
webpack-cli -v
配置:创建 webpack.config.js配置文件
直接运行webpack
命令打包
创建项目
创建一个空文件夹,用IDEA open即可。
新建一个Directory,命名为modules,用于放置JS模块等资源文件;
在modules目录下创建模块文件,用于编写JS模块相关代码,如下:
hello.js
//使用exports暴露一个方法
exports.sayHi = function () {
document.write("Hello,Webpack!")
}
main.js
//require导入一个模块,就可以调用这个模块中的方法了
let hello = require("./hello");
hello.sayHi();
在项目目录下创建webpack.config.js
配置文件
webpack.config.js
module.exports = {
entry:"./modules/main.js",
output: {
filename:"./js/bundle.js"
}
}
使用webpack
命令打包
在项目目录下创建一个HTML页面,导入上述步骤打包后的js文件
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Webpack-study</title>
</head>
<body>
<script src="./dist/js/bundle.js"></script>
</body>
</html>
运行index.html
查看效果:
实现热部署,命令如下:
webpack --watch
Vue Router是Vue.js官方的路由管理器。它和Vue.js的核心深度集成, 让构建单页面应用变得易如反掌。包含的功能有:
Vue js
过渡系统的视图过渡效果HTML5
历史模式或hash模式,在IE 9中自动降级基于第一个vue-cli项目myvue
进行测试学习,首先 先查看node_modules目录中是否存在vue-router
;
vue-router是一个插件包,所以还是需要用npm/cnpm来进行安装。打开命令行工具,进入项目目录,输入下面命令:
npm install vue-router --save-dev
在模块化工程中使用,必须通过Vue.use(VueRouter)
显示安装路由功能:
import Vue from "vue";
import VueRouter from "vue-router";
Vue.use(VueRouter);
components
目录下存放编写的组件;
Content.vue
<template>
<h1>内容页</h1>
</template>
<script>
export default {
name: "Content"
}
</script>
<!--作用域-->
<style scoped>
</style>
Main.vue
<template>
<h1>首页</h1>
</template>
<script>
export default {
name: "Main"
}
</script>
<style scoped>
</style>
在src目录下,新建目录router
存放路由,新建index.js
配置路由;
index.js
import Vue from "vue"; import VueRouter from "vue-router"; import Content from "../components/Content"; import Main from "../components/Main"; //安装路由 Vue.use(VueRouter); //配置导出路由 export default new VueRouter({ routes: [ { //路由路径 path : '/content', name:'content', //跳转的组件 component:Content }, { path : '/main', name: 'main', component : Main } ] })
在main.js
中配置路由;
import Vue from 'vue'
import App from './App'
//自动扫描里面的路由配置
import router from './router'
Vue.config.productionTip = false
new Vue({
el: '#app',
//配置路由
router,
components: { App },
template: '<App/>'
})
在App.vue
中使用路由;
<template> <div id="app"> <h1>THIS IS T.O.P</h1> <router-link to="/main">首页</router-link> <router-link to="/content">内容页</router-link> <!--展示template内容--> <router-view></router-view> </div> </template> <script> export default { name: 'App', } </script> <style> #app { font-family: 'Avenir', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
测试结果:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。