表单操作
基础用法
文本
<input v-model="message" placeholder="edit me">
<p>Message is: {{ message }}</p>
多行文本
<span>Multiline message is:</span>
<p style="white-space: pre-line;">{{ message }}</p>
<br>
<textarea v-model="message" placeholder="add multiple lines"></textarea>
注意:
在文本区域插值 <textarea>{{text}}</textarea> 并不会生效,应用 v-model 来代替。
复选框
- 单个复选框
单个复选框,绑定到布尔值:
<input type="checkbox" id="checkbox" v-model="checked">
<label for="checkbox">{{ checked }}</label>
- 多个复选框
多个复选框,绑定到同一个数组:
html:
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>
<br>
<span>Checked names: {{ checkedNames }}</span>
js:
new Vue({
el: '...',
data: {
checkedNames: []
}
})
单选按钮
html:
<div id="example-4">
<input type="radio" id="one" value="One" v-model="picked">
<label for="one">One</label>
<br>
<input type="radio" id="two" value="Two" v-model="picked">
<label for="two">Two</label>
<br>
<span>Picked: {{ picked }}</span>
</div>
js:
new Vue({
el: '#example-4',
data: {
picked: ''
}
})
下拉选择框
- 单选选择框:
html:
<div id="example-5">
<select v-model="selected">
<option disabled value="">请选择</option>
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<span>Selected: {{ selected }}</span>
</div>
js:
new Vue({
el: '...',
data: {
selected: ''
}
})
注意:
如果 v-model 表达式的初始值未能匹配任何选项,<select> 元素将被渲染为“未选中”状态。在 iOS 中,这会使用户无法选择第一个选项。因为这样的情况下,iOS 不会触发 change 事件。因此,更推荐像上面这样提供一个值为空的禁用选项。
- 多选选择框:
绑定到一个数组
html:
<div id="example-6">
<select v-model="selected" multiple style="width: 50px;">
<option>A</option>
<option>B</option>
<option>C</option>
</select>
<br>
<span>Selected: {{ selected }}</span>
</div>
js:
new Vue({
el: '#example-6',
data: {
selected: []
}
})
- 用
v-for渲染的动态选项:
html:
<select v-model="selected">
<option v-for="option in options" v-bind:value="option.value">
{{ option.text }}
</option>
</select>
<span>Selected: {{ selected }}</span>
js:
new Vue({
el: '...',
data: {
selected: 'A',
options: [
{ text: 'One', value: 'A' },
{ text: 'Two', value: 'B' },
{ text: 'Three', value: 'C' } ]
}
})
表单操作值的绑定
对于单选按钮,复选框及选择框的选项,v-model 绑定的值通常是静态字符串 (对于复选框也可以是布尔值):
<!-- 当选中时,`picked` 为字符串 "a" -->
<input type="radio" v-model="picked" value="a">
<!-- `toggle` 为 true 或 false -->
<input type="checkbox" v-model="toggle">
<!-- 当选中第一个选项时,`selected` 为字符串 "abc" -->
<select v-model="selected">
<option value="abc">ABC</option>
</select>
但是有时我们可能想把值绑定到 Vue 实例的一个动态 property 上,这时可以用 v-bind 实现,并且这个 property 的值可以不是字符串。
复选框
html:
<input
type="checkbox"
v-model="toggle"
true-value="yes"
false-value="no"
>
js:
// 当选中时
vm.toggle === 'yes'
// 当没有选中时
vm.toggle === 'no'
单选按钮
html:
<input type="radio" v-model="pick" v-bind:value="a">
js:
// 当选中时
vm.pick === vm.a
选择框的选项
html:
<select v-model="selected">
<!-- 内联对象字面量 -->
<option v-bind:value="{ number: 123 }">123</option>
</select>
js:
// 当选中时
typeof vm.selected // => 'object'
vm.selected.number // => 123
修饰符
.lazy
一般情况 v-model 在每次 input 事件触发后将输入框的值与数据进行同步,使用lazy 修饰符,转为在 change 事件之后进行同步
<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg">
.number
给 v-model 添加 number 修饰符, 自动将用户的输入值转为数值类型:
<input v-model.number="age" type="number">
.trim
给 v-model 添加 trim 修饰符, 去除用户输入的首尾空白字符(中间不去):
<input v-model.trim="msg">
自定义指令
内置指令不满足需求时,自定义
基本用法
全局自定义指令: Vue.directive
局部自定义指令:组件中也接受一个 directives 的选项
示例: 输入框聚焦
html:
<div id='app'>
<input type="text">
<input type="text" v-focus>
<!-- 或 -->
<input type="text" v-focuslocal>
</div>
vue:
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {//指令名
inserted: function(el) {
//el表示指令所绑定的元素
el.focus();// 聚焦元素
}
})
var vm = new Vue({
el: '#app',
data() {
return {
}
},
methods: {
handle: function(){
}
},
directives: {
focuslocal: {//名字都得是小写
// 局部自定义指令 `v-focuslocal`
inserted: function (el) {
el.focus()
}
}
}
})
参数
-
el:指令所绑定的元素,可以用来直接操作 DOM。 -
binding:一个对象,包含以下 property:name:指令名,不包括v-前缀。value:指令的绑定值,例如:v-my-directive="1 + 1"中,绑定值为2。oldValue:指令绑定的前一个值,仅在update和componentUpdated钩子中可用。无论值是否改变都可用。expression:字符串形式的指令表达式。例如v-my-directive="1 + 1"中,表达式为"1 + 1"。arg:传给指令的参数,可选。例如v-my-directive:foo中,参数为"foo"。modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar中,修饰符对象为{ foo: true, bar: true }。
-
vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。 -
oldVnode:上一个虚拟节点,仅在update和componentUpdated钩子中可用。
注意:
除了 el 之外,其它参数都应该是只读的,切勿进行修改。如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行。
示例:
html:
<div id="hook-arguments-example" v-demo:foo.a.b="message"></div>
js:
Vue.directive('demo', {
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(', ')
}
})
new Vue({
el: '#hook-arguments-example',
data: {
message: 'hello!'
}
})
计算属性
为啥需要计算属性
抽取模板复杂的计算
<div id='app'>
<div>{{msg}}</div>
<div>{{msg.split('').reverse().join('')}}</div>
</div>
表达式的计算逻辑可能很复杂,使用计算属性可以使模板内容更加简洁。
基本用法
示例:
<div id='app'>
<div>{{msg}}</div>
<div>{{msg.split('').reverse().join('')}}</div>
<div>{{reverseString}}</div>
</div>
var vm = new Vue({
el: '#app',
data() {
return {
msg: 'Hello'
}
},
computed: {
reverseString: function(){
return this.msg.split('').reverse().join('')
}
}
})
计算属性就是基于 data 中的数据来进行处理的。data 中的数据改变,计算属性也跟着变。
计算属性和方法的区别
- 计算属性是基于依赖(
data中的数据)进行缓存。 - 方法不存在缓存。
计算属性计算完一次后,只在相关响应式依赖( data 中的数据)发生改变时它们才会重新求值。
相比之下,每当触发重新渲染时,调用方法将总会再次执行函数。
为什么需要缓存?假设我们有一个性能开销比较大的计算属性 A,它需要遍历一个巨大的数组并做大量的计算。然后我们可能有其他的计算属性依赖于 A。如果没有缓存,我们将不可避免的多次执行 A 的 getter!如果你不希望有缓存,请用方法来替代。
示例:
<div id='app'>
<div>{{reverseString}}</div>
<div>{{reverseString}}</div>
<div>{{reverseMessage()}}</div>
<div>{{reverseMessage()}}</div>
</div>
var vm = new Vue({
el: '#app',
data() {
return {
msg: 'Hello'
}
},
methods:{
reverseMessage: function(){
console.log('methods');
return this.msg.split('').reverse().join('')
}
},
computed: {
reverseString: function(){
console.log('computed');
return this.msg.split('').reverse().join('')
}
}
})
computed 只计算了一次,methods 每次都重新计算了。
侦听器
什么是侦听器
侦听器 watch 用来监听数据,数据一旦发生变化就通知侦听器所绑定的方法。
常用于当需要在数据变化时执行异步或开销较大(执行慢)的操作时。
基本用法
监听的属性名称要和 watch 绑定方法的名称一致
示例:
<div id='app'>
<div>
<span>用户名:</span>
<span>
<!-- .lazy 失去焦点时才会触发 -->
<input type="text" v-model.lazy="uname">
</span>
<span>{{tips}}</span>
</div>
</div>
var vm = new Vue({
el: '#app',
data() {
return {
uname: '',
tips: ''
}
},
methods:{
checkName: function(uname){
//使用定时器模拟接口调用
let that = this;//setTimeout里面的this是Window对象
setTimeout(function(){
if(uname === 'admin'){
that.tips = '用户名已经存在,请更换一个'
}else {
that.tips = '用户名可以使用'
}
}, 2000);
}
},
watch: {
uname: function(val){//和监听的属性名一致
this.checkName(val);
this.tips = '正在验证。。。。'
}
}
})
过滤器
干啥的
可被用于一些常见的文本格式化
过滤器可以用在两个地方:双花括号插值和 v-bind 表达式
<!-- 在双花括号中 -->
{{ message | capitalize }}
<!-- 在 `v-bind` 中 -->
<div v-bind:id="rawId | formatId"></div>
基础用法
示例:
<div id='app'>
<input type="text" v-model="msg">
<div>{{msg | upper}}</div>
<!-- 过滤器可以串联 -->
<div>{{msg | upper | lower}}</div>
<div>{{msg | upper | lower | upperlocal}}</div>
</div>
// 定义全局过滤器
Vue.filter('upper', function(val){
return val.charAt(0).toUpperCase() + val.slice(1);
});
// 定义全局过滤器
Vue.filter('lower', function(val){
return val.charAt(0).toLowerCase() + val.slice(1);
});
var vm = new Vue({
el: '#app',
data() {
return {
msg: ''
}
},
filters: {// 定义局部过滤器
upperlocal: function(val){
return val.charAt(0).toUpperCase() + val.slice(1);
}
}
})
生命周期
啥是生命周期
vue实例有一个完整的生命周期,生命周期也就是指一个实例从开始创建到销毁的这个过程
每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做生命周期钩子的函数,这给了用户在不同阶段添加自己的代码的机会。
注意:
不要在选项 property 或回调上使用箭头函数,比如 created: () => console.log(this.a) 或 vm.$watch('a', newValue => this.myMethod())。因为箭头函数并没有 this,this 会作为变量一直向上级词法作用域查找,直至找到为止,经常导致 Uncaught TypeError: Cannot read property of undefined 或 Uncaught TypeError: this.myMethod is not a function 之类的错误。
主要阶段
- 挂载(初始化相关属性)
- beforeCreate
- created
- beforeMount
- mounted
- 更新
- beforeUpdate
- updated
- 销毁
- beforeDestroy
- destroyed
对生命周期的理解
beforeCreate()在实例创建之间执行,数据未加载状态created()在实例创建、数据加载后,能初始化数据,dom渲染之前执行beforeMount()虚拟dom已创建完成,在数据渲染前最后一次更改数据mounted()页面、数据渲染完成,真实dom挂载完成beforeUpadate()重新渲染之前触发updated()数据已经更改完成,dom也重新render完成,更改数据会陷入死循环beforeDestory()和destoryed()前者是销毁前执行(实例仍然完全可用),后者则是销毁后执行
各个周期适用场景
示例 :
- beforecreate : 加loading事件
- created :在这结束loading,还做一些初始化,实现函数自执行
- mounted : 在这发起后端请求,拿回数据,配合路由钩子做一些事情
- beforeDestory: 确认删除XX吗? destoryed :当前组件已被删除,清空相关内容
created和mounted的区别?
- beforecreated:el 和 data 并未初始化
- created: 完成了 data 数据的初始化,el没有 渲染前调用,初始化某些属性值,再渲染
- beforeMount:完成了 el 和 data 初始化
- mounted :完成挂载 渲染后再调用,初始化页面完成后,再对DOM节点进行操作