Vue——属性监听器(面试)、自定义指令(面试)

目录

一、属性监听器(面试)

二、自定义指令(面试)


一、属性监听器(面试)

watch:{x(){}}

中的方法名必须跟要监听的data中的属性名一样,才代表监听指定属性

当侦听器监听的属性发生变化时,就会调用watch中对应的方法

侦听器属性,比计算属性计算效率消耗大

new Vue({
	el:"",//关联界面元素
	data:{x:12},//vm的数据源
	methods:{},//方法
	filter:{},//过滤器
	computed:{xx(){}}, //xx就是一个计算属性
	watch:{x(){}} //x就是监听了data中的x属性的一个监听器
})

 用法:

<div id='app'>
			<p>{{n}}</p>
			<button @click="change1">修改n</button>
			<p>{{obj.age}}</p>
			<button @click="change2">修改obj</button>
		</div>
		<script>
			var vm = new Vue({
				el: '#app',
				data: {
					n: 100,
					obj: {
						age: 20
					}
				},
				methods: {
					change1() {
						console.log("点击事件触发了")
						this.n = "修改了"
					},
					change2() {
						// this.obj.age="修改了引用数据内部的属性值:页面会重新渲染,但是侦听器属性不会触发"
						// this.obj={age:"只有修改了引用数据的引用 才能触发侦听器属性"}
						this.obj.age = "修改了引用数据内部的属性值也想触发侦听器属性,必须深度监听"
					}
				},
				watch: {//侦听器属性:必须和data中的数据源同名
					n() {
						console.log(666666666)
					},
					// obj(){
					// 	console.log("obj改变了")
					// }
					obj: {  //这就是深度监听,上面改变this.obj.age,这个属性监听器也会触发
						//其实这样设计不好
						deep: true,
						handler: () => {
							console.log("obj改变了")
						}
					}
				}
			})
		</script>

案例一:汇率换算

    <div id='app'>
			RMB:<input type="text" v-model="rmb">
			doller:<input type="text" v-model="doller">
		</div>
		<script>
			var vm = new Vue({
				el: '#app',
				data: {
					rmb:0,
					doller:0
				},
				methods: {},
				watch:{	
					rmb(newvalue,oldvalue){
						console.log(arguments)   //会打印两个值,原来的值和新的值
						this.doller=(newvalue/6.9).toFixed(2)*100/100
					},
					doller(newvalue,oldvalue){
						this.rmb=newvalue*6.9
					}
				}
			})
		</script>

案例二:消费余额提示

<div id='app'>
			<p>{{money}}</p>
			<button @click="fn">消费</button>
		</div>
		<script>
			var vm = new Vue({
				el: '#app',
				data: {
					money:100
				},
				methods: {
					fn(){
						this.money-=5
					}
				},
				watch:{
					money(newv,oldv){
						if(newv<30){
							alert("发短信还给用户:只剩30了不到了")
						}
					}
				}
			})
		</script>

案例三:播放进度条监听

	<style type="text/css">
			.slider{
				width:400px;
				height: 20px;
				background-color: skyblue;
				position: relative;
				left: 100px;
				top: 100px;
				border-radius: 10px;
			}
			.sliderbar{
				width:30px;
				height: 30px;
				border-radius: 50%;
				background-color:cadetblue;
				position: relative;
				top: -5px;
			}
		</style>
		<div id='app'>
			进度条:{{total-currenttime|timerparser}}
			<div class="slider">
				<div class="sliderbar" :style="{left:x}"></div>
			</div>
			<button @click="start">start</button>
		</div>
		<script>
			var vm = new Vue({
				el: '#app',
				data: {
					currenttime:0,
					total:242,
					x:0,
					maxwidth:370
				},
				methods: {
					start(){
						this.timer=setInterval(()=>{
							this.currenttime+=0.1
						},100)
					}
				},
				filters:{
					timerparser(arg){
						return ` ${parseInt(arg/60).toString().padStart(2,"0")}:${parseInt(arg%60).toString().padStart(2,"0")}`
					}
				},
				watch:{
					currenttime(value){
						this.x=this.maxwidth*value/this.total+"px"
						if(value>=60){
							clearInterval(this.timer)
							alert("试听结束")
						}
					}
				}
			})
		</script>

