组件详解
注意点
1.关于组件名
一个单词组成:
第一种写法(首字母小写):school
第二种写法(首字母大写):School
多个单词组成:
第一种写法(kebab-case命名):my-school
第二种写法(CamelCase命名):MySchool (需要Vue脚手架支持)
备注:
(1).组件名尽可能回避HTML中已有的元素名称,例如:h2、H2都不行。
(2).可以使用name配置项指定组件在开发者工具中呈现的名字。
2.关于组件标签:
第一种写法:
第二种写法:
备注:不用使用脚手架时,
3.一个简写方式:
const school = Vue.extend(options) 可简写为:const school = options
关于VueComponent:
1.school组件本质是一个名为VueComponent的构造函数,且不是程序员定义的,是Vue.extend生成的。
2.我们只需要写
即Vue帮我们执行的:new VueComponent(options)。
3.特别注意:每次调用Vue.extend,返回的都是一个全新的VueComponent!!!!
4.关于this指向:
(1).组件配置中:
data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【VueComponent实例对象】。
(2).new Vue(options)配置中:
data函数、methods中的函数、watch中的函数、computed中的函数 它们的this均是【Vue实例对象】。
vue实例的render方法
组件直接替换掉控制区域(#app)
<body><div id="app"></div><template id="father"><div><h1>111</h1></div></template><script type="text/javascript">Vue.component("father", {template: "#father"});let app = new Vue({el: '#app',render: function(creatElement) {//获取模板fatherlet html = creatElement("father");return html}});</script></body>
组件嵌套
<!DOCTYPE html>
<html>
<body>
<!-- 准备好一个容器-->
<div id="root"></div>
</body>
<script type="text/javascript">
Vue.config.productionTip = false //阻止 vue 在启动时生成生产提示。
//定义student组件
const student = Vue.extend({
name:'student',
template:`
<div>
<h2>学生姓名:{{name}}</h2>
<h2>学生年龄:{{age}}</h2>
</div>
`,
data(){
return {
name:'尚硅谷',
age:18
}
}
})
//定义school组件
const school = Vue.extend({
name:'school',
template:`
<div>
<h2>学校名称:{{name}}</h2>
<h2>学校地址:{{address}}</h2>
<student></student>
</div>
`,
data(){
return {
name:'尚硅谷',
address:'北京'
}
},
//注册组件(局部)
components:{
student
}
})
//定义app组件
const app = Vue.extend({
template:`
<div>
<school></school>
</div>
`,
components:{
school
}
})
//创建vm
new Vue({
template:'<app></app>',
el:'#root',
//注册组件(局部)
components:{app}
})
</script>
</html>
全局组件
main.js
组件数据传递
父→子(数据): 通过props向子组件传数据(实例一)
<body>
<div id="app">
<father></father>
</div>
<!-- 父组件 -->
<template id="father">
<div>
<h1>{{name}}</h1>
<!-- son子组件 -->
<son :parentname="name"></son>
</div>
</template>
<!-- 子组件 -->
<template id="son">
<div>父级数据:{{parentname}}</div>
</template>
<script type="text/javascript">
Vue.component("father", {
template: "#father",
data: function() {
return {
"name": "张三"
}
},
components: {
"son": {
props: ["parentname"],
template: "#son"
}
}
});
let app = new Vue({
el: '#app',
});
</script>
</body>
父→子(数据): 通过props向子组件传数据(实例二)
<body>
<!-- Vue实例是父级,school组件是子级,通过props静态或动态的给"school-name"赋值(此处驼峰命名规范改写) -->
<div id="app">
<!-- 静态属性 -->
<school school-name="清华大学"></school>
<!-- 动态属性 -->
<school :school-name="schoolName"></school>
<!-- 动态属性 -->
<school :school-name="schoolList[0]"></school>
<!-- 循环传值组件 -->
<school v-for="item,index in schoolList" :index="index" :school-name="item" :key="'abc'+index"></school>
</div>
<script type="text/javascript">
let app = new Vue({
el: '#app',
data: {
schoolName: "清远职业技术学",
schoolList: ['清大', '浙江大学', '北大']
},
components: {
"school": {
props: ['schoolName', 'index'],
template: ` <h3>{{index}}学校名称: {{schoolName}}</h3>`,
}
}
});
</script>
</body>
父→子(方法): 通过$emit向子组件传递方法
<body>
<div id="app">
<father></father>
</div>
<!-- 父组件 -->
<template id="father">
<div>
<button @click="say">点击</button>
<!-- son子组件 -->
<son @parentsay="say"></son>
</div>
</template>
<!-- 子组件 -->
<template id="son">
<div><button @click="sonfn">点击</button></div>
</template>
<script type="text/javascript">
Vue.component("father", {
template: "#father",
data: function() {
return {
"name": "张三"
}
},
methods: {
"say" () {
alert(123)
}
},
components: {
"son": {
methods: {
"sonfn" () {
this.$emit("parentsay")
}
},
template: "#son"
}
}
});
let app = new Vue({
el: '#app',
});
</script>
</body>
父→子(数据): 通过$children(推荐使用ref)调用子组件方法或数据
<body>
<div id="app">
<button @click="changeEvent">点击</button>
<school></school>
</div>
<script type="text/javascript">
Vue.component("school", {
props: ['action'],
data: function() {
return {
name: "路飞"
}
},
template: ` <div>
<span>子组件-{{name}}</span>
</div>`,
methods: {
chooseEvent: function(schoolName) {
console.log(schoolName)
}
}
})
let app = new Vue({
el: '#app',
methods: {
changeEvent: function() {
//$children 可以获取多个子组件
//[0]是因为可以有多个
this.$children[0].name = "索隆";
this.$children[0].chooseEvent("海贼")
}
}
});
</script>
</body>
子 →父组件的自定义事件
- 一种组件间通信的方式,适用于:子组件 ===> 父组件
- 使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中)。
绑定自定义事件:
- 第一种方式,在父组件中:
<Demo @atguigu="test"/>或<Demo v-on:atguigu="test"/> 第二种方式,在父组件中:
<Demo ref="demo"/> ...... mounted(){ this.$refs.xxx.$on('atguigu',回调) }若想让自定义事件只能触发一次,可以使用
once修饰符,或$once方法。
this.$refs.xxx.$once('atguigu',回调)
- 第一种方式,在父组件中:
- 子组件触发自定义事件:
this.$emit('atguigu',数据) - 子组件解绑自定义事件(被绑的vc):
this.$off('atguigu')解绑一个自定义事件this.$off(['atguigu','demo'])解绑多个自定义事件this.$off()解绑所有的自定义事件*
- 组件上也可以绑定原生DOM事件,需要使用
native修饰符(不然vue不认为是原生事件)。
<Student @click.native="show"/> 注意:通过
this.$refs.xxx.$on('atguigu',回调)绑定自定义事件时,回调要么配置在methods中,要么用箭头函数(箭头函数没有this,于是vue会往上一层找 找到vc实例当做this),否则this指向会出问题!子→父(方法-参数-数据): 通过$emit向父组件传数据
父传递【方法】给子
- 子调用父【方法】并传递数据
父【方法】接收数据
<body> <div id="app"> <!--@cschool事件接收this.$emit('cschool', schoolName)--> <school v-for="item,index in schoolList" @cschool="changeEvent" :index="index" :school-name="item" :key="'abc'+index"></school> <p>{{chooseSchool}}</p> </div> <script type="text/javascript"> Vue.component("school", { props: ['schoolName', 'index'], template: ` <div> <h3>学校名称: {{schoolName}}</h3> <button @click="chooseEvent(schoolName)">传值</button> </div>`, methods: { //点击按钮触发事件 chooseEvent: function(schoolName) { //触发一个叫 cschool 的事件来调用父组件的changeEvent方法,实现数据传值 this.$emit('cschool', schoolName) } } }) let app = new Vue({ el: '#app', data: { schoolList: ['清大', '浙江大学', '北大'], chooseSchool: "" }, methods: { changeEvent: function(data) { this.chooseSchool = data; } } }); </script> </body>子→父(数据): 通过props调用父组件方法 向父组件传递数据
父传递【方法】以v-bind绑定数据形式给子
- 子调用父【方法】以this.XX(参数)形式 并传递数据
父【方法】接收数据
<body> <div id="app"> <!-- 因为父元素的方法可以直接修改父元素的数据 所以将父元素的方法传递给子元素 由子元素进行调用,从而修改父元素 --> <school :action="changeEvent"></school> <p>{{chooseSchool}}</p> </div> <script type="text/javascript"> Vue.component("school", { props: ['action'], template: `<button @click="chooseEvent(schoolName)">传值</button>`, data: function() { return { schoolName: "清职院" } }, methods: { //点击按钮触发事件 chooseEvent: function(schoolName) { //调用定义的属性,以此调用父组件方法changeEvent this.action(schoolName) } } }) let app = new Vue({ el: '#app', data: { chooseSchool: "" }, methods: { changeEvent: function(data) { this.chooseSchool = data; } } }); </script> </body>子→父(数据): 通过$parent调用父组件方法 向父组件传递数据
<body> <div id="app"> <!-- 因为父元素的方法可以直接修改父元素的数据 所以将父元素的方法传递给子元素 由子元素进行调用,从而修改父元素 --> <school :action="changeEvent"></school> {{chooseSchool}} </div> <script type="text/javascript"> Vue.component("school", { props: ['action'], //1.间接在事件中调用父组件方(this.$parent.) //2.在视图直接调用父元素方法($parent) //3.直接修改父元素数据chooseSchool template: ` <div> <button @click="chooseEvent(schoolName)">传值</button> <button @click="$parent.changeEvent(schoolName)">传值</button> <button @click="$parent.chooseSchool=schoolName">传值</button> </div>`, data: function() { return { schoolName: "清职院" } }, methods: { chooseEvent: function(schoolName) { //$parent父组件 this.$parent.changeEvent(schoolName); //$root最上层组件 this.$root.changeEvent(schoolName) } } }) let app = new Vue({ el: '#app', data: { chooseSchool: "" }, methods: { changeEvent: function(data) { this.chooseSchool = data; } } }); </script> </body><body> <div id="app"> <!-- 因为父元素的方法可以直接修改父元素的数据 所以将父元素的方法传递给子元素 由子元素进行调用,从而修改父元素 --> <school :action="changeEvent"></school> </div> <script type="text/javascript"> Vue.component("school", { props: ['action'], //1.间接在事件中调用父组件方(this.$parent.) //2.在视图直接调用父元素方法($parent) //3.直接修改父元素数据chooseSchool template: ` <div> <button @click="chooseEvent(schoolName)">传值</button> <button @click="$parent.changeEvent(schoolName)">传值</button> <button @click="$parent.chooseSchool=schoolName">传值</button> </div>`, methods: { chooseEvent: function(schoolName) { //$parent父组件 this.$parent.changeEvent(schoolName) //$root最上层组件 this.$root.changeEvent(schoolName) } } }) let app = new Vue({ el: '#app', data: { chooseSchool: "" }, methods: { changeEvent: function(data) { this.chooseSchool = data; } } }); </script> </body>
