知识点
- 组件注册
- 组件复用
- 组件通信
- 动态组件
- 实例生命周期
- 生命周期示意图
组建注册
全局注册
Vue.component(组件名字,template:{元素标签})
<body>
<div id="app">
<syl></syl>
<syl></syl>
</div>
<script>
Vue.component("syl",{template:"<h1>实验室全局组件</h1>"});
var app = new Vue({
el:"#app",
});
</script>
</body>
运行效果
局部组件
在父级的components对象中声明,局部组件只有它的父级才能调用。
<body>
<div id="app">
<syl></syl>
<syl></syl>
<div id="father">
<child></child>
</div>
<!-- 不是父组件无法调用 -->
<child></child>
</div>
<script>
// 声明子组件
var childComponent = {
template:"<h2>我们是子组件,只有父组件才能调用</h2>"
};
var app = new Vue({
el:"#app",
});
var father = new Vue({
el:"#father",
// 子组件必须先声明后使用,不然不起效,记住是components
components:{
"child": childComponent,
},
});
</script>
</body>
组件复用
组件的优点就在于能够复用,一次代码编写,整个项目受用。
注意: 复用组件内的 data 必须是一个函数,如果是一个对象(引用类型),组件与组件间会相互影响,组件数据不能独立管理。
<div id="app">
<button-counter></button-counter>
<button-counter></button-counter>
<button-counter></button-counter>
</div>
<script>
Vue.component("button-counter",{
data(){
return{
counter:0,
};
},
template:'<button @click="counter++">{{counter}}</button>',
});
var app = new Vue({
el:"#app",
});
</script>
组件间通信
父子组件之 props
只允许父组件向子组件传值
传值类型:数值、字符、布尔值、数值、对象
子组件需要显式地用 props 选项声明 "prop",告诉使用者需要传入什么数据
注意:HTML 中的特性名是大小写不敏感的,所以浏览器会把所有大写字符解释为小写字符。这意味着当你使用 DOM 中的模板时,camelCase (驼峰命名法) 的 prop 需要使用其等价的 kebab-case (短横线分隔命名) 命名
个人理解:使用该模板的是父组件,子组件暴露出可传入的值,由父组件传入
注意:
所有的 props 都遵循着单向绑定原则,props 因父组件的更新而变化,自然地将新的状态向下流往子组件,而不会逆向传递。这避免了子组件意外修改父组件的状态的情况,不然应用的数据流将很容易变得混乱而难以理解。
另外,每次父组件更新后,所有的子组件中的 props 都会被更新到最新值,这意味着你不应该在子组件中去更改一个 prop。若你这么做了,Vue 会在控制台上向你抛出警告:
export default {
props: ['foo'],
created() {
// ❌ 警告!prop 是只读的!
this.foo = 'bar'
}
}
若子组件有更改需求,建议重新定义一个变量承接prop的值。
示例:
<body>
<div id="app">
//动态组件
<blog-post v-for="post in posts"
:key="post.id"
:title="post.title">
</blog-post>
</div>
<script>
Vue.component("blog-post",{
props:["title"],
template:"<h1>{{title}}</h1>",
});
var app = new Vue({
el:"#app",
data(){
return{
posts:[
{ id: 1, title: 'My journey with Vue'},
{ id: 2, title: 'Blogging with Vue'},
{id: 3, title: 'Why Vue is so fun'},
]
}
}
})
</script>
</body>
props 类型检测
以对象形式列出 prop,这些属性的名称和值分别是 prop 各自的名称和类型
<body>
<div id="app">
<child-component
id="1"
title="hello syl"
content="you are welcom"
></child-component>
</div>
<script>
// 注册一个子组件
Vue.component("child-component", {
// props 对象形式,传递属性值 进行类型检测,在脚手架环境中很有用
props: {
id: Number,
title: String,
content: String,
},
// 使用 es6 模板字符串书写格式更优美
template: `<div><p>id:{{id}}</p><p>title:{{title}}</p><p>content:{{content}}</p></div>`,
});
var app = new Vue({
el: "#app",
});
</script>
</body>
子父组件通信之 emit
子组件向父组件通信
这里要使用自定义事件 emit 方法,通过自定义事件来由下到上的数据流动。
语法如下:
this.$emit('自定义事件名',参数)
<div id="app">
<child-component v-on:send-msg="getMsg">
</child-component>
</div>
<script>
// 1、定义一个子组件,template绑定click事件
// 2、当click事件触发就使用emit自定义一个事件send-msg,传入参数“我是子组件请求与你通信”
// $emit('send-msg','我是子组件请求与你通信')
// 3、子组件标签绑定自定义事件send-msg,并绑定上父级的方法getMsg,即可完成了子父组件通信
// <child-component v-on:send-msg="getMsg"></child-component>
Vue.component("child-component",{
template:`
<button v-on:click="$emit('send-msg','我是子组件请求与你通信')">
Click me
</button>
`,
});
var app = new Vue({
el:"#app",
methods:{
getMsg:function(msg){
// 父组件的获取子组件消息的方法
alert(msg);
}
}
});
</script>
子组件向父组件数据传递套路:
第一步:子组件绑定事件。
第二步:子组件绑定事件触发,使用 $emit 创建自定义事件并传入需要传值给父组件的数据。
第三步:在子组件标签上 用 v-on 绑定自定义事件,在父组件中声明自定义事件处理的方法。
第四步:父组件方法,接受自定义事件传的参数,就完成了整个由下到上的数据流。
生命周期函数
//主要的生命周期函数
beforeCreate() {
alert(
"在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用"
);
},
created() {
alert(
"在实例创建完成后被立即调用,挂载阶段还没开始,$el 属性目前不可见"
);
},
beforeMount() {
alert("在挂载开始之前被调用:相关的 render 函数首次被调用");
},
mounted() {
alert("el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子");
},
beforeUpdate() {
alert("数据更新时调用");
},
updated() {
alert("组件 DOM 已经更新");
},
beforeDestroy() {},
destroyed() {},
这么多钩子函数我们经常主要用到有:
-
created 钩子函数内我们可以进行异步数据请求。
created() { fetch('url') .then(function(response) { console.log(response) }) } -
mounted 我们可以直接操作元素 DOM 了,但是并不推荐这样做,不利于性能提升。
<body> <div id="app"> <div id="box" style="width:40px;background: tomato;">点击</div> </div> <script> var app = new Vue({ el: "#app", data() { return {}; }, // div#box 开始并没有绑定事件,挂载后我们直接操作原生 dom mounted() { var box = document.querySelector("#box"); box.addEventListener("click", function () { alert("我们挂载后 原生点击事件"); }); }, }); </script> </body>