vue学习笔记

深入响应式原理


如何追踪变化


当Vue初始化时,会遍历data对象中的所有属性,并将这些属性通过Object.defineProperty 转换为setter和getter。
vue的每一个组件实例都有一个watcher对象,当组件渲染时,其属性将被标记为依赖,一旦依赖项的setter被调用,就会通知watcher重新计算,从而与其相关的组件将会更新。

变化检测问题


受到javascript的限制,vue无法检测到对象属性的添加或者删除,因此,setter和getter的转化只会在vue实例初始化时实现一次。在这之后新增的任何属性,vue都无法动态检测到该属性的变化,如:
<body>
<div id='vueDemo'><div v-if='showDiv'>{{message}}</div>
<button @click='show'></button>
</div>
</body>
<script type="text/javascript">
	var vueTest=new Vue({
el:'#vueDemo',
data:{
	showDiv:false,
	
},
methods:{
	show:function(){
		this.message='djiowu';
		this.showDiv=!this.showDiv;

	}
}
	})
</script>
以上代码,由于message是在初始化之后添加的,故当对vueTest.message重新赋值为‘ddddd’,页面上的显示仍然是djiowu,无法随着属性值的变化动态更新页面。

而如果在初始化之前添加,即data:{showDiv:false,message:'djiowu'},则将vueTest.message重新赋值后,页面会随之而更新。

虽然vue无法在初始化后添加根级响应属性,但却可以通过Vue.set方法来给转换为setter/getter的现有根基响应属性添加子属性。注意,通过vueTest.attr.innerAttr='ddddd'这种直接赋值方法不生效,必须通过Vue.set方法添加才可以。如下例,虽然是在初始化之后添加的属性,vue却仍然可以随着属性值的变化动态更新页面
<div id='vueDemo'><div v-if='showDiv'>{{message.innerAttr}}</div>
<button @click='show'></button>
</div>
</body>
<script type="text/javascript">
	var vueTest=new Vue({
el:'#vueDemo',
data:{
	showDiv:false,
	message:{}
},
methods:{
	show:function(){
		this.$set(this.message,'innerAttr','DJIOW')
		this.showDiv=!this.showDiv;

	}
}
	})
</script>

异步更新队列


当我们对Vue的属性做出改变时,页面并非立即刷新渲染,而是将这些改变放入一个队列。在下一次事件循环‘tick’中,刷新队列并执行实际工作,把对数据的改变渲染到页面上。可是有时候我们需要在Dom改变后做出一些操作,这时可以使用Vue.nextTick(callback),回调函数会在DOM更新完成后调用。如下例
<body>
	<div id="test">
		<div>{{message}}</div>	
	</child>
</div>
</body>
<script type="text/javascript">

	var vueTest=new Vue({
		el:'#test',
		data:{
			message:''
		}	})
	vueTest.message='i am new message'
	debugger//此时会看到,页面并未更新,显示的仍未空字符串
	
</script>

<body>
	<div id="test">
		<div>{{message}}</div>	
	</child>
</div>
</body>
<script type="text/javascript">

	var vueTest=new Vue({
		el:'#test',
		data:{
			message:''
		}	})
	vueTest.message='i am new message'
	Vue.nextTick(function(){
		debugger//此时会看到,页面已经更新,显示的为新字符串
	})
</script>


若是在组件内部,则通过this.$nextTick()来实现。其中this为当前vue组件实例
<body>
	<div id='test'>
		<child>
			
		</child>
	</div>
</div>
</body>
<script type="text/javascript">
	Vue.component('child',{
		template:'<div style="background:red;width:100px;height:100px" v-on:click="clickDiv">{{message}}</div>',
		data:function(){return {message:''}},
		methods:{
			clickDiv:function(){
				this.message=' i am clicked'
				this.$nextTick(function(){
					debugger
				})
			}
		}
	})
	var vueTest=new Vue({
		el:'#test',
	})
	
</script>

Render函数

