1. bind
<span>v-bind:title="message"</span>
2. if
<p>v-if="seen"</p>
3. v-for 指令可以绑定数组的数据来渲染一个项目列表
<li v-for="todo in todos">
{{ todo.text }}
</li>
data:{
todos:[
{text:'a'},
{text:'b'},
{text:'c'}
]
}
4. v-on 指令绑定一个事件监听器,调用实例中定义的方法
<button v-on:click="reverseMessage">nizhuan</button>
methods:{
reverseMessage:function(){
this.message='aaa'
}
}
5. v-model 表单输入和应用状态之间的双向绑定
<p>{{ message }} </p>
<input v-model="message"/>
6. 组件
Vue 中注册组件
Vue.component('todo-item',{
props:['todo'],
templdate:'<li>{{ todo.text }}</li>'
})
构建另一个组件模板
<ol>
<todo-item v-for="item in groceryList" v-bind="item"></todo-item>
</ol>
var app7 = new Vue({
el:'#app-7',
data:{
groceryList:[
{text:'shucai'},
{text:'nailao'},
{text:'suibian'}
]
}
})
模板语法
1. 文本
1. {{ msg }}
2. v-once 当数据改变时,插值处的内容不会更新
<span v-once>this will never changed{{ msg }}</span>
2. 纯html
双大括号会将数据解释为纯文本,而非 HTML 。为了输出真正的 HTML ,你需要使用 v-html 指令
<div v-html="rawHtml"></dvi>
3. 属性
Mustache 不能在 HTML 属性中使用,应使用 v-bind 指令
<div v-bind:id="dynamicId"></div>
<button v-bind:disabled="someDynamicCondition">Button</button>
4. javascript表达式
{{ number + 1 }}
{{ ok ? 'YES' : 'NO' }}
{{ message.split('').reverse().join('') }}
<div v-bind:id="'last-'+id"></div>
<!-- 这是语句,不是表达式 -->
{{ var a = 1 }}
<!-- 流控制也不会生效,请使用三元表达式 -->
{{ if (ok) { return message } }}
5. 指令 Directives
指令(Directives)是带有 v- 前缀的特殊属性。指令属性的值预期是单一 JavaScript 表达式(除了 v-for,之后再讨论)
<p v-if="seen">Now you see me </p>
6. 参数
一些指令能接受一个“参数”,在指令后以冒号指明
v-bind 指令被用来响应地更新 HTML 属性
<a v-bind:href="url"></a>
v-on 用于监听DOM事件
<a v-on:click="dosomething">
7. 修饰符
修饰符(Modifiers)是以半角句号 . 指明的特殊后缀,用于指出一个指令应该以特殊方式绑定
.prevent 修饰符告诉 v-on 指令对于触发的事件调用 event.preventDefault()
<from v-on:submit.prevent="onSubmit"></form>
8. 过滤器
过滤器可以用在两个地方:mustache 插值和 v-bind 表达式
因为过滤器设计目的就是用于文本转换,为了在其他指令中实现更复杂的数据变换,你应该使用计算属性
{{ message | capitalize }}
<div v-bind:id="rawId | formatId"></div>
new Vue({
filters:{
capitalize:function(value){
if(!value) return ''
value = value.toString()
return value.charAt(0).toUpperCase()+value.Slice(1)
}
}
})
过滤器嵌套
{{ message | filterA | filterB }}
过滤器本身时js函数,所以可以传参,
{{ message | filterA('arg1', arg2) }}
这里,字符串 'arg1' 将传给过滤器作为第二个参数, arg2 表达式的值将被求值然后传给过滤器作为第三个参数
9. 缩写
v-bind 缩写
<a v-bind:href="url"></a>
<a :href="url"></a>
v-on 缩写
<a v-on:click="dosomething"></a>
<a @click="dosomething"></a>
计算属性
对于任何复杂的逻辑,使用计算属性
1. basic
var vm= new Vue({
el:'#example',
data:{
message:'Hello'
},
computed:{
reverseMessage:function(){
//直接调用处理
return this.message.split(' ').reverse().join('');
}
}
})
<div id="example">
<p>Original message: "{{ message }}</p>
<p>Computed message: "{{ reverseMessage }}</p>
</div>
console.log(vm.reverseMessage)
vm.message="Goodbye"
console.log(vm.reverseMessage)
你可以像绑定普通属性一样在模板中绑定计算属性。 Vue 知道 vm.reversedMessage 依赖于 vm.message
计算缓存-vs-Methods
计算属性是基于它们的依赖进行缓存的,计算属性只有在它的相关依赖发生改变时才会重新求值
如果你不希望有缓存,请用 method 替代
Computed属性vs Watched 属性
Vue 确实提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:watch 属性
当你有一些数据需要随着其它数据变动而变动时,你很容易滥用 watch
然而,通常更好的想法是使用 computed 属性而不是命令式的 watch 回调
<div id="demo">{{ fullName }}</div>
var vm = new Vue({
el:'#demo',
data:{
firstName:'foo',
lastName:'Bar',
fullName:'foo Bar'
},
watch:{
firstName:function(val){
this.fullName=val+' ' +this.lastName
},
lastName:function(val){
this.fullName=val+' ' +this.lastName
}
}
})
使用computed属性
var vm = new Vue({
el: '#demo',
data:{
firstName:'foo',
lastName:'Bar',
},
computed:{
fullName:function(){
return this.firstName +' ' +this.lastName;
}
}
})
计算属性setter
默认只有getter,可以提供
computed:{
fullName:{
get:function(){
return this.firstName +' ' +this.lastName;
},
set:function(newValue){
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length-1]
}
}
}
观察 Watchers
虽然计算属性在大多数情况下更合适,但有时也需要一个自定义的 watcher
并在我们得到最终结果前,设置中间状态。这是计算属性无法做到的
watch:{
//question属性发生改变,这个函数就会运行
question:function(newQuestion){
this.answer="";
this.getAnswer()
}
},
methods:{
getAnswer:_.debounce(function(){
...
})
}
Class和Style绑定
绑定Class和内联style是v-bind:xxx="class or style"
不过,字符串拼接麻烦又易错。因此,在 v-bind 用于 class 和 style 时, Vue.js 专门增强了它
绑定Html Class
我们可以传给 v-bind:class 一个对象,以动态地切换 class
<div class="static" v-bind:class="{ active:isActive,'text-danger':hasError }></div>
data:{
isActive:true,
hasError:false
}
<div class="static active"></div>
2. 直接绑定一个对象
<div v-bind:class="classObject"></div>
data:{
classObject:{
active: true,
'text-danger': false
}
}
3. 计算属性。这是一个常用且强大的模式
<div v-bind:class="classObject"></div>
data:{
isActive:true,
error:null
},
computed:{
classObject:function(){
return{
active: this.isActvie && !this.error,
'text-danger':this.error&& this.error.type==='fatal'
}
}
}
4. 数组语法
<div v-bind:class="[activeClass,errorClass]"></div>
<div v-bind:class="[isActive ? activeClass : '', errorClass]">
<div v-bind:class="[{ active: isActive }, errorClass]">
data:{
activeClass:'active',
errorClass:'text-danger'
}
绑定内联样式
v-bind:style 看起来非常像css
1. basic
<div v-bind:style="{ color: activeColor, fontSize:fontSize + 'px' }></div>
data:{
activeColor:'red',
fontSize:30
}
2. 绑定对象,让模板更清晰
<div v-bind:style="{styleObject}"></div>
data: {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
3. 同样使用计算属性
4. 数组语言发
<div v-bind:style="[baseStyles,overridingStyle]"></div>
条件渲染
1. v-if v-else
<h1 v-if="ok">Yes</h1>
<h1 v-else>No</h1>
2. <template>中v-if
<template v-if="ok">
<h1>Title</h1>
</template>
3. v-else
<div v-if="Math.random()>0.5">
Now you see me
</div>
<div v-else>
Now you don't
</div>
4. v-else-if
<div v-if="type === A">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else>
other
</div>
5. key 管理可复用的元素,不想复用的时候使用key
Vue 为你提供了一种方式来声明“这两个元素是完全独立的——不要复用它们
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address" key="email-input">
</template>
6. v-show
简单的切换display,会一直保留在DOM中
v-show不支持 <templdate>语法 也不支持 v-else
v-if vs v-show
v-if 是“真正的”条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
一般来说, v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销
因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件不太可能改变,则使用 v-if 较好
v-if 和 v-for 一起使用
v-for 具有比v-if更高的优先级
列表渲染
1. 可选的第二个index参数
<li v-for="(item,index) in items">
{{ parentMessage }} -{{ index }} - {{ item.message }}
</li>
2. of 替代 in
<li v-for="(item,index) of items"></li>
3. template
<ul>
<template v-for="item in items">
<li>{{ item.msg }}</li>
<li class="divider"></li>
</template>
</ul>
4. 对象迭代 v-for,迭代一个对象的属性,而不是通常的集合
<li v-for="value in object">
{{ value }}
</li>
new Vue({
data:{
object:{
FirstName:'john',
LastName:'Doe',
Age:58
}
}
})
<div v-for="(value ,key) in object">
{{ key }} : {{ value }}
</div>
<div v-for="(value, key, index) in object">
{{ index }}.{{ key }} : {{ value }}
</div>
在遍历对象时,是按 Object.keys() 的结果遍历,但是不能保证它的结果在不同的 JavaScript 引擎下是一致的
5. 整数迭代 v-for
<span v-for="n in 10">{{ n }}</span>
6. 组件和v-for
你可以像任何普通元素一样用 v-for
<my-compontent v-for="(item, idnex) in items"
v-bind:item="item"
v-bind:index="index">
</my-compontent>
7. key
<div v-for="item in items" :key="item.id">
</div>
建议尽可能使用 v-for 来提供 key ,除非迭代 DOM 内容足够简单,或者你是故意要依赖于默认行为来获得性能提升。
因为它是 Vue 识别节点的一个通用机制, key 并不特别与 v-for 关联,key 还具有其他用途,我们将在后面的指南中看到其他用途。
8. 数组更新检测
1. 变异方法
push(),pop(),shift(),unshift(),splice(),sort(),reverse()
2. 重塑数组
filter(),concat(),slice() 这些非变异方法,也可以使得新数组替换旧数组
example.items = example1.items.filter(function(){
return item.message.match(/Foo/)
})
3. 注意
以下两种不能更新检测
1. 当用索引设置一个项时
vm.item[0]=newvlaue;
解决方法
1. Vue.set(example.items,indexOfItem,newVlaue)
2. example1.items.splice(indexOfitem,1,newVlaue)
2. 修改数组长度时
vm.items.length=newlength;
解决方法
example1.items.splice(newlength)
splice(index,howmany,item1,...itemx)
index 位置
howmany:要删除元素的个数,0表示不删除
http://www.w3school.com.cn/jsref/jsref_splice.asp
事件处理器
1. $event 获取原生DOM中的e
<button v-on:click="warn('message',$event)"></button>
methods: {
warn: function (message,event) {
if (event) event.preventDefault()
alert(message)
}
}
2. 事件修饰符号
在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。
尽管我们可以在 methods 中轻松实现这点,但更好的方式是:methods 只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。
.stop //stopPropagation
.prevent //preventDefault
.capture // 添加事件侦听器时使用事件捕获模式
.self //只当事件在该元素本身(而不是子元素)触发时触发回调
.once //点击事件将只会触发一次
<form v-on:submit.prevent="onSubmit"></form>
<a v-on:click.stop.prevent="doThat"></a>
<!-- 只有修饰符 -->
<form v-on:submit.prevent></form>
3. 按键修饰符号
在监听键盘事件时,我们经常需要监测常见的键值。 Vue 允许为 v-on 在监听键盘事件时添加按键修饰符
<!-- 只有在 keyCode 是 13 时(按回车)调用 vm.submit() -->
以下三种写法都可以
<input v-on:keyup.13="submit">
使用别名
<input v-on:keyup.enter="submit">
省写
<input @keyup.enter="submit">
.enter
.tab
.delete
.esc
.space
.up
.down
.left
.right
.ctrl
.alt
.shift
.meta //meta对应命令键 (⌘)。在Windows系统键盘meta对应windows徽标键(⊞)。在Sun操作系统键盘上,meta对应实心宝石键 (◆)
可以通过全局 config.keyCodes 对象自定义按键修饰符别名:
Vue.config.keyCodes.f1 = 112
<input @keyup.alt.67="clear">
<!-- Ctrl + Click -->
<div @click.ctrl="doSomething">Do something</div>
为什么在HTML中监听事件按
你可能注意到这种事件监听的方式违背了关注点分离(separation of concern)传统理念。
不必担心,因为所有的 Vue.js 事件处理方法和表达式都严格绑定在当前视图的 ViewModel 上,
它不会导致任何维护上的困难。实际上,使用 v-on 有几个好处:
1. 扫一眼 HTML 模板便能轻松定位在 JavaScript 代码里对应的方法。
2. 因为你无须在 JavaScript 里手动绑定事件,你的 ViewModel 代码可以是非常纯粹的逻辑,和 DOM 完全解耦,更易于测试。
3. 当一个 ViewModel 被销毁时,所有的事件处理器都会自动被删除。你无须担心如何自己清理它们。
表单控件绑定
1. basic
v-model 本质上不过是语法糖,它负责监听用户的输入事件以更新数据,并特别处理一些极端的例子
v-model 并不关心表单控件初始化所生成的值。因为它会选择 Vue 实例数据来作为具体的值。
对于要求 IME (如中文、 日语、 韩语等) 的语言,你会发现那v-model不会在 ime 构成中得到更新。如果你也想实现更新,请使用 input事件。
2. 绑定checkbox
<input type="checkbox" value="a" v-model="checkedNames"/>
<input type="checkbox" value="b" v-model="checkedNames"/>
<input type="checkbox" value="c" v-model="checkedNames"/>
<span>{{ checkedNames }}</span>
data: {
checkedNames: []
}
3. 单选按钮
<input type="radio" value="one" v-model="picked"/>
<input type="radio" value="two" v-model="picked"/>
<span>{{ picked }}</span>
4. select 绑定及渲染
<select v-model="selected">
<option v-for="option in options" v-bind:value="option.value">
{{ option.text }}
</option>
</select>
data: {
option: [
{text:'one' value:'A'},
{text:'two' value:'B'},
{text:'three' value:'C'},
{text:'four' value:'D'}
]
}
5. 绑定value
使用v-bind 动态绑定 和 v-model 结合
1. 复选框
<input type="checkbox" v-model="toggle" v-bind:true-value="a" v-bind:false-value="b">
当选中时 vm.toggle === vm.a
未选中时 vm.toggle === vm.b
2. 单选框
<input type="radio" v-model="pick" v-bind:value="a">
当选中时 vm.pick === vm.a
3. select
<select v-model="selected">
<!-- 内联对象字面量 -->
<option v-bind:value="{ number: 123 }">123</option>
</select>
当选中时
typeof vm.selected
vm.selected.number
6. 修饰符
.lazy //<!-- 在 "change" 而不是 "input" 事件中更新 -->
<input v-model.lazy="msg">
.number //如果想自动将用户的输入值转为 Number 类型
<input v-model.number="age" type="number">
.trim //过滤首尾空格
<input v-model.trim="msg"
组件
组件(Component)是 Vue.js 最强大的功能之一。组件可以扩展 HTML 元素,封装可重用的代码。在较高层面上,组件是自定义元素
1. 注册
1. 注册一个全局组件,使用Vue.component(tagname,option)
Vue.component('my-component',{})
2. 局部注册
new Vue({
components:{
'my-component':{}
}
})
2. DOM 模板解析说明
table中限制不能出现my-row,会导致解析错误
<table>
<my-component>...</my-component>
</table>
解决方法使用is属性
<table>
<tr is="my-component"></tr>
</table>
3. data必须是函数
这是一个非常特殊的地方,因为如果不是的话,多个组件的属性会共享
4. 构成组件
父组件通过props向下传递给子组件
子组件tongueevents给父组件发送消息
1. Prop
子组件要显式地用 props 选项声明它期待获得的数据
Vue.component('child',{
props: ['message'],
template: '<span> {{ message }}</span>'
})
传入一个普通字符串
<child message="heelo!"></child>
2. camelCase vs kebab-case
HTML 特性是不区分大小写的。所以,当使用的不是字符串模版,camelCased (驼峰式) 命名的 prop 需要转换为相对应的 kebab-case (短横线隔开式) 命名:
Vue.component('click',{
props:['myMessage'],
template: '<span>{{ myMessage }}</span>'
})
<child my-message='Hello!'></child>
3. 动态Prop,使用v-bind 绑定属性
<input v-model="parentMsg">
<child v-bind:my-message="parentMsg"></child>
简写
<child :my-message="parentMsg"></child>
4. 字面量语法vs动态语法
<!--传递了一个字符串1-->
<comp some-prop="1"></comp>
<!-- 传递真实的number -->
<comp :some-prop="1"></comp>
5. 单项数据流
不要在子组件中修改prop,最多修改它的拷贝,可以用计算属性代替
prop:['initalCounter'],
data:function(){
return {counter:this.initialCounter}
},
computed:{
normalizedSize:function(){
return this.initalCounter.trim().tolowerCase
}
}
如果是数组的话,也要拷贝一份再操作,否则直接修改的话,也会导致修改props,而导致影响父组件,那为什么vue不帮我们拷贝一下呢
6. Prop验证
props: {
// 基础类型检测 (`null` 意思是任何类型都可以)
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
}
}
原生构造器
String
Number
Boolean
Function
Object
Array
当 prop 验证失败,Vue会在抛出警告 (如果使用的是开发版本)。
7.自定义事件
子组件要把数据传递回去给父组件
1. 使用v-on绑定自定义事件
每个 Vue 实例都实现了事件接口(Events interface),即:
使用 $on(eventName) 监听事件
使用 $emit(eventName) 触发事件
<p>{{ total }}</p>
<button-counter v-on:increment="incrementTotal"></button>
<button-counter v-on:increment="incrementTotal"></button>
Vue.component('button-counter', {
template: '<button v-on:click="increment">{{ counter }}</button>',
data:function(){
return {
counter: 0
}
},
methods: {
increment: function(){
this.counter += 1
this.$emit('increment')
}
},
})
new Vue({
el:'',
data:{
total: 0
},
methods: {
incrementTotal:function(){
this.total += 1
}
}
})
8. 给组件绑定原生事件 .native
<my-component v-on:click.native="dosomething"></my-component>
9. .sync
<comp :foo.sync="bar"></comp>
<comp :foo="bar" @update:foo="val=> val=bar"></comp>
10. 使用自定义事件的表单输入组件
这是个语法糖
<input v-model="something">
<input :value="something" @:input="something = $event.target.value">
所以在组件中使用时,它相当于下面的简写
<custome-input :value="something" @:input="something=argument[0]></custome-input>
所以完全可以自定义input事件的绑定来做一些特殊处理
Vue.component('currency-input', {
template: '\
<span>\
$\
<input\
ref="input"\
v-bind:value="value"\
v-on:input="updateValue($event.target.value)"\
>\
</span>\
',
props: ['value'],
methods: {
// 不是直接更新值,而是使用此方法来对输入值进行格式化和位数限制
updateValue: function (value) {
var formattedValue = value
// 删除两侧的空格符
.trim()
// 保留 2 小数位
.slice(0, value.indexOf('.') + 3)
// 如果值不统一,手动覆盖以保持一致
if (formattedValue !== value) {
this.$refs.input.value = formattedValue
}
// 通过 input 事件发出数值
this.$emit('input', Number(formattedValue))
}
}
})
https://jsfiddle.net/chrisvfritz/1oqjojjx/?utm_source=website&utm_medium=embed&utm_campaign=1oqjojjx
8. 非父子组件通信
使用一个空的Vue实例
var bus = new Vue()
bus.$emit('id-selected',1)
bus.$on('id-selected',function(){})
复杂情况,考虑状态管理模式
9. 使用slot分发内容
为了让组件可以组合,我们需要一种方式来混合父组件的内容与子组件自己的模板
1. 单个slot
2. 具名slot
<slot name="header"></slot>
<slot></slot>
<slot name="footer"></slot>
<app-layout>
<h1 slot="header">
<p> aaa</p>
<p slot="footer">
</app-layout>