vue生命周期实战(一)—— 实例创建

此学习教程是对官方教程的解析,

本章节主要涉及到的官方教程地址:

生命周期图示 — Vue.js

组件之间的循环引用

侦听器

上一章 :Vue入门实战教程(七)—— 生命周期概述

本章节介绍实例创建阶段的生命周期钩子:beforeCreate和created

beforeCreate和created的区别

生命周期钩子可获取的对象常见应用场景
beforeCreatethis.$root、this.$parent、this.$options需要在虚拟DOM渲染前设置的options选项
createdthis.$root、this.$parent、this.$options
data、computed、watch、methods中的数据和方法
添加关联其它方法的方法
用异步获取数据初始化响应式属性

beforeCreate应用

组件循环引用的例子

官方教程组件之间的循环引用里,有一个组件循环引用的例子,构建一个文件目录树,有两个组件,每个组件内部引用另一个组件。我使用局部注册的方式实现的代码如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
<div id="app1">
	<tree-folder :folder="folder"></tree-folder>
</div>


<script>
var treeFolderOptions = {
  props: ['folder'],
  template: '<p>\
  	  <span>{{ folder.name }}</span>\
      <tree-folder-contents :children="folder.children"/>\
	</p>'
	,
	components:{
	   'tree-folder-contents':treeFolderContentsOptions
	}
}

var treeFolderContentsOptions = {
  props: ['children'],
  template: '<ul>\
	  <li v-for="child in children">\
		<tree-folder v-if="child.children" :folder="child"/>\
		<span v-else>{{ child.name }}</span>\
	  </li>\
	</ul>'
	,
	components:{
	  'tree-folder':treeFolderOptions
	}
}

//局部注册
var vm = new Vue({
	el: "#app1",
	data:{
		folder : {
			name : "A",
			children: [
				{
					name : "AA",
					children: [
						{name : "AAA"}
					]
				}
			]
		}
	},
	components:{
	  'tree-folder':treeFolderOptions
	}
})
</script>
</body>
</html>

运行出错及原因

这个例子运行会出错:
在这里插入图片描述
出错的原因就是在渲染tree-folder组件时,遇到了<tree-folder-contents>,但却说是“不认识的自定义元素”,询问你“是否正确注册了这个组件”。
怎么会这样呢,不是明明在代码中局部注册了tree-folder-contents组件了吗?

components:{
	   'tree-folder-contents':treeFolderContentsOptions
}

很可惜,这时候treeFolderContentsOptions的值是undefined,因为treeFolderContentsOptions写在treeFolderOptions后面,treeFolderOptions无法识别
treeFolderContentsOptions。

那把treeFolderContentsOptions写在treeFolderOptions前面不就得了?不行, treeFolderContentsOptions又依赖于treeFolderOptions,这样写又会识别不了<tree-folder>了。

这可真是个悖论!你中有我,我中有你。怎么办呢?

解决方案

<tree-folder-contents>组件是在<tree-folder>组件渲染时才发现没有注册的, 那只要在渲染前注册组件就行了!在哪里注册呢?

vue官方教程实战(七)—— 生命周期概述可以知道,组件渲染是在mounted之前发生的,所以在mounted之前的beforeCreate、created、beforeMount钩子里都可以!而且注册组件的components选项是在vm.$options里,在上面三个钩子里也都可以访问到。

因为只是使用到vm.$options,不涉及数据、方法和render函数,所以放在beforeCreate更合适、代码组织更合理。

更改上面的例子:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>

<body>
<div id="app1">
	<tree-folder :folder="folder"></tree-folder>
</div>


<script>
var treeFolderOptions = {
  props: ['folder'],
  template: '<p>\
  	  <span>{{ folder.name }}</span>\
      <tree-folder-contents :children="folder.children"/>\
	</p>'
	,
	beforeCreate: function () {
	  this.$options.components['tree-folder-contents'] = treeFolderContentsOptions
	}
}

var treeFolderContentsOptions = {
  props: ['children'],
  template: '<ul>\
	  <li v-for="child in children">\
		<tree-folder v-if="child.children" :folder="child"/>\
		<span v-else>{{ child.name }}</span>\
	  </li>\
	</ul>'
	,
	components:{
	  'tree-folder':treeFolderOptions
	}
}

//局部注册
var vm = new Vue({
	el: "#app1",
	data:{
		folder : {
			name : "A",
			children: [
				{
					name : "AA",
					children: [
						{name : "AAA"}
					]
				}
			]
		}
	},
	components:{
	  'tree-folder':treeFolderOptions
	}
})
</script>
</body>
</html>

浏览器运行以上代码,成功了!

created应用

在官方教程侦听器中,有一个使用created的例子:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js"></script>
</head>

<body>
<div id="watch-example">
  <p>
    Ask a yes/no question:
    <input v-model="question">
  </p>
  <p>{{ answer }}</p>
</div>

<script>

var watchExampleVM = new Vue({
  el: '#watch-example',
  data: {
    question: '',
    answer: 'I cannot give you an answer until you ask a question!'
  },
  watch: {
    // 如果 `question` 发生改变,这个函数就会运行
    question: function (newQuestion, oldQuestion) {
      this.answer = 'Waiting for you to stop typing...'
      this.debouncedGetAnswer()
    }
  },
  created: function () {
    // `_.debounce` 是一个通过 Lodash 限制操作频率的函数。
    // 在这个例子中,我们希望限制访问 yesno.wtf/api 的频率
    // AJAX 请求直到用户输入完毕才会发出。想要了解更多关于
    // `_.debounce` 函数 (及其近亲 `_.throttle`) 的知识,
    // 请参考:https://lodash.com/docs#debounce
    this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
  },
  methods: {
    getAnswer: function () {
      if (this.question.indexOf('?') === -1) {
        this.answer = 'Questions usually contain a question mark. ;-)'
        return
      }
      this.answer = 'Thinking...'
      var vm = this
      axios.get('https://yesno.wtf/api')
        .then(function (response) {
          vm.answer = _.capitalize(response.data.answer)
        })
        .catch(function (error) {
          vm.answer = 'Error! Could not reach the API. ' + error
        })
    }
  }
})
</script>
</body>
</html>

这个例子是把debouncedGetAnswer方法的定义放在了created钩子中。因为debouncedGetAnswer方法是和getAnswer方法是紧密相联的,在created钩子里可以访问到methods中的方法,所以放在这里定义是最好不过了。

那为什么不能放在methods定义呢?那是因为methods只是一个对象,把debouncedGetAnswer放在methods中定义会访问不到getAnswer方法。而且这时候methods中的方法还没有注入到实例中,所以使用this.getAnswer的方式调用也是不行的。

methods: {
    getAnswer: function () {
      ...
    },
    //报错,无法访问getAnswer方法
    //debouncedGetAnswer : _.debounce(getAnswer,500)
    //报错,无法访问this.getAnswer方法
	//debouncedGetAnswer : _.debounce(this.getAnswer,500)
  }

本章节教程结束。

全部教程地址:Vue入门实战教程 | 寒于水学习网

vue生命周期实战系列:

vue生命周期实战(一)—— 实例创建

vue生命周期实战(二)——实例挂载

vue生命周期实战(三)—— 实例更新并深刻理解nextTick、watch和生命周期的关系

vue生命周期实战(四)——实例销毁

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值