render函数用来通过js生成DOM。这在有些情况下是需要的。比如,我现在想要根据level值,生成指定大小的字体。
<body>
	<div id='test'>
		<anchored-heading :level="2">Hello world!</anchored-heading>
	</div>
</div>
<template  id="anchored-heading-template">
	<div >
		<h1 v-if="level === 1">
			<slot></slot>
		</h1>
		<h2 v-if="level === 2">
			<slot></slot>
		</h2>
		<h3 v-if="level === 3">
			<slot></slot>
		</h3>
		<h4 v-if="level === 4">
			<slot></slot>
		</h4>
		<h5 v-if="level === 5">
			<slot></slot>
		</h5>
		<h6 v-if="level === 6">
			<slot></slot>
		</h6>
	</div>


</template>
</body>
<script type="text/javascript">
	Vue.component('anchored-heading', {
		template: '#anchored-heading-template',
		props: {
			level: {
				type: Number,
				required: true
			}
		}
	})
	var vueTest=new Vue({
		el:'#test'
			})
</script>


以上组件html代码其实完全可以通过Render函数来简化
<body>
	<div id='test'>
		<anchored-heading :level="3">Hello world!</anchored-heading>
	</div>
</div>
</body>
<script type="text/javascript">
	Vue.component('anchored-heading', {
		render:function(createElement){
			return createElement('h'+this.level,this.$slots.default)//(html标签,标签内的内容)
		},
		props: {
			level: {
				type: Number,
				required: true
			}
		}
	})
	var vueTest=new Vue({
		el:'#test'	})
	
	</script>

自定义指令


钩子函数

bind: 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。通常用于初始化被绑定元素。
<body>
	<div id='test'>
		<div v-color='colorMessage' style='width: 100px;height: 100px'>
			i am message
		</div>	</div>
	</div>
</body>
<script type="text/javascript">
	Vue.directive('color', {
		bind:function(el,binding){
			el.style.backgroundColor=binding.value;//若没有对bind事件的回调,则对colorMessage变动之前标签颜色不会发生变化,即页面初始化时不会变为红色。
		},
		update:function(el,binding){
			el.style.backgroundColor=binding.value;
		}
	})
	var vueTest=new Vue({
		el:'#test',
		data:{colorMessage:'red'}
	})
	
</script>


混合


Vue中的一个属性:mixins用来声明混合的对象。当所混合的对象与Vue实例自身的选项相重合时,混合对象的配置项和Vue实例的配置项相结合一起执行,且混合对象的执行优先级要高于vue实例。如:

<body>
<div id='vueDemo'><input >
	
</input>
</div>
</body>
<script type="text/javascript">
// 定义一个混合对象
var myMixin = {
  created: function () {//created为一个钩子函数
    this.hello()
  },
  methods: {
    hello: function () {
      console.log('hello from mixin!')
    }
  }
}
var vueTest=new Vue({
	el:'#vueDemo',
	mixins:[myMixin],//注意,这里是数组
	created:function(){
		console.log('from vue instance')//由于vue实例和myMixin混合对象都定义了created钩子函数,故这两个钩子函数中的操作都将被执行。最终的结果是在控制台输出了hello from mixin和from vue instance
	}
})

</script>

当一级选项内部的二级属性名相重合时,并非全部执行,而是执行组件的操作,而不执行vue实例的。如:methods内定义的方法相重合时。
<body>
	<div id='vueDemo'><input >
	</input>
</div>
</body>
<script type="text/javascript">
	// 定义一个混合对象
	var myMixin = {
		created: function () {
			this.hello()
		},
		methods: {
			hello: function () {
				console.log('hello from mixin!')
			}
		}
	}
	var vueTest=new Vue({
		el:'#vueDemo',
		mixins:[myMixin],
		methods:{hello:function(){
			console.log( 'a hello from vue')//运行后输出 a hello from vue和from vue instance。而不输出hello from mixin
		}},
		created:function(){
			console.log('from vue instance')
		}
	})
</script>



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值