二、自定义指令(面试)

除了默认设置的核心指令( v-model 和 v-show 等),Vue 也允许注册自定义指令。

在Vue里,代码复用的主要形式和抽象是组件。

有的情况下,仍然需要对纯 DOM 元素进行底层操作,这时候就会用到自定义指令 。

指令:Vue中指令就是标签中V-开始的一种自定义的标签的属性,它在Vue运行了以后,就具有封装好的功能,使用时非常简洁

以一个input元素自动获得焦点为例,当页面加载时,使用autofocuse可以让元素将获得焦点 ,但是autofocuse在移动版Safari上不工作,现在注册一个使元素自动获取焦点的指令。

指令注册类似于组件注册,包括全局指令和局部指令两种。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.14/vue.js"></script>
	</head>
	<body>
		<div id="app">
			<p v-html="msg"></p>
			<input v-red type="text" v-model="count"  v-focus/>
			<div v-red>hello</div>  <!-- 变为红色 -->
			<h2 v-color="'blue'">123</h2> <!-- v-color="blue"中的blue是一个变量,要为字符串需要用引号引起来 -->
			<h2 v-color="'gold'">123</h2>
			<p v-color="mycolor">123</p>
			<input type="text" >
		</div>
		<script>
			var vm = new Vue({
				el: "#app",
				data: {
					msg: "<b>hello</b>",
					count: 123,
					mycolor:"grey"
				},
				methods: {
				},
				directives: {
					red: {
						inserted(el) {
							console.log(el) //绑定这个指令的节点对象:DOM
							el.style.color = "red"
						}
					},
					color: {
						inserted(el, option) {  //option是一个对象
							el.style.color = option.value
						}
					},
					focus:{
						inserted(el){
							el.focus()
						}
					}
				}
			})
		</script>
	</body>
</html>

 案例:Echarts

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title></title>
	<script src='https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.14/vue.js'></script>
	<script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/echarts/5.3.0-rc.1/echarts.js"></script>
</head>
<body>
	<style type="text/css">
		.box {
			width: 600px;
			height: 600px;
		}
	</style>
	<div id='app'>
		<div class="box" style="width:600px;height:600px;" v-echarts>
		</div>
	</div>
	<script>
		var vm = new Vue({
			el: '#app',
			data: {
			},
			methods: {},
			directives: {
				echarts: {
					bind(el) {
						var myChart = echarts.init(el);
						let options = {
							title: {
								text: 'Referer of a Website',
								subtext: 'Fake Data',
								left: 'center'
							},
							tooltip: {
								trigger: 'item'
							},
							legend: {
								orient: 'vertical',
								left: 'left'
							},
							series: [{
								name: 'Access From',
								type: 'pie',
								radius: '50%',
								data: [{
									value: 1048,
									name: 'Search Engine'
								},
								{
									value: 735,
									name: 'Direct'
								},
								{
									value: 580,
									name: 'Email'
								},
								{
									value: 484,
									name: 'Union Ads'
								},
								{
									value: 300,
									name: 'Video Ads'
								}
								],
								emphasis: {
									itemStyle: {
										shadowBlur: 10,
										shadowOffsetX: 0,
										shadowColor: 'rgba(0, 0, 0, 0.5)'
									}
								}
							}]
						}
						myChart.setOption(options)
					}
				}
			}
		})
	</script>
</body>
</html>

1)全局指令

// 注册一个全局自定义指令 v-focus
Vue.directive('focus', {
  // 当绑定元素插入到 DOM 中。
  inserted: function (el) {
    // 聚焦元素
    el.focus()
  }
})

2)局部指令

var vm = new Vue({
  el: '#app',
  directives:{
    focus:{
      inserted: function (el) {
        el.focus()
      }      
    }
  }
})

在模板中任何元素上使用新的 v-focus 属性

<div id="app"> <input v-focus> </div>

3)钩子函数

指令定义函数提供了几个钩子函数(可选) 。

【bind】

  只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。

【inserted】

  被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。

【update】

  所在组件的 VNode 更新时调用,但是可能发生在其孩子的 VNode 更新之前。指令的值可能发生了改变也可能没有。但是可以通过比较更新前后的值来忽略不必要的模板更新。

