表单基本操作
1.获取单选框中的值
<body>
<div id="app">
<!--
1、 两个单选框需要同时通过 v-model 双向绑定一个值
2、 每一个单选框必须要有 value 属性且 value 值不能一样
3、 当某一个单选框选中的时候 v-model 会将当前的 value 值 改变 data 中的 数据
gender 的值就是选中的值,我们只需要实时监控它的值就可以了
-->
<input type="radio" id="male" v-model='gender' value="1">
<label for="male">男</label>
<input type="radio" id="female" v-model='gender' value="2">
<label for="female">女</label>
</div>
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
// 默认会让当前的 value 值为 2 的单选框选中
gender: 2
}
})
</script>
</body>
2.获取复选框中的值
- 和获取单选框中的值一样
- 复选框
checkbox
这种的组合时 data 中的 hobby 我们要定义成数组,否则无法实现多选
<body>
<div id="app">
<!--
1、 两个单选框需要同时通过 v-model 双向绑定一个值
2、 每一个单选框必须要有 value 属性且 value 值不能一样
3、 当某一个单选框选中的时候 v-model 会将当前的 value 值 改变 data 中的 数据
hobby 的值就是选中的值,我们只需要实时监控它的值就可以了
-->
<div>
<span>爱好:</span>
<input type="checkbox" id="ball" value="1" v-model='hobby'>
<label for="ball">跑步</label>
<input type="checkbox" id="sing" value="2" v-model='hobby'>
<label for="sing">唱歌</label>
<input type="checkbox" id="code" value="3" v-model='hobby'>
<label for="code">写代码</label>
</div>
</div>
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
// 默认会让当前的 value 值为 2 和 3 的复选框选中
hobby: ['2', '3']
}
})
</script>
</body>
3.获取下拉框和文本框中的值
<body>
<div id="app">
<span>职业:</span>
<!--
1、 需要给 select 通过 v-model 双向绑定一个值
2、 每一个 option 必须要有 value 属性 且 value 值不能一样
3、 当某一个 option 选中的时候 v-model 会将当前的 value 值改变 data 中的数据
occupation 的值就是选中的值,我们只需要实时监控他的值就可以了
-->
<!-- multiple 多选 -->
<select v-model='occupation' multiple>
<option value="0">请选择职业...</option>
<option value="1">教师</option>
<option value="2">软件工程师</option>
<option value="3">作家</option>
</select>
<!-- textarea 是一个双标签 不需要绑定 value 属性 -->
<textarea v-model='desc'></textarea>
</div>
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
// 默认会让当前的 value 值为 2 和 3 的下拉框选中
occupation: ['2', '3'],
desc: 'moon'
}
})
</script>
</body>
表单修饰符
.number 转换为数值
注意点:当开始输入非数字的字符串时,因为Vue无法将字符串转换成数值,所以属性值将实时更新成相同的字符串,即使后面输入数字,也将被视作字符串。
.trim 自动过滤用户输入的首尾空白字符
注意点: 只能去掉首尾的,不能去除中间的空格。
.lazy 将input事件切换成change事件
注意点: .lazy 修饰符延迟了同步更新属性值的时机,即将原本绑定在 input 事件的同步逻辑转变为绑定在 change 事件上。
<!-- 自动将用户的输入值转为数值类型 -->
<input v-model.number="age" type="number">
<!--自动过滤用户输入的首尾空白字符 -->
<input v-model.trim="msg">
<!-- 在“change”时而非“input”时更新 -->
<input v-model.lazy="msg" >
自定义指令
- 内置指令不能满足我们特殊的需求
- Vue允许我们自定义指令
Vue.directive 注册全局指令
<body>
<div id="app">
<!-- 使用自定义的指令,只需在要使用的元素中,加上'v-'的前缀形成类似于内部指令'v-if','v-text'的形式。 -->
<input type="text" v-focus>
</div>
<script src="js/vue.js"></script>
<script>
// 注意点:
// 1、 在自定义指令中 如果以驼峰命名的方式定义 如 Vue.directive('focusA',function(){})
// 2、 在HTML中使用的时候 只能通过 v-focus-a 来使用
// 注册一个全局自定义指令 v-focus
Vue.directive('focus', {
// 当绑定元素插入到 DOM 中。 其中 el 为 dom 元素
inserted: function(el) {
// 聚焦元素
el.focus();
}
});
var vm = new Vue({
el: '#app'
})
</script>
</body>
Vue.directive 注册全局指令(带参数)
<body>
<div id="app">
<input type="text" v-color='msg'>
</div>
<script src="js/vue.js"></script>
<script>
/*
自定义指令-带参数
bind 只调用一次,在指令第一次绑定到元素上时候调用
*/
Vue.directive('color', {
// bind 声明周期, 只调用一次,指令第一次绑定到元素时调用,在这里可以进行一次性的初始化设置
// el 为当前自定义指令的 DOM 元素
// binding 为自定义的函数形参,通过自定义属性传递过来的值 存在 binding.value 里面
bind: function(el, binding) {
// 根据指令的参数设置背景色
el.style.backgroundColor = binding.value.color;
}
});
var vm = new Vue({
el: '#app',
data: {
msg: {
color: 'pink'
}
}
});
</script>
</body>
自定义指令(局部指令)
- 局部指令,需要定义在 directives 的选项中,用法和全局指令一样
- 局部指令只能在当前组件里面使用(在当前的Vue实例中)
- 当全局指令和局部指令同名时以局部指令为准
<body>
<div id="app">
<input type="text" v-color='msg'>
<input type="text" v-focus>
</div>
<script src="js/vue.js"></script>
<script>
/*
自定义指令-局部指令
*/
var vm = new Vue({
el: '#app',
data: {
msg: {
color: 'skyblue'
}
},
//局部指令,需要定义在 directives 的选项
directives: {
color: {
bind: function(el, binding) {
// 根据指令参数设置背景色
el.style.backgroundColor = binding.value.color;
}
},
focus: {
inserted: function(el) {
// 得到焦点
el.focus();
}
}
}
});
</script>
</body>
计算属性
- 模板中放入太多的逻辑会让模板过重且难以维护,使用计算属性可以让模板更加的简洁
- 计算属性是基于它们的响应式依赖进行缓存的
- computed 比较适合对多个变量或者对象进行处理后返回一个结果值,也就是多个变量中的某一个值发生了变化则我们监控的这个值也就会发生变化
<body>
<div id="app">
<!--
当多次调用 reverseString 的时候
只要里面的 num 值不改变,它会把第一次计算的结果直接返回
直到data 中的 num 值改变,计算属性才会重新发生计算
-->
<div>{{reverseString}}</div>
<div>{{reverseString}}</div>
<!-- 调用methods中的方法的时候 他每次会重新调用 -->
<div>{{reverseMessage()}}</div>
<div>{{reverseMessage()}}</div>
</div>
<script src="js/vue.js"></script>
<script>
// 计算属性与方法的区别:计算属性是基于依赖进行缓存的,而方法不缓存
var vm = new Vue({
el: '#app',
data: {
msg: 'MoonShadow',
num: 100
},
methods: {
reverseMessage: function() {
console.log('methods');
return this.msg.split('').reverse().join('');
}
},
//computed 属性定义和 data 以及 methods 平级
computed: {
// reverseString 这个是我们自己定义的名字
reverseString: function() {
console.log('computed')
var total = 0;
// 当 data 中的 num 的值改变的时候 reverseString 会自动发生计算
for (var i = 0; i <= this.num; i++) {
total += i;
}
// 这里一定要有 return 否则调用 reverseString 的时候无法拿到结果
return total;
}
}
});
</script>
</body>
侦听器
- 使用 watch 来响应数据的变化
- 一般用于异步或者开销较大的操作
- watch 中的属性一定是 data 中已经存在的数据
- 当需要监听一个对象的改变时,普通的 watch 方法无法监听到对象内部属性的改变,只有 data 中的数据才能够监听到变化,此时就需要 deep 属性对对象进行深度监听
<body>
<div id="app">
<div>
<span>名:</span>
<span><input type="text" v-model='firstName'></span>
</div>
<div>
<span>姓:</span>
<span><input type="text" v-model='lastName'></span>
</div>
<div>{{fullName}}</div>
</div>
<script src="js/vue.js"></script>
<script type="text/javascript">
// 侦听器
var vm = new Vue({
el: '#app',
data: {
firstName: 'Klein',
lastName: 'Moretti',
fullName: 'Klein Moretti'
},
// watch 属性定义和 data 以及 methods 平级
watch: {
// 注意:这里 firstName 对应着 data 中的 firstName
// 当 firstName 值改变的时候会自动触发 watch
// val 代表改变的值
firstName: function(val) {
console.log(val);
this.fullName = val + ' ' + this.lastName;
},
// 注意:这里 lastName 对应着 data 中的 lastName
lastName: function(val) {
this.fullName = this.firstName + ' ' + val;
}
}
});
</script>
</body>
handler 方法和 immediate 属性
watch 的一个特点是:最初绑定的时候是不会执行的,要等到 firstName 改变时才执行监听计算,那想要一开始就让它最初绑定的时候就执行该怎么办呢?需要修改一下 watch 的写法,修改过后的代码如下:
<script>
var vm = new Vue({
el: '#app',
data: {
firstName: 'Klein',
lastName: 'Moretti',
fullName: ''
},
// watch 属性定义和 data 以及 methods 平级
watch: {
firstName: {
handler(val) {
this.fullName = val + ' ' + this.lastName;
},
// 代表在 wacth 里声明了 firstName 这个方法之后立即先去执行 handler 方法
immediate: true
},
lastName: {
handler(val) {
this.fullName = val + ' ' + this.firstName;
},
// 代表在 wacth 里声明了 firstName 这个方法之后立即先去执行 handler 方法
immediate: true
}
}
});
</script>
注意到 handler了吗,我们给 firstName 绑定了一个handler方法,之前我们写的 watch 方法其实默认写的就是这个 handler,Vue.js会去处理这个逻辑,最终编译出来其实就是这个handler,上面的 handler 方法使用了简写。
而 immediate:true 代表如果在 wacth 里声明了 firstName 之后,就会立即先去执行里面的 handler 方法,如果为 false 就跟以前的效果一样,不会在绑定的时候就执行。
deep属性(深度监听)
watch 里面有一个属性 deep,默认值是 false,代表是否深度监听。
<body>
<div id="app">
<p>{{msg.info}}</p>
<input type="text" v-model="msg.info">
</div>
<script src="js/vue.js"></script>
<script>
var vm = new Vue({
el: '#app',
data: {
msg: {
info: 222
}
},
watch: {
msg: function(val) {
console.log('msg.info is changed');
}
}
});
</script>
</body>
当我们在在输入框中输入数据改变 msg.info 的值时,我们发现是无效的。受现代 JavaScript 的限制 (以及废弃 Object.observe),Vue 不能检测到对象属性的添加或删除。由于 Vue 会在初始化实例时对属性执行 getter/setter 转化过程,所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。
默认情况下 handler 只监听 msg 这个属性它的引用的变化,只有给 msg 赋值的时候它才会监听到,比如我们在 mounted 事件钩子函数中对 msg 进行重新赋值:
mounted: {
this.msg = {
info: 111
}
}
这样 handler 才会执行,控制台才会打印 msg.info is changed
所以我们要监听 msg.info (对象的属性)的值必须使用 deep 属性,更改 watch 为以下代码:
watch: {
msg: {
handler: function(val) {
console.log('msg.info is changed');
},
deep: true
}
}
deep 的意思就是深入观察,监听器会一层层的往下遍历,给对象的所有属性都加上这个监听器,但是这样性能开销就会非常大了,任何修改 msg 里面任何一个属性都会触发这个监听器里的 handler方法。
如果只需要对某个对象中的某个属性监听,我们可以使用字符串形式监听,这样可以优化性能,代码如下:
watch: {
'msg.info': {
handler: function(val) {
console.log('msg.info is changed');
},
// deep: true
}
}
这样Vue.js才会一层一层解析下去,直到遇到属性 info,然后才给 info 设置监听函数。
过滤器
- Vue.js允许自定义过滤器,可被用于一些常见的文本格式化
- 过滤器可以用在两个地方:双花括号插值和 v-bind 表达式
- 过滤器应该被添加在JavaScript表达式的尾部,由“管道”符号指示
- 支持级联操作
- 过滤器不改变真正的
data
,而只是改变渲染的结果,并返回过滤后的版本 - 全局注册时是 filter,没有s的,而局部过滤器是filters,是有s的
<body>
<div id="app">
<input type="text" v-model='msg'>
<!-- upper 被定义为接收单个参数的过滤器函数,表达式 msg 的值将作为参数传入到函数中 -->
<div>{{msg | upper}}</div>
<!--
支持级联操作
upper 被定义为接收单个参数的过滤器函数,表达式 msg 的值将作为参数传入到函数中。
然后继续调用同样被定义为接收单个参数的过滤器 lower ,将 upper 的结果传递到 lower 中
-->
<div>{{msg | upper | lower}}</div>
<div :abc='msg | upper'>测试数据</div>
</div>
<script src="js/vue.js"></script>
<script>
// lower 为全局过滤器
Vue.filter('lower', function(val) {
return val.charAt(0).toLowerCase() + val.slice(1);
});
var vm = new Vue({
el: '#app',
data: {
msg: ''
},
// filters 属性定义和 data 以及 methods 平级
// 定义 filters 中的过滤器为局部过滤器
filters: {
// upper 自定义的过滤器名字
// upper 被定义为接收单个参数的过滤器函数,表达式 msg 的值将作为参数传入到函数中
// 此处的 val 就是要过滤的数据
upper: function(val) {
// 过滤器中一定要有返回值 这样外界使用过滤器的时候才能拿到结果
return val.charAt(0).toUpperCase() + val.slice(1);
}
}
});
</script>
</body>
过滤器中传递参数
<body>
<div id="app">
<!--
filterA 被定义为接收三个参数的过滤器函数。
其中 message 的值作为第一个参数,
普通字符串 arg1 作为第二个参数,表达式 arg2 的值作为第三个参数。
-->
{{ message | filterA('arg1', 'arg2') }}
</div>
</div>
<script src="js/vue.js"></script>
<script>
// 在过滤器中第一个参数对应的是管道符前面的数据 n ,此时对应 message
// 第2个参数 a 对应实参 arg1 字符串
// 第3个参数 b 对应 参 arg2 字符串
Vue.filter('filterA', function(n, a, b) {
return n + ' ' + a + ' ' + b;
});
var vm = new Vue({
el: '#app',
data: {
message: 'hello hello'
}
});
</script>
</body>
生命周期
- 事物从出生到死亡的过程
- Vue实例从创建到销毁的过程 ,这些过程中会伴随着一些函数的自调用,我们称这些函数为钩子函数
常用的钩子函数
beforeCreate | 在实例初始化之后,数据观测和事件配置之前被调用,此时 data 和 methods 以及页面的DOM结构都没有初始化,什么都做不了 |
---|---|
created | 在实例创建完成后被立即调用此时 data 和 methods 已经可以使用,但是页面还没有渲染出来 |
beforeMount | 在挂载开始之前被调用,此时页面上还看不到真实数据,只是一个模板页面而已 |
mounted | el 被新创建的 vm.$e l替换,并挂载到实例上去之后调用该钩子,数据已经真实渲染到页面上,在这个钩子函数里面我们可以使用一些第三方的插件 |
beforeUpdate | 数据更新时调用,发生在虚拟DOM打补丁之前,页面上数据还是旧的 |
updated | 由于数据更改导致的虚拟DOM重新渲染和打补丁,在这之后会调用该钩子,页面上数据已经替换成最新的 |
beforeDestroy | 实例销毁之前调用 |
destroyed | 实例销毁后调用 |
生命周期图示:

