【概括】Vue入门Vue.js两大前端框架之一准确的来说不能叫做框架应该叫做渐进式框架是后来Vue生态逐渐壮大产生了例如Vue-router等的资源Vue生态才逐渐变成的框架Vue基础Vue指令V-on click 绑定时间Vue对象是MVVM中的VM绑定数据不需要操作DOMV-bind动态的绑定一个或多个 attribute也可以是组件的 prop。v-model双向v-bind是单向​在表单输入元素或组件上创建双向绑定。期望的绑定值类型根据表单输入元素或组件输出的值而变化Vue的声明周期beforeCreateCreatedDestory等生命周期钩子 生命周期函数 生命周期事件Vue自定义组件建议一开始就使用驼峰命名法v-for中key的使用注意事项Vue的组件化组合复用创建命名建议一开始就使用驼峰命名法注意在 Vue 2.2.0 版本里当在组件中使用 v-for 时key 属性是必须要加上的。这样做是因为每次 for 循环的时候通过指定 key 来标示当前循环这一项的唯一身份。当 Vue.js 用 v-for 正在更新已渲染过的元素列表时它默认用 “就地复用” 策略。如果数据项的顺序被改变Vue将不是移动 DOM 元素来匹配数据项的顺序 而是简单复用此处每个元素并且确保它在特定索引下显示已被渲染过的每个元素。为了给 Vue 一个提示以便它能跟踪每个节点的身份从而重用和重新排序现有元素你需要为每项提供一个唯一 key 属性。key的类型只能是string/number而且要通过 v-bind 来指定。v-if设置元素的显示和隐藏添加/删除DOM元素作用根据表达式的值的真假条件来决定是否渲染元素如果为false则不渲染达到隐藏元素的目的如果为true则渲染。在切换时元素和它的数据绑定会被销毁并重建。举例如下点击按钮时切换和隐藏盒子v-show设置元素的显示和隐藏在元素上添加/移除styledisplay:none属性作用根据表达式的真假条件来切换元素的 display 属性。如果为false则在元素上添加display:none属性否则移除display:none属性。举例如下点击按钮时切换和隐藏盒子我们直接把上一段代码中的v-if改成v-show就可以了v-if和v-show的区别v-if和v-show都能够实现对一个元素的隐藏和显示操作。区别v-if每次都会重新添加/删除DOM元素v-show每次不会重新进行DOM的添加/删除操作只是在这个元素上添加/移除styledisplay:none属性表示节点的显示和隐藏。优缺点v-if有较高的切换性能消耗。这个很好理解毕竟每次都要进行dom的添加删除操作。v-show有较高的初始渲染消耗。也就是说即使一开始v-showfalse该节点也会被创建只是隐藏起来了。而v-iffalse的节点根本就不会被创建。总结如果元素涉及到频繁的切换最好不要使用 v-if, 而是推荐使用 v-show如果元素可能永远也不会被显示出来被用户看到则推荐使用 v-ifv-on的按键修饰符Vue 内置的按键修饰符通俗一点讲指的是监听键盘输入的事件。Vue 允许为 v-on 在监听键盘事件时添加按键修饰符。如下Vue内置的按键修饰符.enter .tab .delete (捕获 “删除” 和 “退格” 键) .esc .space .up .down .left .right 1.0.8版本支持单字母的按键别名。比如说keyup指的是键盘任何键位抬起时的监听事件。.enter指的是按enter键的按键修饰符。我们把这两个结合起来看看。keyup.enter举例按enter键后的监听事件keyup.enteraddData表示按住enter键后执行addData()方法。全称是v-on:key.enteraddData。我们还是拿01-04这篇文章中的列表功能来举例。之前是点击“添加”按钮后列表中会添加一个item。现在要求在输入框中按enter键后也能添加一个item。核心代码如下input typetext v-modelformData.name keyup.enteraddData自定义全局按键修饰符//自定义全局按键修饰符 Vue.config.keyCodes.f2 113;1使用Vue.directive()自定义全局指令input typetext idsearch v-modelname v-focus//自定义全局指令 v-focus让文本框自动获取焦点 //参数1指令的名称。注意在定义的时候指令的名称前面不需要加 v- 前缀但是在调用的时候必须在指令名称前 加上 v- 前缀 //参数2是一个对象这个对象身上有一些指令相关的函数这些函数可以在特定的阶段执行相关的操作 Vue.directive(focus, { //在每个函数中第一个参数永远是 el 表示 被绑定了指令的那个元素这个 el 参数是一个原生的JS对象DOM对象 bind: function (el) { // 每当指令绑定到元素上的时候会立即执行这个 bind 函数【只执行一次】 // 在元素 刚绑定了指令的时候还没有 插入到 DOM中去这时候调用 focus 方法没有作用 // 因为一个元素只有插入DOM之后才能获取焦点 // el.focus() }, inserted: function (el) { // inserted 表示元素 插入到DOM中的时候会执行 inserted 函数【触发1次】 el.focus() // 和JS行为有关的操作最好在 inserted 中去执行放置 JS行为不生效 }, updated: function (el) { // 当VNode更新的时候会执行 updated 【可能会触发多次】 ​ } })v-bind指令绑定到元素的时候会调用函数只有一次自定义指令不需要加v-但是在html标签里的指令必须加上v- 自定义指令名称由此可以看看出bind、inserted、updated这三个钩子函数的执行时机不同且执行的次数有区别。//自定义全局指令 v-color设置DOM元素的color属性 Vue.directive(color, { // 样式只要通过指令绑定给了元素不管这个元素有没有被插入到页面中去这个元素肯定有了一个内联的样式 // 将来元素肯定会显示到页面中这时候浏览器的渲染引擎必然会解析样式应用给这个元素 // 意思是说我们可以把样式的代码写到bind中去即使这个时候dom元素还没有被创建 bind: function (el, binding) { // 每当指令绑定到元素上的时候会立即执行这个 bind 函数【只执行一次】 ​ console.log(binding.name); //打印结果color console.log(binding.value); //打印结果green console.log(binding.expression); //green ​ el.style.color binding.value// 通过bining拿到v-color中传递过来的值 ​ }, inserted: function (el) { // inserted 表示元素 插入到DOM中的时候会执行 inserted 函数【触发1次】 // 和JS行为有关的操作最好在 inserted 中去执行防止 JS行为不生效 //el.focus() }, updated: function (el) { // 当VNode更新的时候会执行 updated 【可能会触发多次】 } }) ​ new Vue({ el: #app, data: { name: smyhvae } })div idapp 搜索框1 input typetext idsearch v-modelname v-colorgreen /div //自定义全局指令 v-color设置DOM元素的color属性 Vue.directive(color, { // 样式只要通过指令绑定给了元素不管这个元素有没有被插入到页面中去这个元素肯定有了一个内联的样式 // 将来元素肯定会显示到页面中这时候浏览器的渲染引擎必然会解析样式应用给这个元素 // 意思是说我们可以把样式的代码写到bind中去即使这个时候dom元素还没有被创建 bind: function (el, binding) { // 每当指令绑定到元素上的时候会立即执行这个 bind 函数【只执行一次】 ​ console.log(binding.name); //打印结果color console.log(binding.value); //打印结果green console.log(binding.expression); //green ​ el.style.color binding.value// 通过bining拿到v-color中传递过来的值 ​ }, inserted: function (el) { // inserted 表示元素 插入到DOM中的时候会执行 inserted 函数【触发1次】 // 和JS行为有关的操作最好在 inserted 中去执行防止 JS行为不生效 //el.focus() }, updated: function (el) { // 当VNode更新的时候会执行 updated 【可能会触发多次】 } }) ​ new Vue({ el: #app, data: { name: smyhvae } }) /script /body ​ /html上方代码中,bind方法里传递的第二个参数binding可以拿到DOM元素中v-color里填的值。注意v-colorgreen这里面写的是字符串常量如果去掉单引号就成了变量不是我们想要的。自定义私有指令自定义私有指令在某一个vue 对象内部自定义的指令称之为私有指令。这种指令只有在当前vue对象的el指定的监管区域有用。代码举例设置文字的font-weight属性!DOCTYPE html html langen ​ head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 meta http-equivX-UA-Compatible contentieedge titleDocument/title script srcvue2.5.16.js/script /head ​ body ​ div idapp span v-fontweight600生命壹号/span /div script ​ new Vue({ el: #app, data: { name: smyhvae }, //自定义私有指令 directives: { fontweight: { bind: function (el, binding) { el.style.fontWeight binding.value; } } } }) /scriptvue实例的生命周期从Vue实例创建、运行、到销毁期间总是伴随着各种各样的事件这些事件统称为生命周期。生命周期钩子就是生命周期事件的别名而已。生命周期钩子 生命周期函数 生命周期事件。1、创建期间的生命周期函数beforeCreate实例刚在内存中被创建出来此时还没有初始化好 data 和 methods 属性created实例已经在内存中创建OK此时 data 和 methods 已经创建OK此时还没有开始 编译模板。我们可以在这里进行Ajax请求。beforeMount此时已经完成了模板的编译但是还没有挂载到页面中mounted此时已经将编译好的模板挂载到了页面指定的容器中显示。mounted之后表示真实DOM渲染完了可以操作DOM了运行期间的生命周期函数beforeUpdate状态更新之前执行此函数 此时 data 中的状态值是最新的但是界面上显示的 数据还是旧的因为此时还没有开始重新渲染DOM节点updated实例更新完毕之后调用此函数此时 data 中的状态值 和 界面上显示的数据都已经完成了更新界面已经被重新渲染好了。PS数据发生变化时会触发这两个方法。不过我们一般用watch来做。3、销毁期间的生命周期函数beforeDestroy实例销毁之前调用。在这一步实例仍然完全可用。destroyedVue 实例销毁后调用。调用后Vue 实例指示的所有东西都会解绑定所有的事件监听器会被移除所有的子实例也会被销毁。PS可以在beforeDestroy里清除定时器、或清除事件绑定。vue-resource的介绍vue-resource是Vue高度集成的第三方包。官网链接文档http相关vue-resource/docs/http.md at master · pagekit/vue-resource · GitHubvue-resource 依赖于 Vue。所以我们要按照先后顺序导入vue.js和vue-resource.js文件。解释vue.js文件向Windows对象暴露了Vue这个关键词vue-resource.js向Vue身上挂载了this.$http这个属性。于是我们可以直接写this.$http.get或者this.$http.post或者this.$http.jsonp来调用。vue-resource 发送Ajax请求常见的数据请求类型包括get、post、jsonp。下面我们分别讲一讲。get 请求格式举例this.$http.get(url) .then(function (result) { // 当发起get请求之后通过 .then 来设置成功的回调函数 console.log(result.body); // response.body就是服务器返回的成功的数据 var result result.body; }, function (err) { //err是异常数据 });//ajax请求添加数据 adddata: function () { // 1、获取用户填写的文本框的值只需要通过this.pname即可 // 2、调用ajax的post方法将数据上传到服务器 var url http://vueapi.ittun.com/api/addproduct; var postData { name: this.pname }; //【重要】键name是json中约定好的字段。我们把这个字段传给服务器 var options { emulateJSON: true }; this.$http.post(url, postData, options).then(function (response) { if (response.body.status ! 0) { alert(response.body.message); return; } this.pname ; // 3、添加完成后只需要手动再调用一次getlist将列表数据重新加载一次即可刷新页面上的数据 this.getlist(); }); },axios除了 vue-resource 之外还可以使用axios的第三方包实现实现数据的请求。通过Vue全局配置api接口的url地址api接口的url地址包括绝对路径相对路径。我们在做Ajax请求的时候所填写的url建议填相对路径然后把绝对路径放在全局的位置。Vue就提供了这个功能。举例如下如上方代码所示第一步是在全局的位置写绝对路径Vue.http.options.root http://smyhvae/;第二步是在Ajax请求的url中写相对路径注意前面不要带/this.$http.get(api/getprodlist)动画进入v-enter动画进入之前的初始状态v-enter-to动画进入之后的结束状态v-enter-active动画进入的时间段PS第一、第二个是时间点第三个是时间段。动画离开v-leave动画离开之前的初始状态v-leave-to动画离开之后的结束状态v-leave-active动画离开的时间段v-enter动画进入之前的初始状态v-enter-to动画进入之后的结束状态v-enter-active动画进入的时间段PS第一、第二个是时间点第三个是时间段。动画离开v-leave动画离开之前的初始状态v-leave-to动画离开之后的结束状态v-leave-active动画离开的时间段PS第一、第二个是时间点第三个是时间段。什么是组件组件 组件的出现就是为了拆分Vue实例的代码量的能够让我们以不同的组件来划分不同的功能模块将来我们需要什么样的功能就可以去调用对应的组件即可。模块化和组件化的区别模块化是从代码逻辑的角度进行划分的方便代码分层开发保证每个功能模块的职能单一组件化是从UI界面的角度进行划分的前端的组件化方便UI组件的重用全局组件的定义和注册组件Component是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素封装可重用的代码。全局组件的定义和注册有三种方式我们接下来讲一讲。//第一步使用 Vue.extend 定义组件 var myAccount Vue.extend({ template: divh2登录页面/h2 h3注册页面/h3/div // 通过 template 属性指定了组件要展示的HTML结构。template 是 Vue 中的关键字不能改。 }); //第二步使用 Vue.component 注册组件 // Vue.component(组件的名称, 创建出来的组件模板对象) Vue.component(account, myAccount); //第一个参数是组件的名称标签名第二个参数是模板对象 new Vue({ el: #app });注意1、红框部分要保证二者的名字是一致的。如果在注册时组件的名称是驼峰命名比如Vue.component(myComponent, myAccount); //第一个参数是组件的名称标签名第二个参数是模板对象那么在标签中使用组件时需要把大写的驼峰改为小写的字母同时两个单词之间使用-进行连接my-component /my-component谁用标签的时候需要把自己定义的模版对象从驼峰写法改为全部小写并使用“-”进行连接//定义、注册组件第一个参数是组件的名称标签名第二个参数是组件的定义 Vue.component(account, { template: divh2登录页面/h2 h3注册页面/h3/div // template 是 Vue 中的关键字不能改。 });定义注册一步到位写法三将组件内容定义到template标签中去。代码如下!DOCTYPE html html langen head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 meta http-equivX-UA-Compatible contentieedge titleDocument/title script srcvue2.5.16.js/script /head body !-- 定义模板 -- template idmyAccount div h2登录页面/h2 h3注册页面/h3 /div /template div idapp !-- 使用组件 -- account /account /div script //定义、注册组件 Vue.component(account, { template: #myAccount // template 是 Vue 中的关键字不能改。 }); new Vue({ el: #app }); /script /body /htmlnew Vue({ el: #app, data: {}, components: { // 定义、注册Vue实例内部的私有组件 myLogin: { template: h3这是私有的login组件/h3 } } });在Vue内部定义的是私有组件只有当前的区域才能使用上方代码中如果在注册私有组件时组件的名称是驼峰命名比如components: { // 定义、注册Vue实例内部的私有组件 myLogin: { template: #loginTmp } }那么在标签中使用组件时需要把大写的驼峰改为小写的字母同时两个单词之间使用-进行连接my-login/my-login所以为了避免名字不一致的问题我们注册组件时组件的名称可以直接写成my-login。比如避免驼峰不一致的建议写法components: { // 定义、注册Vue实例内部的私有组件 my-login: { template: #loginTmp } }在进行组件注册的时候建议直接使用斜杠的方式注册组件名这样在使用的时候就可以方便的直接直接使用-组件名而不用考虑驼峰转-的写法div !-- 在组件的模板中调用本组件中的data -- {{myData}} a href# v-on:clicklogin登录1/a h2登录页面/h2 h3注册页面/h3 /div /template div idapp !-- 第一次调用组件 -- account /account !-- 第二次调用组件 -- account /account /div script //定义、注册组件 Vue.component(account, { template: #myAccount, //组件中的 data //【注意】组件中的data不再是对象而是一个方法否则报错而且这个方法内部还必须返回一个对象才行 // 组件中 的data 数据,使用方式,和实例中的 data 使用方式完全一样!!! data: function () { return { myData: smyhvae } }, //组件中的 method methods: { login: function () { alert(login操作); } } });注意在为组件添加数据时data不再是对象了而是function而且要通过 return的形式进行返回否则页面上是无法看到效果的。通过 function返回对象的形式来定义data作用是上方代码中组件account被调用了两次不像根组件那样只能调用一次但是每个组件里的数据 myData是各自独立的不产生冲突。换而言之通过函数返回对象的目的是为了让每个组件都有自己独立的数据存储而不应该共享一套数据。组件定义时如果要添加数据data就换成function了每当我们创建一个新的组件实例时就会调用data函数data函数里会return一个新开辟的对象数据。这样做就可以保证每个组件实例有独立的数据存储。// 这是一个计数器的组件, 身上有个按钮,每当点击按钮,让 data 中的 count 值 1 Vue.component(counter, { template: #tmpl, data: function () { // return dataObj //当我们return全局的dataObj的时候这个dataObj是共享的 return { count: 0 } // 【重要】return一个**新开辟**的对象数据 }, methods: { increment() { this.count } } })父组件向子组件传值我们可以这样理解Vue实例就是一个父组件而我们自定义的组件包括全局组件、私有组件就是子组件。【重点】需要注意的是子组件不能直接使用父组件中的数据。父组件可以通过props属性向子组件传值。script // 创建 Vue 实例得到 ViewModel var vm new Vue({ el: #app, data: { msg: 父组件中的数据123 }, methods: {}, components: { // 子组件默认无法访问到 父组件中的 data 中的数据 和 methods 中的方法 component1: { //将子组件的名称定义为 component1 template: #myTemplate, data() { // 注意 子组件中的 data 数据并不是通过 父组件传递过来的而是子组件自身私有的比如 子组件通过 Ajax 请求回来的数据都可以放到 data 身上 // data 上的数据都是可读可写的 return { title: 子组件私有的数据 title, content: 子组件私有的数据 content } }, // 注意 组件中的 所有 props 中的数据都是通过 父组件 传递给子组件的 // props 中的数据都是只读的无法重新赋值 props: [parentMsg], // 第一步把父组件传递过来的 parentMsg 属性先在 props 数组中定义一下这样才能使用这个数据 directives: {}, filters: {}, components: {}, methods: { change() { // 下面这行会报错因为子组件不要直接修改父组件中的data数据 // this.parentMsg 被修改了 } } } } }); /script父组件给子组件传值的步骤根据上方截图我们可以总结出父组件给子组件传值的步骤如下。1在子组件的props属性中声明父亲传递过来的数据2定义子组件的模板时使用props中的属性3父组件在引用子组件时进行属性绑定。子组件中data中的数据和props中的数据的区别子组件中的 data 数据并不是通过 父组件传递过来的而是子组件自身私有的比如 子组件通过 Ajax 请求回来的数据都可以放到 data 身上。props 中的数据都是通过 父组件 传递给子组件的。data中的数据是可读可写的props中的属性只是可读的无法重新赋值重新赋值会报错也就是说子组件不要直接去修改父组件中的数据。父组件将方法传递给子组件父组件通过事件绑定机制将父组件的方法传递给子组件后端路由对于普通的网站所有的超链接都是URL地址所有的URL地址都对应服务器上对应的资源。当前端输入url请求资源时服务器会监听到是什么url地址那后端会返回什么样的资源呢后端这个处理的过程就是通过路由来分发的。总结后端路由就是把所有url地址都对应到服务器的资源这个对应关系就是路由。前端路由对于单页面应用程序来说主要通过URL中的hashurl地址中的#号来实现不同页面之间的切换。同时hash有一个特点HTTP请求中不会包含hash相关的内容。所以单页面程序中的页面跳转主要用hash实现。总结在单页应用程序中这种通过hash改变来切换页面的方式称作前端路由区别于后端路由。