创建全局组件----
方法一:(初始阶段)
1.//使用vue.extend来创建组件模板
const vr = vue.extend({
//
template: `<div>
<h1></h1>
<p></p>
</div>
`
})
//使用component来创建组件模板对象
vue.component('MyCont(实例化的组件名)',vr(组件模板名))
//调用:
<body>
<my-cont></my-cont>//使用的组件直接以html标签的样式引用
//组件名格式,在注册的时候最好用双驼峰命名,引用的时候用‘-’链接双驼峰
</body>
方法二:(进阶)
vue.component('MyCont(实例化的组件名)',vue.extend({
//第一个参数为组件名,二参为将要创建的组件模板
template: `<div>
<h1></h1>
<p></p>
</div>
`
}))
//调用:
<body>
<my-cont></my-cont>//使用的组件直接以html标签的样式引用
//组件名格式,在注册的时候最好用双驼峰命名,引用的时候用‘-’链接双驼峰
</body>
方法二简化:
vue.component('MyCont(实例化的组件名)',{
//对象的字面量形式
template: `<div>
<h1></h1>
<p></p>
</div>
`
})
//调用:
<body>
<my-cont></my-cont>//使用的组件直接以html标签的样式引用
//组件名格式,在注册的时候最好用双驼峰命名,引用的时候用‘-’链接双驼峰
</body>
方法三:(组件的模板写在外部)
<div id="app">
<my-cont></my-con>
</div>
<template id="one">
<div>
<h3></h3>
...
</div>
</template>
<script>
//实例化vue对象
const v = new vue({
el: "#app",
data: {},
})
//创建组件
vue.component('MyCont(实例化的组件名)',{
//第一个参数为组件名,二参为将要创建的组件模板
template: "#one"//组件模板绑定在外部的template上,类似vue实例化中的el
})
</script>
总结:不管是那种方法,template模板中只能有一个根标签
正确写法:**<template>** 错误写法:**<template>**
<div>//被div包裹 <div>不只有一对根标签
<p></p> </div>
... ...
</div> <p></p>
**</template>** **</template>**
-----------------------------------------------------------------------------
创建私有组件----
方法一:
<div id="app">
<ones></ones>//在app范围内使用
<div>
```javascript
const v = new vue({
el: "#app",
components: {
ones: {
template: `<div>
<p></p>
<h1></h1>
...
</div>`
}
}
})
**方法二:**
```html
<div id="app">
<ones></ones>//在app范围内使用
<div>
<template id="one">
<div>
<p></p>
....
</div>
</template>
const v = new vue({
el: "#app",
components: { 定义私有组件的函数(内部函数)
ones: {
template: "#one"
}
}
})
----------------------------------------------------------
组件的data数据----
<body>
<div id="app">
<my-cont></my-cont>
</div>
<!-- <my-cont>{{ mag }}</my-cont> -->
</body>
<script>
Vue.component("MyCont", {
template: `<h1>全局组件----{{ mag }}</h1>`,
//组件可以有自己的data数据
//组件中的data和实例上的data不同,必须是一个函数,并且返回一个对象,
//组件中的data使用和实例的data一样
data() {
return {
mag: 'xxx',
}
},
})
const v = new Vue({
el: "#app",
data: {
msg: "xxx"
},
methods: {
},
});
</script>
总结:**data为函数返回对象而不是直接是一个对象的原因,
因为当data为一个全局组件的时候,目的是为了能够复用,但是如果data为对象的话
就会造成引用类型传递现象(引用类型地址指向相同),操作一个,全部跟着改变
所以data为函数返回对象,可以避免这一现象的发生,组件多次使用不会干扰**
-------------------------------------------------------------
组件切换登录/注册小demo-----
<body>
<div id="app">
<a href="#"><button @click="log">登录</button></a>
<a href="#"><button @click="sig">注册</button></a>
<login v-if="flag"></login>
<sign v-else="flag"></sign>
</div>
<!-- <my-cont>{{ mag }}</my-cont> -->
</body>
<script>
//登录组件
Vue.component("login", {
template: `<h1>登录板块</h1>`,
data() {
return {
}
},
})
//注册组键
Vue.component("sign", {
template: `<h1>注册板块</h1>`,
data() {
return {
}
},
})
const v = new Vue({
el: "#app",
data: {
msg: "xxx",
flag: true,
},
methods: {
log(){
this.flag = true//登录按钮控制,配和v-if
},
sig(){
this.flag = false//注册按钮控制,配和v-else
}
},
})
</script>
---缺点,只能在俩中状态中切换
component 标签:
<style>
.v-enter, .v-leave{
opacity: 1;
}
.v-enter-avtive,.v-leave-active{
transform: translateX(150px);
color: rgb(209, 62, 4);
opacity: 0;
transition: all 1.2s ease
}
</style>
<body>
<div id="app">
<a href="" @click.prevent="name='login'"><button>登录</button></a>
<a href="" @click.prevent="name='sign'"><button>注册</button></a>
<a href="" @click.prevent="name='way'"><button>路人</button></a>
<!-- vue 提供的component标签用于切换组件 :is="xxx" xxx就是要切换的组件名 -->
<!-- 这个组件名定义成实例data数据的一个变量 -->
<transition>
<component :is="name"></component>
</transition>
</div>
</body>
<script src="./vue.js"></script>
<script>
//登录组件
Vue.component("login", { 啊0
template: `<h1>登录板块</h1>`,
data() {
return {
}
},
})
//注册组键
Vue.component("sign", {
template: `<h1>注册板块</h1>`,
data() {
return {
}
},
})
//路人a组键
Vue.component("way", {
template: `<h1>路人板块</h1>`,
data() {
return {
}
},
})
const v = new Vue({
el: "#app",
data: {
name: ""
},
methods: {
},
})
</script>
vue 提供的一些标签(元素)
<component></component>/<template><template>/<transition></transition>/<transitionGroup></transitionGroup>
----------------------------------------------------------------
组件间的传值----
父向子传递普通属性数据:
<body>
<div id="app" v-cloak>
<!-- 传递父组件的msg 使用自定义属性传递 -->
<login :fuzi="msg"></login><!-- ① -->
</div>
</body>
<script src="./vue.js"></script>
<script>
const c = new Vue({
el: '#app',
data: {
msg: "fufu",
},
methods: {
change(){
console.log("fu")
}
},
components: {
login:{
//子组件可以使用父组件传递的值,为了后期冲突,在父组件传递属性的时候
//属性名最好不要和子组件的data里的属性名相同,不然后警告
template: `<h1>子组件{{ fuzi + msg }}</h1>`,
//props是数组 里面的值都是父组件传递过来的,数组的值就是上面父组件传递的属性
//props接受到的值可以改,但是千万别动一旦更改 修改的这个值的源头就会不再指向唯一
//违背单流体原则,当一个父组件中有多个子组件时,子组件的数据 应该由 父组件统一管理(不应该在子组件的data中管理)
//好处:增加组件的复用性 以及可维护性
props: [
"fuzi"/* ① */
],
data(){
return {
msg: "zizi"
}
}
}
}
})
</script>
子向父传递(通过自定义事件)理解为父给子一个方法模型,子调用该方法后
父就可以拿到子调用方法时的参数并赋值给自己的数据上:
<body>
<div id="app" v-cloak>
<!-- 自定义的事件名,就是子组件要接受的属性 ①-->
<!-- 如果change加个()就成了方法的调用,会把方法的结果传递给子组件 -->
<login @aaa="change"></login>
</div>
</body>
<script src="./vue.js"></script>
<script>
const v = new Vue({
el: "#app",
data: {
msg: "fu" ,
setmsg: null,
},
methods: {
change(a1,a2) {
console.log("fufufufufu" + a1 + a2)
this.setmsg = a2//收到子组件传过来的值,赋值给自己的data数据
}
},
components: {
login: {
template: `
<div>
<h1>我是子</h1>
<button @click="btn">子组件按钮,来调用父组件的方法</button>
</div>
`,
data: {
msg: "xxx"
},
methods: {
btn(){
//使用this.$emit来接受父组件的传递的方法①
//可以接受传参,参数和父组件中的change参数保持一致
//父组件的参数时形参,子组件的是实参
//因为这个子组件的aaa可以理解为指向父组件的change
//这里的实参可以是子组件里的data数据,父组件里就可以收到该子组件传递回去的数据
this.$emit("aaa",11,this.msg)
}
},
}
},
})
</script>
兄弟之间的传递(事件总线)
原理和子向父传递一样,只不过兄弟之间不能只能在组件标签内写自定的事件,所以需要用一个第三方组件来链接
定义一个全局的总线(第三方)bus,谁向外传递值就给谁调用bus.$eimt("自定义事件名①",传递的值)
谁接收就给谁调用bus.$on("自定的事件名①",(形参->传递的值)=>{})
<body>
<div id="app" v-cloak>
<!-- 自定义的事件名,就是子组件要接受的属性 ①-->
<!-- 如果change加个()就成了方法的调用,会把方法的结果传递给子组件 -->
<login></login>
<logins></logins>
</div>
</body>
<script src="./vue.js"></script>
<script>
//第三方中间过度
const bus = new Vue()
const v = new Vue({
el: "#app",
data: {
msg: "fu",
setmsg: "",
},
methods: {
change(a1) {
console.log("fufufufufu" + a1)
this.setmsg = a1
}
},
components: {
login: {//子组件1
template: `
<div>
<h1>我是子1</h1>
<button @click="btn">我是子1</button>
</div>
`,
data(){
return {
setmsg: "xiongdi1"
}
},
methods: {
btn(){
bus.$emit("aaa",this.setmsg)//传递给子组件2的值,自定义事件aaa
}
},
},
logins: {//子组件2
template: `
<div>
<h1>我是子2</h1>
<button>我是子2</button>
</div>
`,
data(){
return {
setmsg: ""
}
},
methods: {
},
mounted(){
bus.$on("aaa",(setmsg)=>{//接受自定义事件aaa
this.setmsg = setmsg//接收子组件1传过来的值,并赋值给自己的data数据上
})
}
},
},
})
</script>
一下三种通信 不太常用
-
ref 父组件中直接获取子组件的实例 需要记住
面试题:如何在父组件中 直接调用子组件的 方法 -
实例 $parent属性和 $children属性
$parent获取父组件实例(子组件中使用)
$children 获取 所有的子组件 返回的是数组(父组件中使用) -
provide/inject
provide 父组件属性 提供给 子组件的数据
inject 父组件通过provide提供的数据,子组件可以通过inject拿到