前言 第二次要与VUE见面了,好兴奋啊!虽然不知道为啥兴奋呢!
继Vue我的首次遇见 之后,我又要开始我的“操作了”。
基本创建都在 Vue我的首次遇见 中。
这里面内容大都来自runoob ,因为我这里用的是router
,所以作了部分修改 。
Vue.js 模板语法 Vue.js 使用了基于 HTML 的模版语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。
Vue.js 的核心是一个允许你采用简洁的模板语法来声明式的将数据渲染进 DOM 的系统。
结合响应系统,在应用状态改变时, Vue 能够智能地计算出重新渲染组件的最小代价并应用到 DOM 操作上。
插值 文本 数据绑定最常见的形式就是使用
(双大括号)的文本插值:
打开 index.html
1 2 3 4 5 6 7 <div id ="app" > </div > <div id ="vue_det" > <h1 > author : {{author}}</h1 > <h1 > date : {{date}}</h1 > <h1 > {{description()}}</h1 > </div >
打开 src/main.js
,这里面放的是当前router
写js
脚本的地方。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 new Vue ({ el : '#vue_det' , data : { author : 'maxzhao' , date : '2019-04-24' }, methods : { description : function ( ) { return this .author + ' - 学的不仅是技术,更是梦想!' } } })
保存之后刷新页面(如果是按照我的安装,则自动添加热加载);
Html 使用 v-html 指令用于输出 html 代码:
打开 index.html
1 2 3 4 5 6 7 8 <div id ="app" > </div > <div id ="vue_det" > <h1 > author : {{author}}</h1 > <h1 > date : {{date}}</h1 > <h1 > {{description()}}</h1 > <div v-html ="message" > </div > </div >
打开 src/main.js
1 2 3 4 5 6 7 8 new Vue ({ el : '#vue_det' , data : { author : 'maxzhao' , date : '2019-04-24' , message : '<h1>maxzhao_v-html</h1>' },
自己测试前段界面哦。
属性 HTML 属性中的值应使用 v-bind 指令。
以下实例判断 class1 的值,如果为 true 使用 class1 类的样式,否则不使用该类:
v-bind 指令 打开 index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <!DOCTYPE html > <html > <head > <meta charset ="utf-8" > <meta name ="viewport" content ="width=device-width,initial-scale=1.0" > <title > vue_maxzhao</title > <style > .class1 { background : #444 ; color : #eee ; } </style > </head > <body > <div id ="app" > </div > <div id ="vue_det" > <h1 > author : {{author}}</h1 > <h1 > date : {{date}}</h1 > <h1 > {{description()}}</h1 > <div v-html ="message" > </div > <label for ="r1" > 修改颜色</label > <input type ="checkbox" v-model ="use" id ="r1" > <br > <br > <div v-bind:class ="{'class1': use}" > v-bind:class 指令 </div > </div > </body > </html >
打开 src/main.js
在 data
中添加,use: false
;
表达式 Vue.js 都提供了完全的 JavaScript 表达式支持。
打开 index.html
1 2 3 4 5 6 7 8 9 <div v-bind:class ="{'class1': use}" > v-bind:class 指令 </div > <br > {{5+5}}<br > {{ ok ? 'YES' : 'NO' }}<br > {{ message.split('').reverse().join('') }} <div v-bind:id ="'list-' + id" > maxzhao</div >
打开 src/main.js
在 data
中添加
1 2 3 use : false ,ok : true ,id : 1
指令 指令是带有 v- 前缀的特殊属性。
指令用于在表达式的值改变时,将某些行为应用到 DOM 上。如下例子:
v-if 打开 index.html
,接着添加:
1 2 3 4 5 6 7 <br > <p v-if ="seen" > 现在你看到我了</p > <template v-if ="ok" > <h1 > maxzhao</h1 > <p > 学的不仅是技术,更是梦想!</p > <p > 哈哈哈,打字辛苦啊!!!</p > </template >
打开 src/main.js
在 data
中添加
这里, v-if 指令将根据表达式 seen 的值(true 或 false )来决定是否插入 p 元素。
参数 参数在指令后以冒号指明。例如, v-bind 指令被用来响应地更新 HTML 属性:
打开 index.html
,接着添加:
1 2 <br > <pre > <a v-bind:href ="url" > 菜鸟教程</a > </pre >
打开 src/main.js
在 data
中添加
1 url : 'http://localhost:8080'
在这里 href 是参数,告知 v-bind 指令将该元素的 href 属性与表达式 url 的值绑定。
另一个例子是 v-on 指令,它用于监听 DOM 事件:
打开 index.html
,接着添加:
1 <pre > <a v-on:click ="alertMsg" > 弹出警示</a > </pre >
打开 src/main.js
在 methods
中添加
1 2 3 4 5 6 7 8 methods : { description : function ( ) { return this .author + ' - 学的不仅是技术,更是梦想!' }, alertMsg : function ( ) { alert ('弹出警示' ) } }
在这里参数是监听的事件名。
修饰符 修饰符是以半角句号.
指明的特殊后缀,用于指出一个指令应该以特殊方式绑定。例如,.prevent
修饰符告诉 v-on
指令对于触发的事件调用 event.preventDefault()
:
1 <form v-on:submit.prevent ="onSubmit" > </form >
用户输入 在 input 输入框中我们可以使用 v-model 指令来实现双向数据绑定:
双向数据绑定 打开 index.html
,接着添加:
1 2 <p > {{ message }}</p > <input v-model ="message" >
v-model 指令用来在 input、select、textarea、checkbox、radio 等表单控件元素上创建双向数据绑定,根据表单上的值,自动更新绑定的元素的值。
按钮的事件我们可以使用 v-on 监听事件,并对用户的输入进行响应。
以下实例在用户点击按钮后对字符串进行反转操作:
字符串反转 打开 index.html
,接着添加:
1 2 <p > {{ message }}</p > <input v-model ="message" >
在main.js
中的 methods
中添加
1 2 3 reverseMessage : function ( ) { this .message = this .message .split ('' ).reverse ().join ('' ) }
现在大家已经可以知道数据和方法的“存放处”了,接下来就不在详细叙述了,只是走流程。
过滤器 Vue.js 允许你自定义过滤器,被用作一些常见的文本格式化。由”管道符”指示, 格式如下:
1 <h1 > {{ message | reverseMessage }}</h1 >
过滤器函数接受表达式的值作为第一个参数。
以下实例对输入的字符串第一个字母反转
1 2 3 4 5 6 7 8 9 10 11 12 13 filters : { reverseMessage : function (value ) { if (!value) return '' value = value.toString () return value.split ('' ).reverse ().join ('' ) }, capitalize : function (value ) { if (!value) return '' value = value.toString () return value.charAt (11 ).toUpperCase () + value.slice (1 ) } }
过滤器可以串联:
1 <h1 > {{ message |reverseMessage | capitalize }}</h1 >
过滤器是 JavaScript 函数,因此可以接受参数:
1 <h1 > {{ message |reverseMessage | capitalize | addStr('--maxzhao--') }}</h1 >
1 2 3 4 5 addStr: function (value, addStr) { if (!value) return '' value = value.toString() return value + addStr }
这里,message 是第一个参数,字符串 ‘arg1’ 将传给过滤器作为第二个参数, arg2 表达式的值将被求值然后传给过滤器作为第三个参数。
缩写 v-bind 缩写 Vue.js 为两个最为常用的指令提供了特别的缩写:
1 2 <a v-bind:href ="url" > </a > <a :href ="url" > </a > </pre >
v-on 缩写 1 2 3 <a v-on:click ="doSomething" > </a > <a @click ="doSomething" > </a >
起步结束了,下面开始一些有难度的操作(学过之后简直毫无难度)。 Vue.js 条件与循环 条件判断 v-if 指令 条件判断使用 v-if 指令:
在元素 和 template 中使用 v-if 指令:
1 2 3 4 5 <template v-if ="ok" > <h1 > maxzhao</h1 > <p > 学的不仅是技术,更是梦想!</p > <p > 哈哈哈,打字辛苦啊!!!</p > </template >
这里, v-if
指令将根据表达式 ok
的值(true 或 false )来决定是否插入template
元素。
在字符串模板中,如 Handlebars ,我们得像这样写一个条件块:
1 2 3 4 {{#if ok}} <h1 > Yes</h1 > {{/if}}
v-else 指令 可以用 v-else 指令给 v-if 添加一个 “else” 块:
随机生成一个数字,判断是否大于0.5,然后输出对应信息:
1 2 3 4 5 6 <div v-if ="Math.random() > 0.5" > Sorry </div > <div v-else > Not sorry </div >
v-else-if 指令 v-else-if 在 2.1.0 新增,顾名思义,用作 v-if 的 else-if 块。可以链式的多次使用:
判断 type 变量的值:
1 2 3 4 5 6 7 8 9 10 11 12 <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 >
v-else 、v-else-if 必须跟在 v-if 或者 v-else-if之后。
v-show 指令 我们也可以使用 v-show 指令来根据条件展示元素:
1 2 <h1 v-show ="true" > Hello!</h1 > <h1 v-show ="false" > don't show!</h1 >
Vue.js 循环语句 v-for 指令 循环使用 v-for 指令。 v-for 指令需要以 site in sites 形式的特殊语法, sites 是源数据数组并且 site 是数组元素迭代的别名。
v-for 可以绑定数据到数组来渲染一个列表:
1 2 3 4 5 <ol > <li v-for ="site in sites" > {{ site.name }} </li > </ol >
1 2 3 4 5 6 7 data : { sites : [ { name : 'Runoob' }, { name : 'Google' }, { name : 'Taobao' } ] }
模板中使用 v-for:
v-for 迭代对象 v-for 可以通过一个对象的属性来迭代数据:
1 2 3 4 5 <ul > <li v-for ="value in object" > {{ value }} </li > </ul >
1 2 3 4 5 6 7 8 data : { object : { name : '菜鸟教程' , url : 'http://www.runoob.com' , slogan : '学的不仅是技术,更是梦想!' } } })
第二个的参数为键名: 1 2 3 4 5 6 <ul > <li v-for ="(value, key) in object" > {{ key }} : {{ value }} </li > </ul > </div >
第三个参数为索引: 1 2 3 4 5 <ul > <li v-for ="(value, key, index) in object" > {{ index }}. {{ key }} : {{ value }} </li > </ul >
v-for 迭代整数 v-for 也可以循环整数
1 2 3 4 5 <ul > <li v-for ="n in 10" > {{ n }} </li > </ul >
v-for指令界面效果
Vue.js 计算属性 计算属性关键词: computed。
计算属性在处理一些复杂逻辑时是很有用的。
可以看下以下反转字符串的例子:
1 2 3 4 5 6 <div > {{ message.split('').reverse().join('') }} </div > <div > {{ reversedMessage }} </div >
1 2 3 4 5 6 7 computed : { reversedMessage : function ( ) { return this .message .split ('' ).reverse ().join ('' ) } }
实例中声明了一个计算属性 reversedMessage 。
提供的函数将用作属性 vm.reversedMessage 的 getter 。
vm.reversedMessage 依赖于 vm.message,在 vm.message 发生改变时,vm.reversedMessage 也会更新。
computed vs methods 我们可以使用 methods 来替代 computed,效果上两个都是一样的,但是 computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值。而使用 methods ,在重新渲染的时候,函数总会重新调用执行。
可以说使用 computed 性能会更好,但是如果你不希望缓存,你可以使用 methods 属性。
computed setter computed 属性默认只有 getter ,不过在需要时你也可以提供一个 setter :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 var vm = new Vue ({ el : '#vue_det' , data : { }, computed : { reversedMessage : function ( ) { return this .message .split ('' ).reverse ().join ('' ) }, site : { get : function ( ) { return this .author + ' ' + this .slogan }, set : function (newValue ) { var names = newValue.split (' ' ) this .author = names[0 ] this .slogan = names[names.length - 1 ] } } } }) vm.site = 'maxzhao 学的不仅是技术,更是梦想!' document .write ('author: ' + vm.author )document .write ('<br>' )document .write ('slogan: ' + vm.slogan )document .write ('<br>' )document .write ('site: ' + vm.site )
引:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 var cnt=1 ;var vm = new Vue ({ el : '#app' , data : { message : 'Runoob!' }, computed : { reversedMessage : function ( ) { cnt+=1 ; return cnt+this .message .split ('' ).reverse ().join ('' ) } }, methods : { reversedMessage2 : function ( ) { cnt+=1 ; return cnt+this .message .split ('' ).reverse ().join ('' ) } } })
Vue.js 监听属性 本章节,我们将为大家介绍 Vue.js 监听属性 watch,我们可以通过 watch 来响应数据的变化。
以下实例通过使用 watch 实现计数器:
1 2 3 4 <div > <p style ="font-size:25px;" > 计数器: {{ counter }}</p > <button @click ="counter++" style ="font-size:25px;" > 点我</button > </div >
1 2 3 4 5 6 7 8 9 10 var vm = new Vue ({ data : { counter : 1 }); vm.$watch('counter' , function (nval, oval ) { console .log ('计数器值的变化 :' + oval + ' 变为 ' + nval + '!' ); });
千米和米的换算
1 2 3 4 5 <br > <div > 千米 : <input type ="text" v-model ="kilometers" > 米 : <input type ="text" v-model ="meters" > </div >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 data : { kilometers : 0 , meters :0 }, watch : { kilometers : function (newVal, oldVal ) { console .log ('newVal=' + newVal + ' oldVal=' + oldVal) this .kilometers = newVal this .meters = this .kilometers * 1000 }, meters : function (newVal ) { this .kilometers = newVal / 1000 this .meters = newVal } }
控制台为什么会打印两次呢?因为kilometers
改变执行一次,并且改变了 meters
,所以执行的meters
改变(又改变了kilometers
),所以又打印了一次,但因为 meters
在此时并没有改变,所以没有后续触发。
Vue.js 样式绑定 Vue.js class class 与 style 是 HTML 元素的属性,用于设置元素的样式,我们可以用 v-bind 来设置样式属性。
Vue.js v-bind 在处理 class 和 style 时, 专门增强了它。表达式的结果类型除了字符串之外,还可以是对象或数组。
class 属性绑定 我们可以为 v-bind:class 设置一个对象,从而动态的切换 class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <head > <meta charset ="utf-8" > <meta name ="viewport" content ="width=device-width,initial-scale=1.0" > <title > vue_maxzhao</title > <style > .class1 { background : #444 ; color : #eee ; } .active { background : #42b983 ; } .text-danger { background : red; } </style > </head > <div v-bind:class ="{ active: isActive }" > </div > <div class ="active" > </div > <div :class ="{ active: isActive , 'text-danger': true }" > BBBBBBBBBBBBB </div > <div :class ="classObj" > AAAAAAAAAAAAAAAAAAAAAAAAAAA </div > <div :class ="[activeClass, errorClass]" > AAAAAAAAAAAAAAAAAAAAAAAAAAA </div > <div :class ="[activeClass, true?errorClass:'']" > C</div > <div :class ="[activeClass, false?errorClass:'']" > D</div >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 data : { isActive : true , activeClass : 'active' , errorClass : 'text-danger' } computed : { classObj : function ( ) { return { active : true , 'text-danger' : true } } }
Vue.js style(内联样式) 这里的所有操作就不写在 js 中了,表达式等都是可以直接写在页面上的。
1 2 3 4 5 6 7 8 9 10 11 <br > <div :style ="{ color: 'green', fontSize: 30 + 'px' }" > maxzhao_style——普通绑定,'green'、30 为值 </div > <div :style ="{color: 'green',fontSize: '30px'}" > maxzhao_style——对象绑定,{color: 'green',fontSize: '30px'} 是对象 </div > <div :style ="[{color: 'green',fontSize: '30px'},{'font-weight': 'bold'}]" > maxzhao_style——数组对象绑定,[{color: 'green',fontSize: '30px'},{'font-weight': 'bold'}] 是数组对象绑定 </div >
Vue.js 事件处理器 v-on 事件监听可以使用 v-on 指令。
通常情况下,我们需要使用一个方法来调用 JavaScript 方法。
v-on 可以接收一个定义的方法来调用。
1 2 3 4 5 <br > <button v-on:click ="greet" > Greet</button > <button @click ="say('hi')" > Say hi</button > <button @click ="say('what')" > Say what</button >
js 中添加
1 2 3 4 5 6 7 8 9 10 11 12 13 14 methods : { greet : function (event ) { console .log ('Hello ' + this .author + '!' ) if (event) { console .log (event.target .tagName ) } }, say : function (message ) { console .log (message) } }
事件修饰符 Vue.js 为 v-on 提供了事件修饰符来处理 DOM 事件细节,如:event.preventDefault() 或 event.stopPropagation()。
Vue.js通过由点(.)表示的指令后缀来调用修饰符。
.stop
.prevent
.capture
.self
.once
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <br > <a v-on:click.stop ="doThis" > click.stop</a > <form v-on:submit.prevent ="onSubmit" > submit.prevent</form > <a v-on:click.stop.prevent ="doThat" > click.stop.prevent</a > <form v-on:submit.prevent > submit.prevent</form > <div v-on:click.capture ="doThis" > ...</div > <div v-on:click.self ="doThat" > ...</div > <a v-on:click.once ="doThis" > </a > <br >
按键修饰符 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 methods : { clear : function (event ) { console .log ('------ clear ----------' ) if (event) { console .log (event.target .tagName ) } }, submit : function (event ) { console .log ('------ submit ----------' ) if (event) { console .log (event.target .tagName ) console .log (event.keyCode ) } }, doSomething : function (event ) { console .log ('------ doSomething ----------' ) if (event) { console .log (event.target .tagName ) console .log (event.keyCode ) } }
Vue 允许为 v-on 在监听键盘事件时添加按键修饰符:
1 2 <input @keyup.13 ="submit" value ="keyup = 13 " >
记住所有的 keyCode 比较困难,所以 Vue 为最常用的按键提供了别名:
1 2 3 4 5 6 7 8 9 <input v-on:keyup.enter ="submit" value ="keyup = 13 " > <input @keyup.enter ="submit" value ="enter" > <input @keyup.alt.67 ="clear" value ="Alt + C" > <div @click.ctrl ="doSomething" > Ctrl + Click will Do something</div > <br >
全部的按键别名:
.enter
.tab
.delete
(捕获 “删除” 和 “退格” 键)
.esc
.space
.up
.down
.left
.right
.ctrl
.alt
.shift
.meta
Vue.js 表单 可以用 v-model 指令在表单控件元素上创建双向数据绑定。
v-model 会根据控件类型自动选取正确的方法来更新元素。\
常规表单 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 <p > input 元素:</p > <input v-model ="author" placeholder ="编辑我……" > <p > author: {{ author }}</p > <p > textarea 元素:</p > <p style ="white-space: pre" > {{ message }}</p > <textarea v-model ="message" placeholder ="多行文本输入……" > </textarea > <br > <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 > <br > <div > <input type ="radio" id ="cat" value ="cat" v-model ="picked" > <label for ="cat" > cat</label > <br > <input type ="radio" id ="dog" value ="dog" v-model ="picked" > <label for ="google" > dog</label > <br > <span > 选中值为: {{ picked }}</span > </div > <br > <select v-model ="selected" name ="fruit" > <option value ="" > 选择一个网站</option > <option value ="www.baidu.com" > baidu</option > <option value ="www.google.com" > Google</option > </select > <div id ="output" > 选择的网站是: {{selected}} </div >
1 2 3 4 checked : false , checkedNames : [],picked : 'cat' ,selected : ''
修饰符 .lazy 在默认情况下, v-model 在 input 事件中同步输入框的值与数据,但你可以添加一个修饰符 lazy ,从而转变为在 change 事件中同步:
1 2 <input v-model.lazy ="msg" >
.number 如果想自动将用户的输入值转为 Number 类型(如果原值的转换结果为 NaN 则返回原值),可以添加一个修饰符 number 给 v-model 来处理输入值:
1 <input v-model.number ="age" type ="number" >
这通常很有用,因为在 type=”number” 时 HTML 中输入的值也总是会返回字符串类型。
.trim 如果要自动过滤用户输入的首尾空格,可以添加 trim 修饰符到 v-model 上过滤输入:
1 <input v-model.trim ="msg" >
Vue.js 组件component
组件(Component)是 Vue.js 最强大的功能之一。
组件可以扩展 HTML 元素,封装可重用的代码。
组件系统让我们可以用独立可复用的小组件来构建大型应用,几乎任意类型的应用的界面都可以抽象为一个组件树:
全局组件 注册一个全局组件语法格式如下:
1 Vue .component (tagName, options)
tagName 为组件名,options 为配置选项。注册后,我们可以使用以下方式来调用组件:
实例 1 2 3 4 5 6 7 8 9 10 11 12 <script > Vue .component ('maxzhao_all' , { template : '<h1>自定义组件 maxzhao_all !</h1>' }) new Vue ({ el : '#app' }) </script > <maxzhao_all > </maxzhao_all >
局部组件 我们也可以在实例选项中注册局部组件,这样组件只能在这个实例中使用:
1 2 3 <div id ="vue_det" > <maxzhao > </maxzhao > <maxzhao_all > </maxzhao_all >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Vue .component ('maxzhao_all' , { template : '<h1>自定义组件 maxzhao_all ! </h1>' }) var Child = { template : '<h1>自定义组件 maxzhao !</h1>' } var vm = new Vue ({ el : '#vue_det' , components : { 'maxzhao' : Child }
Prop prop 是父组件用来传递数据的一个自定义属性。
父组件的数据需要通过 props 把数据传给子组件,子组件需要显式地用 props 选项声明 “prop”:
1 <maxzhao_all message1 ="hello!" > </maxzhao_all >
1 2 3 4 5 6 Vue .component ('maxzhao_all' , { props : ['message1' ], template : '<h1>自定义组件 maxzhao_all params:{{message1}} ! </h1>' })
首次接触可能会很难理解,其实很简单,就像<div class="class1" ></div>
一样,为当前的div
的 class
的传递一个 class1
的参数。
动态 Prop 1 <maxzhao_all v-bind:message1 ="author" > </maxzhao_all > <maxzhao_all :message1 ="author" > </maxzhao_all >
1 2 3 data : { author : 'maxzhao' }
Prop 实例 1 2 3 4 5 6 7 8 9 10 11 12 13 Vue .component ('todo-item' , { props : ['todo' ], template : '<li>{{ todo.name }}</li>' }) data : { sites : [ { name : 'Runoob' }, { name : 'Google' }, { name : 'Taobao' } ] }
1 2 3 <ol > <todo-item v-for ="item in sites" v-bind:todo ="item" > </todo-item > </ol >
Prop 验证 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 Vue .component ('example' , { props : { propA : Number , propB : [String , Number ], propC : { type : String , required : true }, propD : { type : Number , default : 100 }, propE : { type : Object , default : function ( ) { return { message : 'hello' } } }, propF : { validator : function (value ) { return value > 10 } } } })
type 可以是下面原生构造器:
String
Number
Boolean
Function
Object
Array
type 也可以是一个自定义构造器,使用 instanceof 检测。
自定义事件 父组件是使用 props 传递数据给子组件,但如果子组件要把数据传递回去,就需要使用自定义事件!
我们可以使用 v-on 绑定自定义事件, 每个 Vue 实例都实现了事件接口(Events interface),即:
使用 $on(eventName)
监听事件
使用 $emit(eventName)
触发事件
另外,父组件可以在使用子组件的地方直接用 v-on 来监听子组件触发的事件。
以下实例中子组件已经和它外部完全解耦了。它所做的只是触发一个父组件关心的内部事件。
1 2 3 4 5 6 <div id ="counter-event-example" > <p > {{ total }}</p > <button-counter v-on:increment ="incrementTotal" > </button-counter > <button-counter v-on:increment ="incrementTotal" > </button-counter > </div >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 Vue .component ('button-counter' , { template : '<button v-on:click="incrementHandler">{{ counter }}</button>' , data : function ( ) { return { counter : 0 } }, methods : { incrementHandler : function ( ) { this .counter += 1 this .$emit('increment' ) } } }) var vm = new Vue ({ el : '#vue_det' , data : { total : 0 }, methods : { incrementTotal : function ( ) { this .total += 1 }
这个可能需要解释一下(自己的理解),首先加载当前的button
按钮,当前按钮的click
执行组件的incrementHandler
,然后执行当前组件在html
中的click
事件,为什么要反向执行呢?因为页面中绑定的事件是 当前vue_det
下的事件。
如果你想在某个组件的根元素上监听一个原生事件。可以使用 .native 修饰 v-on 。例如:
1 <my-component v-on:click.native="doTheThing"></my-component>
data 必须是一个函数 上面例子中,可以看到 button-counter 组件中的 data 不是一个对象,而是一个函数:
1 2 3 4 5 data: function () { return { count: 0 } }
这样的好处就是每个实例可以维护一份被返回对象的独立的拷贝,如果 data 是一个对象则会影响到其他实例,如下所示(没有尝试,js基础知识):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <div id ="components-demo3" class ="demo" > <button-counter2 > </button-counter2 > <button-counter2 > </button-counter2 > <button-counter2 > </button-counter2 > </div > <script > var buttonCounter2Data = { count : 0 } Vue .component ('button-counter2' , { data : function ( ) { return buttonCounter2Data }, template : '<button v-on:click="count++">点击了 {{ count }} 次。</button>' }) new Vue ({ el : '#components-demo3' })</script >
Vue.js 自定义指令 除了默认设置的核心指令( v-model 和 v-show ), Vue 也允许注册自定义指令。
下面我们注册一个全局指令 v-focus, 该指令的功能是在页面加载时,元素获得焦点:
全局指令:实例 v-focus
1 2 <p > 页面载入时,input 元素自动获取焦点:</p > <input v-focus >
1 2 3 4 5 6 7 8 Vue .directive ('focus' , { inserted : function (el ) { el.focus () } })
我们也可以在实例使用 directives 选项来注册局部指令,这样指令只能在这个实例中使用:
局部指令:实例 v-focus
把上面的代码注释掉。
1 2 3 4 5 6 7 8 9 10 11 12 13 var vm = new Vue ({ el : '#vue_det' , directives : { focus : { inserted : function (el ) { el.focus () } } } })
钩子 钩子函数 指令定义函数提供了几个钩子函数(可选):
bind
: 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。
inserted
: 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。
update
: 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新(详细的钩子函数参数见下)。
componentUpdated
: 被绑定元素所在模板完成一次更新周期时调用。
unbind
: 只调用一次, 指令与元素解绑时调用。
钩子函数参数 钩子函数的参数有:
el : 指令所绑定的元素,可以用来直接操作 DOM 。
binding: 一个对象,包含以下属性:
name : 指令名,不包括 v-
前缀。
value : 指令的绑定值, 例如: v-my-directive="1 + 1"
, value 的值是 2
。
oldValue : 指令绑定的前一个值,仅在 update
和 componentUpdated
钩子中可用。无论值是否改变都可用。
expression : 绑定值的表达式或变量名。 例如 v-my-directive="1 + 1"
, expression 的值是 "1 + 1"
。
arg : 传给指令的参数。例如 v-my-directive:foo
, arg 的值是 "foo"
。
modifiers : 一个包含修饰符的对象。 例如: v-my-directive.foo.bar
, 修饰符对象 modifiers 的值是 { foo: true, bar: true }
。
vnode : Vue 编译生成的虚拟节点。
oldVnode : 上一个虚拟节点,仅在 update
和 componentUpdated
钩子中可用。
以下实例演示了这些参数的使用:
实例
1 2 3 4 5 6 7 8 9 10 11 12 13 Vue .directive ('maxzhao' , { bind : function (el, binding, vnode ) { var s = JSON .stringify el.innerHTML = 'name: ' + s (binding.name ) + '<br>' + 'value: ' + s (binding.value ) + '<br>' + 'expression: ' + s (binding.expression ) + '<br>' + 'argument: ' + s (binding.arg ) + '<br>' + 'modifiers: ' + s (binding.modifiers ) + '<br>' + 'vnode keys: ' + Object .keys (vnode).join (', ' ) } })
有时候我们不需要其他钩子函数,我们可以简写函数,如下格式:
1 <div v-maxzhao_dir:a.b.c ='message' v-maxzhao_color ="{ color: 'green', text: 'maxzhao' }" > </div >
1 2 3 4 Vue .directive ('maxzhao_color' , function (el, binding ) { el.style .backgroundColor = binding.value .color })
指令函数可接受所有合法的 JavaScript 表达式,以下实例传入了 JavaScript 对象:
1 2 3 4 5 Vue .directive ('maxzhao_color' , function (el, binding ) { el.innerHTML = binding.value .text el.style .backgroundColor = binding.value .color })
Vue.js 路由(终于到了激动人心,阔步前进的时刻) 本章节我们将为大家介绍 Vue.js 路由。
Vue.js 路由允许我们通过不同的 URL 访问不同的内容。
通过 Vue.js 可以实现多视图的单页Web应用(single page web application,SPA)。
Vue.js 路由需要载入 vue-router 库
中文文档地址:vue-router文档 。
打住:如果是按照本文的安装方式,则默认已经安装了路由
安装 1、直接下载 / CDN 1 wget https://unpkg.com/vue-router/dist/vue-router.js
2、NPM 推荐使用淘宝镜像:
简单实例 Vue.js + vue-router 可以很简单的实现单页应用。
是一个组件,该组件用于设置一个导航链接,切换不同 HTML 内容。 to 属性为目标地址, 即要显示的内容。
以下实例中我们将 vue-router 加进来,然后配置组件和路由映射,再告诉 vue-router 在哪里渲染它们。
HTML代码如下 1 2 3 4 5 6 7 8 9 10 11 12 13 <div id ="app-router-demo" > <h1 > Hello App!</h1 > <p > <router-link to ="/foo" > Go to Foo</router-link > <router-link to ="/bar" > Go to Bar</router-link > </p > <router-view > </router-view > </div >
JavaScript 代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 const Foo = { template : '<div>foo</div>' }const Bar = { template : '<div>bar</div>' }const routes = [ { path : '/foo' , component : Foo }, { path : '/bar' , component : Bar } ] const router = new VueRouter ({ routes }) const app = new Vue ({ router }).$mount('#app-router-demo' )
打眼一看,怎么还是和安装的不一样?这时候的我也是一脸懵逼。先尝试一下这个。最终还是不行,因为new VueRouter
这个是直接报错的。采用当前的方式引入:
1 2 3 4 5 6 7 8 9 10 11 12 import VueRouter from 'vue-router' Vue .use (Router )export default new Router ({ routes : [ { path : '/' , name : 'HelloWorld' , component : HelloWorld } ] })
接下来我把教程的所有代码都删掉了,直接看脚手架的源码。
直接上手脚手架 为了方便阅读,把router/index.js
改为router/indexRouter.js
,此时,会有 test/unit/jest.conf.js
中的 js 路径修改。
当我想把indexRouter.js
移动到components
目录下的时候,发现界面报错了。
1 2 3 4 5 6 7 ERROR Failed to compile with 2 errors These dependencies were not found: * vue-router/types in ./src/router/indexRouter.js * vue/types in ./src/router/indexRouter.js To install them, you can run: npm install --save vue-router/types vue/types
我就按照提示进行了安装
1 2 3 npm install --save vue-router/types vue/types # 报错 找不到 赶紧 npm i 一下
提示:此处有一个build/webpack.base.conf.js
文件下的 1 2 3 4 5 6 7 8 9 10 11 module .exports = { resolve : { extensions : ['.js' , '.vue' , '.json' ], alias : { 'vue$' : 'vue/dist/vue.esm.js' , '@' : resolve ('src' ), } },
提示: /home/maxzhao/code/vue/vue_maxzhao/src/router/index.js
文件下 1 2 3 4 5 6 7 8 9 10 export default new Router ({ routes : [ { path : '/' , name : 'HelloWorld' , component : HelloWorld } ] })
导出多个对象
1 2 3 4 export const str = 'hello world' ;export function f (a ){ return a+1 ;}import { str, f } from 'demo1'
实践 在src/router/index.js
中插入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import Vue from 'vue' import Router from 'vue-router' import HelloWorld from '@/components/HelloWorld' import HelloMaxzhao from '@/components/HelloMaxzhao' Vue .use (Router )export default new Router ({ routes : [ { path : '/' , name : 'HelloWorld' , component : HelloWorld }, { path : '/hello_maxzhao' , name : 'HelloMaxzhao' , component : HelloMaxzhao } ] })
新建src/components/HelloMaxzhao.vue
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 <template > <div class ="hello" > <h1 > {{ msg }}</h1 > <h2 > author:{{author}}</h2 > </div > </template > <script > export default { name : 'HelloMaxzhao' , data () { return { msg : 'Hello MaxZhao' , author : 'maxzhao' } } } </script > <style scoped > h1 , h2 { font-weight : normal; } </style >
浏览器访问:http://localhost:8080/#/hello_maxzhao
点击过的导航链接都会加上样式 **class =”router-link-exact-active router-link-active”**。
<router-link>
相关属性接下来我们可以了解下更多关于 的属性。
to 表示目标路由的链接。 当被点击后,内部会立刻把 to 的值传到 router.push(),所以这个值可以是一个字符串或者是描述目标位置的对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <router-link to ="/hello_maxzhao" > to /hello_maxzhao</router-link > <br > <router-link to ="hello_maxzhao" > hello_maxzhao</router-link > <br > <a href ="#/hello_maxzhao" > a href=hello_maxzhao</a > <br > <router-link v-bind:to ="'hello_maxzhao'" > v-bind:to hello_maxzhao</router-link > <br > <router-link :to ="'hello_maxzhao'" > :to hello_maxzhao</router-link > <br > <router-link :to ="{ path: 'hello_maxzhao' }" > :to="{ path: 'hello_maxzhao' }"</router-link > <br > <router-link :to ="{ name: 'HelloMaxzhao', params: { userId: 123 }}" > 命名的路由 HelloMaxzhao</router-link > <br > <router-link :to ="{ path: 'hello_maxzhao', query: { plan: 'private' }}" > 带查询参数 hello_maxzhao</router-link >
replace 设置 replace 属性的话,当点击时,会调用 router.replace() 而不是 router.push(),导航后不会留下 history 记录。
1 <router-link :to ="{ path: '/abc'}" replace > </router-link >
append 设置 append 属性后,则在当前 (相对) 路径前添加基路径。例如,我们从 /a 导航到一个相对路径 b,如果没有配置 append,则路径为 /b,如果配了,则为 /a/b
1 <router-link :to="{ path: 'relative/path'}" append></router-link>
tag 有时候想要 <router-link>
渲染成某种标签,例如 <li>
。 于是我们使用 tag
prop 类指定何种标签,同样它还是会监听点击,触发导航。
1 2 3 <router-link to ="/foo" tag ="li" > foo</router-link > <li > foo</li >
active-class 设置 链接激活时使用的 CSS 类名。可以通过以下代码来替代。
1 2 3 4 5 6 7 8 9 <style > ._active{ background-color : red; } </style > <p > <router-link v-bind:to = "{ path: '/route1'}" active-class = "_active" > Router Link 1</router-link > <router-link v-bind:to = "{ path: '/route2'}" tag = "span" > Router Link 2</router-link > </p >
注意这里 class 使用 **active_class=”_active”**。
exact-active-class 配置当链接被精确匹配的时候应该激活的 class。可以通过以下代码来替代。
1 2 3 4 <p > <router-link v-bind:to = "{ path: '/route1'}" exact-active-class = "_active" > Router Link 1</router-link > <router-link v-bind:to = "{ path: '/route2'}" tag = "span" > Router Link 2</router-link > </p >
router-link 默认情况下的路由是模糊匹配,例如当前路径是 /article/1 那么也会激活 ,所以当设置 exact-active-class 以后,这个 router-link 只有在当前路由被全包含匹配时才会被激活 exact-active-class 中的 class,例如:
1 <router-link to ="/article" active-class ="router-active" > </router-link >
当用户访问 /article/1 时会被激活为:
1 <a href ="#/article" class ="router-active" rel ="nofollow" > </a >
而当使用:
1 <router-link to ="/article" exact-active-class ="router-active" > </router-link >
当用户访问 /article/1 时,不会激活这个 link 的 class:
1 <a href ="#/article" rel ="nofollow" > </a >
event 声明可以用来触发导航的事件。可以是一个字符串或是一个包含字符串的数组。
1 <router-link v-bind:to = "{ path: '/route1'}" event = "mouseover" > Router Link 1</router-link >
以上代码设置了 event 为 mouseover ,及在鼠标移动到 Router Link 1 上时导航的 HTML 内容会发生改变。
NPM 路由实例 接下来我们演示了一个使用 npm 简单的路由实例,开始前,请先下载该实例源代码:
路由实例
你也可以在 Github 上下载:https://github.com/chrisvfritz/vue-2.0-simple-routing-example
下载完后,解压该目录,重命名目录为 vue-demo,vu 并进入该目录,执行以下命令:
1 2 3 4 5 # 安装依赖,使用淘宝资源命令 cnpm cnpm install # 启动应用,地址为 localhost:8080 cnpm run dev
如果你需要发布到正式环境可以执行以下命令:
执行成功后,访问 http://localhost:8080 即可看到如下界面:
beforeEach 跳转路由前 1 2 3 router.beforeEach ((to, from , next ) => { });
afterEach 跳转路由后 1 2 3 router.afterEach (() => { NProgress .done (); });
Vue.js 混入 混入 (mixins)定义了一部分可复用的方法或者计算属性。混入对象可以包含任意组件选项。当组件使用混入对象时,所有混入对象的选项将被混入该组件本身的选项。
来看一个简单的实例:
实例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 var myMixin = { created : function ( ) { this .startmixin () }, methods : { startmixin : function ( ) { document .write ('欢迎来到混入实例' ) } } } var Component1 = Vue .extend ({ mixins : [myMixin] }) new Component1 ()
选项合并 当组件和混入对象含有同名选项时,这些选项将以恰当的方式混合。
比如,数据对象在内部会进行浅合并 (一层属性深度),在和组件的数据发生冲突时以组件数据优先 。
以下实例中,Vue 实例与混入对象包含了相同的方法。从输出结果可以看出两个选项合并了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 var mixin = { created : function ( ) { document .write ('混入调用' + '<br>' ) } } new Vue ({ el : '#app' , router, components : {App }, template : '<App/>' , mixins : [mixin], created : function ( ) { document .write ('组件调用' + '<br>' ) } })
输出结果为:
如果 methods 选项中有相同的函数名,则 Vue 实例优先级会较高。如下实例,Vue 实例与混入对象的 methods 选项都包含了相同的函数:
相同的函数名 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 var mixin = { methods : { hellworld : function ( ) { document .write ('HelloWorld 方法' + '<br>' ); }, samemethod : function ( ) { document .write ('Mixin:相同方法名' + '<br>' ); } } } var vm = new Vue ({ el : '#app' , router, components : {App }, template : '<App/>' , mixins : [mixin], methods : { start : function ( ) { document .write ('start 方法' + '<br>' ); }, samemethod : function ( ) { document .write ('Main:相同方法名' + '<br>' ); } } }) vm.hellworld (); vm.start (); vm.samemethod ();
输出结果为:
1 2 3 HelloWorld 方法 start 方法 Main:相同方法名
以上实例,我们调用了以下三个方法:
1 2 3 vm.hellworld(); vm.start(); vm.samemethod();
从输出结果 methods 选项中如果碰到相同的函数名则 Vue 实例有更高的优先级会执行输出。并且全局方法不执行。
全局混入 也可以全局注册混入对象。注意使用! 一旦使用全局混入对象,将会影响到 所有 之后创建的 Vue 实例。使用恰当时,可以为自定义对象注入处理逻辑。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Vue .mixin ({ created : function ( ) { var myOption = this .$options .myOption ; if (myOption) { console .log (this .$options ) document .write (myOption) } } }) var vm = new Vue ({ el : '#app' , router, components : {App }, template : '<App/>' , myOption : 'hello!' })
谨慎使用全局混入对象,因为会影响到每个单独创建的 Vue 实例 (包括第三方模板)。
Vue.js Ajax(vue-resource) Vue 要实现异步加载需要使用到 vue-resource 库。
1 <script src="https://cdn.staticfile.org/vue-resource/1.5.1/vue-resource.min.js"></script>
Get 请求 以下是一个简单的 Get 请求实例,请求地址是一个简单的 txt 文本:
如果需要传递数据,可以使用 this.$http.get(‘get.php’,{params : jsonData}) 格式,第二个参数 jsonData 就是传到后端的数据。
1 2 3 4 5 this.$http.get('get.php',{params : {a:1,b:2}}).then(function(res){ document.write(res.body); },function(res){ console.log(res.status); });
post 请求 post 发送数据到后端,需要第三个参数 **{emulateJSON:true}**。
emulateJSON 的作用: 如果Web服务器无法处理编码为 application/json 的请求,你可以启用 emulateJSON 选项。
demo_test_post.php 代码如下:
1 2 3 4 5 6 7 <?php $name = isset($_POST['name']) ? htmlspecialchars($_POST['name']) : ''; $city = isset($_POST['url']) ? htmlspecialchars($_POST['url']) : ''; echo '网站名: ' . $name; echo "\n"; echo 'URL 地址: ' .$city; ?>
语法 & API 你可以使用全局对象方式 Vue.http 或者在一个 Vue 实例的内部使用 this.$http来发起 HTTP 请求。
1 2 3 4 5 6 7 // 基于全局Vue对象使用http Vue.http.get('/someUrl', [options]).then(successCallback, errorCallback); Vue.http.post('/someUrl', [body], [options]).then(successCallback, errorCallback); // 在一个Vue实例内使用$http this.$http.get('/someUrl', [options]).then(successCallback, errorCallback); this.$http.post('/someUrl', [body], [options]).then(successCallback, errorCallback);
vue-resource 提供了 7 种请求 API(REST 风格):
1 2 3 4 5 6 7 get(url, [options]) head(url, [options]) delete(url, [options]) jsonp(url, [options]) post(url, [body], [options]) put(url, [body], [options]) patch(url, [body], [options])
除了 jsonp 以外,另外 6 种的 API 名称是标准的 HTTP 方法。
options 参数说明:
参数
类型
描述
url
string
请求的目标URL
body
Object
, FormData
, string
作为请求体发送的数据
headers
Object
作为请求头部发送的头部对象
params
Object
作为URL参数的参数对象
method
string
HTTP方法 (例如GET,POST,…)
timeout
number
请求超时(单位:毫秒) (0
表示永不超时)
before
function(request)
在请求发送之前修改请求的回调函数
progress
function(event)
用于处理上传进度的回调函数 ProgressEvent
credentials
boolean
是否需要出示用于跨站点请求的凭据
emulateHTTP
boolean
是否需要通过设置X-HTTP-Method-Override
头部并且以传统POST方式发送PUT,PATCH和DELETE请求。
emulateJSON
boolean
设置请求体的类型为application/x-www-form-urlencoded
通过如下属性和方法处理一个请求获取到的响应对象:
属性
类型
描述
url
string
响应的 URL 源
body
Object
, Blob
, string
响应体数据
headers
Header
请求头部对象
ok
boolean
当 HTTP 响应码为 200 到 299 之间的数值时该值为 true
status
number
HTTP 响应码
statusText
string
HTTP 响应状态
方法
类型
描述
text()
约定值
以字符串方式返回响应体
json()
约定值
以格式化后的 json 对象方式返回响应体
blob()
约定值
以二进制 Blob 对象方式返回响应体
axios(听说比vueresource更好) 基于promise用于浏览器和node.js的http客户端
特点
支持浏览器和node.js
支持promise
能拦截请求和响应
能转换请求和响应数据
能取消请求
自动转换JSON数据
浏览器端支持防止CSRF(跨站请求伪造)
安装 npm安装
bower安装
通过cdn引入
1 <script src="https://unpkg.com/axios/dist/axios.min.js" ></script>
例子 发起一个GET
请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 axios.get ('/user?ID=12345' ) .then (function (response ) { console .log (response); }) .catch (function (error ) { console .log (error); }); axios.get ('/user' , { params : { ID : 12345 } }) .then (function (response ) { console .log (response); }) .catch (function (error ) { console .log (error); });
发起一个POST
请求
1 2 3 4 5 6 7 8 9 10 axios.post ('/user' , { firstName : 'Fred' , lastName : 'Flintstone' }) .then (function (response ) { console .log (response); }) .catch (function (error ) { console .log (error); });
同时发起多个请求
1 2 3 4 5 6 7 8 9 10 11 12 function getUserAccount ( ) { return axios.get ('/user/12345' ); } function getUserPermissions ( ) { return axios.get ('/user/12345/permissions' ); } axios.all ([getUserAccount (), getUserPermissions ()]) .then (axios.spread (function (acct, perms ) { }));
官方地址:http://www.axios-js.com/zh-cn/docs/
其它插件 NProgress 进度条 1 2 3 4 NProgress .start () NProgress .set (0.4 )NProgress .inc () NProgress .done ()
vuedraggable 拖动 vue-count-to 数字滚动 showdown 使页面支持 markdown Mock.mock() 拦截请求响应数据 参考
问题 Failed to mount component: template or render function not defined. 1 2 3 4 5 6 7 [Vue warn]: Failed to mount component : template or render function not defined. found in ---> <Anonymous > <App > at src/App .vue <Root >
因为 vue
版本高了,需要在 require
之后 加上 default, 来指定文件中的 export default
1 2 Try adding .default to the end of your require ().component : require ('./index/index.vue' ).default
只能少传参,不能多传、错传参数。
1 2 3 let thisDetail = pick(that.detail, 'money' , 'goodsName' , 'remark' , 'delStatus' , 'expenseTime' ); that.form.setFieldsValue(thisDetail);
本文地址: https://github.com/maxzhao-it/blog/post/36127/