当前所在组件更新的时候,这个函数才运行

【componentUpdated】

  所在组件的 VNode 及其孩子的 VNode 全部更新时调用。

【unbind】

  只调用一次, 指令与元素解绑时调用。

注意区别:

bind与inserted:bind时父节点为null,inserted时父节点存在;

update与componentUpdated:update是数据更新前,componentUpdated是数据更新后。

4)钩子函数参数

【el】

  指令所绑定的元素,可以用来直接操作 DOM。

【binding】

  一个对象,包含指令名称及该指令所绑定的表达式信息。

        里面有name、value、oldvalue等等

【vnode】

  Vue 编译生成的虚拟节点。

【oldVnode】

  上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

注意:除了 el 之外,其它参数都是只读的,尽量不要修改他们。如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行。

	<div id='app'>
			<p v-hqyj="red" @click="change1">hello</p>
		</div>
		<script>
			var vm = new Vue({
				el: '#app',
				data: {
					red:"rgb(255,0,0)"
				},
				methods: {
					change1(){
						this.red="rgb(200,0,0)"
					}
				},
				directives:{
					hqyj:{
						bind(){
							console.log("bind")
						},
						inserted(el,binding){
							var v=binding.value
							console.log(v)
						},
						update(){
							console.log("update")
						},
						componentUpdated(){
							
						},
						unbind(){
						}
					}
				}
			})
		</script>

5)函数简写

大多数情况下,可能想在bind和update钩子上做重复动作,并且不想关心其它的钩子函数。可以这样写:

<div v-demo="{ color: 'white', text: 'hello!' }"></div>

Vue.directive('demo', function (el, binding) {
  console.log(binding.value.color) // => "white"
  console.log(binding.value.text)  // => "hello!"
})

三、nextTick

学习了生命周期之后,会有一个问题:我们在写业务的时候,写的业务代码能否操作vm

所以需要一个工具,让我们写的diamagnetic,无论在哪里写,都希望它是组件加载完了以后才运行

这个函数的回调函数是在组件加载完了才会执行

 

    <div id='app'>
			<p>{{msg}}</p>
		</div>
		<script>
			var vm = new Vue({
				el: '#app',
				data: {
					msg:"hello"
				},
				methods: {},
				beforeCreate(){
					//这个函数的回调函数是在组件加载完了才会执行
					this.$nextTick(()=>{
						console.log(this.msg)
					})
				}
			})
		</script>

==>这个函数就可以解决上面ECharts案例

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src='https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.14/vue.js'></script>
		<script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/echarts/5.3.0-rc.1/echarts.js"></script>
	</head>
	<body>
		<style type="text/css">
			.box {
				width: 600px;
				height: 600px;
			}
		</style>
		<div id='app'>
			<div class="box" v-echarts>
			</div>
		</div>
		<script>
			var vm = new Vue({
				el: '#app',
				data: {},
				methods: {},
				directives: {
					echarts: {
						inserted(el) {
                           Vue.nextTick(()=>{
							   var myChart = echarts.init(el);
							   let options={
							   	title: {
							   		text: 'Referer of a Website',
							   		subtext: 'Fake Data',
							   		left: 'center'
							   	},
							   	tooltip: {
							   		trigger: 'item'
							   	},
							   	legend: {
							   		orient: 'vertical',
							   		left: 'left'
							   	},
							   	series: [{
							   		name: 'Access From',
							   		type: 'pie',
							   		radius: '50%',
							   		data: [{
							   				value: 1048,
							   				name: 'Search Engine'
							   			},
							   			{
							   				value: 735,
							   				name: 'Direct'
							   			},
							   			{
							   				value: 580,
							   				name: 'Email'
							   			},
							   			{
							   				value: 484,
							   				name: 'Union Ads'
							   			},
							   			{
							   				value: 300,
							   				name: 'Video Ads'
							   			}
							   		],
							   		emphasis: {
							   			itemStyle: {
							   				shadowBlur: 10,
							   				shadowOffsetX: 0,
							   				shadowColor: 'rgba(0, 0, 0, 0.5)'
							   			}
							   		}
							   	}]
							   }
							   myChart.setOption(options)
						   })
						}
					}
				}
			})
		</script>
	</body>
</html>

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值