Vue2---(计算属性,属性侦听器,自定义指令)

78 阅读4分钟

计算属性

计算属性:就是处理数据源中的数据,然后用于渲染,而且会监听计算属性中使用到的数据源 然后把计算的结果缓存.如果监听的数据源发生了变化,才会重新计算,否则直接使用缓存的数据.

computed:把computed中的方法当做属性使用,会返回一个数据供使用

:

<body>
		<div id="app">
			<h1>{{birth}}   </h1>
			<p>methods---{{age1(birth)}}</p>
			<p>computed---{{age}}</p>
			<p>{{x}}</p>
			<button @click="change1">change1--{{msg}}</button>
		</div>
		<script>
			//刷新页面==>模板重新渲染 重新取值
			var vm=new Vue({
				//关联模板的选择器
				el:"#app",
				//数据源
				data:{
					birth:"1996-02-03",
					msg:"hello"
				},
				//方法
				methods:{
					change1(){
						this.msg="6666"
						this.birth=this.birth
						this.x=30
					},
					age1(str){
						console.log("方法")
						return new Date().getFullYear()- new Date(str).getFullYear()
					}
				},
				//过滤器
				filters:{
					
				},
				// 计算属性
				computed:{
					age(){
						console.log("计算属性")
						return new Date().getFullYear()- new Date(this.birth).getFullYear()
					},
					x:{
						get(){
							console.log(this,11111)
							return new Date().getFullYear()- new Date(this.birth).getFullYear()+"岁"
						},
						set(v){
							console.log(v)
							this.birth=`${2022-v}-02-03`
						}
					}
				}
			})
			
			
			
			
		</script>
	</body>

image.png

image.png

属性侦听器

属性侦听器:watch:{x(){}}中的方法名必须跟要监听的data中的属性名一样,才代表监听指定属性,当侦听器监听的属性发生变化时,就会调用watch中对应的方法

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

属性监听器的特点

1.修改了引用数据内部的属性值:页面会重新渲染,但是侦听器属性不会触发

<body>
	<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改变了")
				// }
			}
		})
	</script>
</body>

image.png

2.如果要解决修改了引用数据内部的属性值侦听器属性不会触发的问题,需要深度绑定

语法

obj: {
					deep: true,
					handler: () => {
						console.log("obj改变了")
					}

:

<body>
	<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: {
					deep: true,
					handler: () => {
						console.log("obj改变了")
					}
				}
			}
		})
	</script>
</body>

image.png

image.png

3.修改了引用数据的引用,触发侦听器属性

<body>
	<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: {
				// 	deep: true,
				// 	handler: () => {
				// 		console.log("obj改变了")
				// 	}
				// }
			}
		})
	</script>

image.png

image.png

面试题

计算属性,属性侦听器,方法,过滤器有什么区别? 哪些是被this对象劫持过的?

计算属性:会把计算的结果缓存起来,并监听计算过的数据源 如果监听的数据源发生变化才会重新计算(没有监听的属性发生变化 模板会重新渲染)

方法:一般是提供给模板事件和其他方法(比如钩子函数)使用,如果在模板中使用了方法,而且不是事件,如果模板中的渲染的任意数据源改变了 它都会重新调用

过滤器:往往用于数据渲染前的数据处理 除了用法跟方法不一样其他都一样,它没有被劫持

属性侦听器:只有侦听的属性发生变化才会触发(可以深度侦听,但是更消耗内存)

自定义属性

自定义属性(directives):除了默认设置的核心指令( v-model 和 v-show 等),Vue 也允许注册自定义指令。在Vue里,代码复用的主要形式和抽象是组件。然而,有的情况下,仍然需要对纯 DOM 元素进行底层操作,这时候就会用到自定义指令 。

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

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

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()
      }      
    }
  }
})

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

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

自定义属性中的钩子函数

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

【bind】

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

【inserted】

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

【update】

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

【componentUpdated】

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

【unbind】

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

区别:

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

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

自定义属性中的钩子函数的参数

【el】

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

【binding】

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

【vnode】

  Vue 编译生成的虚拟节点。

【oldVnode】

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

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

函数简写

大多数情况下,可能想在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!"
})

:自定义一个ECharts饼状图

<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);
							// console.log(this.options)
							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>

image.png