除了核心功能默认内置的指令 (v-model 和 v-show),Vue 也允许注册自定义指令。
有的情况下,你仍然需要对普通 DOM 元素进行底层操作,这时候就会用到自定义指令。举个聚焦输入框的例子,如下:
// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
// 当被绑定的元素插入到 DOM 中时……
inserted: function (el) {
// 聚焦元素
el.focus()
}
})
如果想注册局部指令,组件中也接受一个 directives 的选项:
directives: {
focus: {
// 指令的定义
inserted: function (el) {
el.focus()
}
}
}
然后你可以在模板中任何元素上使用新的 v-focus 属性,如下:
<input v-focus>
练习代码:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app">
<!--自定义指令用法-->
<input type="text" v-focus/>
<input type="text" v-color='msg'/>
</div>
<script type="text/javascript" src="js/vue.min.js" ></script>
<script type="text/javascript">
/*
* 自定义指令
*/
//全局指令:使用范围
//inserted钩子函数
Vue.directive('focus',{
inserted: function(el){
//获取元素焦点
el.focus();
}
});
// Vue.directive('color',{
// bind: function(el,binding){
// //根据指令的参数设置背景色
// //console.log(binding.value.color);
// el.style.backgroundColor = binding.value.color;
// }
// });
var vm = new Vue({
el: '#app',
data: {
msg: {
color: 'red'
}
},
methods:{
},
//局部指令:只能在本组件使用
directives: {
color: {
bind: function(el,binding){
el.style.backgroundColor = binding.value.color;
}
}
}
});
</script>
</body>
</html>
参考Vue官网链接
一个指令定义对象可以提供如下几个钩子函数 (均为可选):
bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。
inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。
update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode
更新之前。指令的值可能发生了改变,也可能没有。但是你可以通过比较更新前后的值来忽略不必要的模板更新 (详细的钩子函数参数见下)。
componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。
unbind:只调用一次,指令与元素解绑时调用。
钩子函数参数
指令钩子函数会被传入以下参数:
el:指令所绑定的元素,可以用来直接操作 DOM 。 binding:一个对象,包含以下属性:
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 来进行。
参考资料Vue官网:计算属性和侦听器
computed:{}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app">
<!--表达式的计算逻辑可能会比较复杂,使用计算属性可以是模板内容更加简洁-->
<div>{{msg}}</div>
<div>{{reverseString}}</div>
</div>
<script type="text/javascript" src="js/vue.min.js" ></script>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
msg: 'Hello'
},
//计算属性与方法的区别:计算属性是基于它们的依赖(依赖于data里面的值)进行缓存的;方法不存在缓存
//计算属性
computed: {
reverseString: function(){
return this.msg.split('').reverse().join('');
}
}
})
</script>
</body>
</html>
watch:{}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<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 type="text/javascript" src="js/vue.min.js" ></script>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
firstName: 'Jim',
lastName: 'Green',
fullName: 'Jim Green'
},
//侦听器:数据变化时执行异步或开销较大的操作
watch: {
firstName: function(val){
this.fullName = val + ' ' +this.lastName;
},
lastName: function(val){
this.fullName = this.firstName + ' ' + val;
}
},
//31,34-41去掉
// computed: {
// fullName: function(){
// return this.firstName + " " + this.lastName;
// }
// }
})
</script>
</body>
</html>
侦听器应用:验证用户名是否可用
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--验证用户名是否可用-->
<div id="app">
<div>
<span>用户名:</span>
<span>
<input type="text" v-model.lazy="uname"/>
</span>
<span>{{tip}}</span>
</div>
</div>
<script type="text/javascript" src="js/vue.min.js" ></script>
<script type="text/javascript">
/*
* 1.采用侦听器监听用户名变化
* 2.调用后台接口进行验证
* 3.根据验证的结果调整提示信息
*/
var vm = new Vue({
el: '#app',
data: {
uname: '',
tip: ''
},
methods: {
checkName: function(uname){
var that = this;
//调用接口,但是可以使用定时任务的方式模拟接口调用
setTimeout(function(){
//模拟接口调用
if(uname == 'admit'){
that.tip = '用户名已经存在,请更换一个';
}else{
that.tip = '用户名可以使用';
}
},2000)
}
},
watch: {
uname: function(val){
//调用后台接口验证用户名的合法性
this.checkName(val);
//修改提示信息
this.tip = '正在验证...';
}
}
})
</script>
</body>
</html>
Vue官网:过滤器
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--过滤器:格式化数据-->
<div id="app">
<input type="text" v-model="msg"/>
<div>{{msg | upper}}</div>
<div>{{msg | upper | lower}}</div>
<div :asd='msg | upper'>测试</div>
</div>
<script type="text/javascript" src="js/vue.min.js" ></script>
<script type="text/javascript">
/*
* 过滤器
*/
// 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: {
msg: ''
},
//局部绑定
filters: {
upper: function(val){
return val.charAt(0).toUpperCase() + val.slice(1);
}
}
});
</script>
</body>
</html>
过滤器应用:格式化日期
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app">
<div>{{date | format('yyyy-MM-dd')}}</div>
</div>
<script type="text/javascript" src="js/vue.min.js" ></script>
<script type="text/javascript">
/*
* 过滤器格式化日期
*/
//filter参数
Vue.filter('format',function(value,arg){
//console.log(value);
//console.log(arg);
if(arg == 'yyyy-MM-dd'){
//13视频有补充
var ret = '';
ret += value. getFullYear() + '-' +(value.getMonth()+1) + '-' + value.getDate();
return ret;
}
return value;
});
var vm = new Vue({
el: '#app',
data: {
date: new Date()
},
methods: {
}
});
</script>
</body>
</html>
生命周期
测试代码(关注:mounted)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div id="app">
<div>{{msg}}</div>
<button @click="change">更新</button>
<button @click="destory">销毁</button>
</div>
<script type="text/javascript" src="js/vue.min.js" ></script>
<script type="text/javascript">
/*
* 生命周期钩子
* 挂载(mounted)、更新、销毁
*/
var vm = new Vue({
el: '#app',
data: {
msg: '生命周期'
},
methods: {
change: function(){
this.msg = '123456'
},
destory: function(){
this.$destroy();
}
},
beforeCreate: function(){
console.log('beforeCreate');
},
created: function(){
console.log('created');
},
beforeMount: function(){
console.log('beforeMount');
},
mounted: function(){
console.log('mounted');
},
beforeUpdate: function(){
console.log('beforeUpdate');
},
updated: function(){
console.log('updated');
},
beforeDestroy: function(){
console.log('beforeDestroy');
},
destroyed: function(){
console.log('destroyed');
}
});
</script>
</body>
</html>