数组变异方法
- 在 Vue 中,直接修改对象属性的值无法触发响应式,当你直接修改了对象属性的值,你会发现,只有数据改了,但是页面内容并没有改变
- 变异数组方法即保持数组方法原有功能不变的前提下对其进行功能拓展
push() | 往数组最后面添加一个元素,成功返回当前数组的长度 |
---|---|
pop() | 删除数组的最后一个元素,成功返回删除元素的值 |
shift() | 删除数组的第一个元素,成功返回删除元素的值 |
unshift() | 往数组最前面添加一个元素,成功返回当前数组的长度 |
splice() | 有三个参数,第一个是想要删除的元素的下标(必选),第二个是想要删除的个数(必选),第三个是删除后想要在原位置替换的值 |
sort() | sort() 使数组按照字符编码默认从小到大排序,成功返回排序后的数组 |
reverse() | reverse() 将数组倒序,成功返回倒序后的数组 |
替换数组
- 不会改变原始数组,但总是返回一个新数组
filter() | filter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。 |
---|---|
concat() | concat() 方法用于连接两个或多个数组,该方法不会改变现有的数组 |
slice() | slice() 方法可从已有的数组中返回选定的元素,该方法并不会修改数组,而是返回一个子数组 |
动态数组响应式数据
- Vue.set(a,b,c) 让触发视图重新更新一遍,数据动态起来
- a是要更改的数据 、b是数据的第几项、c是更改后的数据