vue的局部组件的使用
渲染组件-父使用子组件
-
1: 创建子组件(对象)
var Header = { template:'模板' , data是一个函数,methods:功能,components:子组件们 }
-
2: 在父组件中声明,根属性
components:{ 组件名:组件对象 }
-
3: 在父组件要用的地方使用
<组件名></组件名>
-
在不同框架中,有的不支持大写字母,用的时候
- 组件名 MyHeader
- 使用 my-header
-
-
总结: 有父,声子,挂子,用子
<div id="app">
</div>
<script type="text/javascript" src="./vue.min.js"></script>
<script type="text/javascript">
// 全局组件
// 第一个参数是组件的名字 第一个参数是options
Vue.component('Vbtn',{
template:`
<button>按钮</button>
`
});
var Vcontent = {
template:`
<div>
我是内容组件
<Vbtn />
<Vbtn />
<Vbtn />
</div>
`
};
var Vaside = {
template:`
<div>
我是侧边栏组件
<Vbtn />
</div>
`
};
var Vheader = {
data(){
return {
}
},
template:`
<div>
我是头部组件
</div>
`,
methods:{
}
};
// 1.声子
var App = {
template:`
<div>
<Vheader />
<div>
<Vaside />
<Vcontent />
</div>
</div>
`,
components:{
Vheader,
Vaside,
Vcontent
}
};
new Vue({
el:'#app',
data(){
return {
}
},
components:{
// 2.挂子
App
},
// 3.用子
template:`<App />`
});
</script>
通过prop往子组件通信
父子组件传值(父传子)
-
1:父用子的时候通过属性Prop传递
-
2:子要声明props:[‘属性名’] 来接收
-
3:收到就是自己的了,随便你用
- 在template中 直接用
- 在js中 this.属性名 用
-
总结:父传,子声明,就是子的了
-
小补充: 常量传递直接用,变量传递加冒号
<div id="app">
</div>
<script type="text/javascript" src="./vue.min.js"></script>
<script type="text/javascript">
// 全局组件
// 第一个参数是组件的名字 第一个参数是options
// 1.Parent 2.Child
Vue.component('Child',{
created(){
console.log(this.childData);
},
template:`
<div>
<p>我是一个孩子组件{{childData}}</p>
<input type="text" v-model = 'childData'/>
</div>
`,
props:['childData']
});
// 父===> 子
// 1.先给父组件中绑定自定义的属性
// 2.在子组件中使用props接收父组件传递的数据
// 3.可以在子组件中任意使用
Vue.component('Parent',{
data(){
return {
msg:"我是父组件的数据"
}
},
template:`
<div>
<p>我是一个父组件</p>
<Child :childData ='msg' />
</div>
`
});
// 1.声子
var App = {
template:`
<div>
<Parent />
</div>
`
};
new Vue({
el:'#app',
data(){
return {
}
},
components:{
// 2.挂子
App
},
// 3.用子
template:`<App />`
});
</script>
总结父传子
- 父用子 先声子,挂子,用子
- 父传子 父传子(属性),子声明(收),子直接用(就是自己的一样)
通过事件向子组件发送消息
子传父
- 1.子要绑定原生事件,在原生事件函数中通过
this.$emit(‘自定义的事件名’,arg1);
触发父组件中子组件自定义的事件名 - 2.父组件中的子组件
v-bind:自定义事件的名字 = 'fn'
绑定自定义的事件 - 3.父组件 就可以触发fn的函数 数据就可以从子组件中传过来了
<div id="app">
</div>
<script type="text/javascript" src="./vue.min.js"></script>
<script type="text/javascript">
Vue.component('Child',{
template:`
<div>
<p>我是一个孩子组件</p>
<input type="text" v-model = 'childData' @input = 'changeValue(childData)'/>
</div>
`,
props:['childData'],
methods:{
changeValue(val){
// 自定义的事件 一定通过this.$emit()去触发
// $emit(自定义的事件名,消息)
this.$emit('childHandler1',val)
}
}
});
// 子 ===》 父
// 1.在父组件绑定 自定义的事件
// 2.在子组件中 触发原生的事件 在函数中使用 $emit触发自定义的childHandler
Vue.component('Parent',{
data(){
return {
msg:"我是父组件的数据"
}
},
template:`
<div>
<p>我是一个父组件</p>
<Child :childData ='msg' @childHandler1 = 'childHandler'/>
</div>
`,
methods:{
childHandler(val){
console.log(val);
}
}
});
// 1.声子
var App = {
template:`
<div>
<Parent />
</div>
`
};
new Vue({
el:'#app',
data(){
return {
}
},
components:{
// 2.挂子
App
},
// 3.用子
template:`<App />`
});
</script>
props
和$emit
父组件向子组件传递数据是通过prop传递的,子组件传递数据给父组件是通过$emit触发事件来做到的。
在下面的例子中,有父组件App和子组件Child。
- 父组件传递了message数据给子组件,并且通过v-on绑定了一个getChildData事件来监听子组件的触发事件;
- 子组件通过props得到相关的message数据,最后通过this.$emit触发了getChildData事件。
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.js"></script>
<script type="text/javascript">
Vue.component('Child',{
data(){
return {
aaa:this.message
}
},
template:`
<div>
<input type="text" v-model="aaa" @input="passData(aaa)"/>
</div>
`,
props:['message'],
methods:{
passData(val){
this.$emit('getChildData',val);
}
}
});
var App = {
data(){
return {
msg:'我是父组件的内容'
}
},
methods:{
getChildData(val){
console.log(`我是子组件传进来的${val}`);
}
},
template:`<div>
<p>这是一个父组件</p>
<Child :message = 'msg' @getChildData = "getChildData"></Child>
</div>`
}
new Vue({
el:"#app",
data(){
return {
}
},
components:{
App
},
template:`<App />`
});
</script>
$attrs
和$listeners
第一种方式处理父子组件之间的数据传输有一个问题: 如果父组件A下面有子组件B, 组件B下面有组件C, 这时如果组件A想传递数据给组件C怎么办呢?
如果采用第一种方法, 我们必须让组件A通过prop传递消息给组件B, 组件B在通过prop传递消息给组件C; 要是组件A和组件C之间有更多的组件, 那采用这种方式就很复杂了。 Vue 2.4 开始提供了$attrs
和$listeners
来解决这个问题, 能够让组件A之间传递消息给组件C。
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
<script type="text/javascript">
Vue.component('C', {
data() {
return {
}
},
template: `
<div>
<div @click = 'cClickHandler'>{{$attrs.messagec}}</div>
</div>
`,
methods: {
cClickHandler(){
alert(1);
this.$emit('getCData','我是c的数据')
}
}
});
Vue.component('B', {
data() {
return {
}
},
template: `
<div>
<C v-bind="$attrs" v-on = '$listeners'></C>
</div>
`,
methods: {
}
});
Vue.component('A', {
data() {
return {
}
},
// props:['message'],
template: `
<div>
<B v-bind="$attrs" v-on = '$listeners'></B>
<!--<input type="text" v-model = '$attrs.messagec' />-->
</div>
`,
methods: {
}
});
var App = {
data() {
return {
msg: '我是父组件的内容',
messagec:'hello c'
}
},
methods: {
},
template: `<div>
<p>这是一个父组件</p>
<A :messagec = 'messagec' v-on:getCData="getCData" ></A>
</div>`,
methods:{
// 执行c组件的触发的函数
getCData(val){
console.log(val);
}
}
};
new Vue({
el: "#app",
data() {
return {
}
},
components: {
App
},
template: `<App />`
});
</script>
</body>
上面两种方式处理的都是父子组件之间的数据传递,而如果两个组件不是父子关系呢?这种情况下可以使用中央事件总线的方式。新建一个Vue事件bus对象,然后通过bus.$emit
触发事件,bus.$on
监听触发的事件。
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
<script type="text/javascript">
// 中央事件总线
var bus = new Vue();
Vue.component('brother2', {
data() {
return {
msg:"hello brother1"
}
},
template: `
<div>
<p>我是老大</p>
<input type="text" v-model = 'msg' @input = 'passData(msg)' />
</div>
`,
methods: {
passData(val){
// //触发全局事件globalEvent
bus.$emit('globalEvent',val)
}
}
});
Vue.component('brother1', {
data() {
return {
msg:"hello brother1",
brother2Msg:''
}
},
template: `
<div>
<p>我是老二</p>
<p>老大传递过来的数据:{{brother2Msg}}</p>
</div>
`,
mounted(){
// 绑定全局事件globalEvent事件,
bus.$on('globalEvent',(val)=>{
bus.brother2Msg = val;
})
}
});
var App = {
data() {
return {
msg: '我是父组件的内容',
messagec:'hello c'
}
},
methods: {
},
template: `<div>
<brother1></brother1>
<brother2></brother2>
</div>`,
methods:{
// 执行c组件的触发的函数
getCData(val){
console.log(val);
}
}
}
new Vue({
el: "#app",
data() {
return {
}
},
components: {
App
},
template: `<App />`
});
</script>
父组件中通过provide来提供变量,然后在子组件中通过inject来注入变量。不论子组件有多深,只要调用了inject那么就可以注入provider中的数据。而不是局限于只能从当前父组件的prop属性来获取数据,只要在父组件的生命周期内,子组件都可以调用。
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
<script type="text/javascript">
Vue.component('Child',{
data(){
return {
msg:''
}
},
template:`
<div>我是孩子{{msg}}</div>
`,
inject:['for'],
created(){
this.msg = this.for;
}
});
Vue.component('Parent',{
template:`
<div>
<p>我是父亲</p>
<Child />
</div>
`
});
var App = {
data(){
return {
}
},
provide:{
for:'他爹'
},
template:`
<div>
<h2>我是入口组件</h2>
<Parent />
</div>
`
}
new Vue({
el:"#app",
template:`<App />`,
data(){
return {
}
},
components:{
App
}
});
</script>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
<script type="text/javascript">
Vue.component('Child',{
data(){
return {
msg:''
}
},
props:{
value:String, //v-model会自动传递一个字段为value的prop属性
},
methods:{
changeValue(){
alert(1);
this.$emit('input',this.value);通过如此调用可以改变父组件上v-model绑定的值
}
},
template:`
<div>
<input type="text" v-model = 'value' @change = 'changeValue'/>
</div>
`
});
Vue.component('Parent',{
data(){
return {
msg:'我是父组件的数据'
}
},
template:`
<div>
<p>我是父亲</p>
<Child v-model ='msg' @input = 'input'/>
</div>
`,
methods:{
input(val){
console.log(val);
}
}
});
var App = {
data(){
return {
}
},
template:`
<div>
<h2>我是入口组件</h2>
<Parent />
</div>
`
}
new Vue({
el:"#app",
template:`<App />`,
data(){
return {
}
},
components:{
App
}
});
</script>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vue/2.5.17-beta.0/vue.min.js"></script>
<script type="text/javascript">
Vue.component('Child', {
props: {
value: String, //v-model会自动传递一个字段为value的prop属性
},
data() {
return {
mymessage: this.value
}
},
methods: {
changeValue() {
console.log(this.mymessage);
this.$parent.message = this.mymessage; //通过如此调用可以改变父组件的值
console.log(this.$parent);
}
},
template: `
<div>
<input type="text" v-model="mymessage" @change="changeValue">
</div>
`
})
Vue.component('Parent',{
template:` <div >
<p>我是父亲组件{{message}}</p>
<button @click = "changeChildValue" > test < /button >
<Child ></Child>
</div>
`,
methods:{
changeChildValue(){
this.$children[0].mymessage = 'hello';
}
},
data(){
return {
message:'hello'
}
}
})
var App = {
data(){
return {
}
},
template:`
<div>
<h2>我是入口组件</h2>
<Parent />
</div>
`
}
var vm = new Vue({
el:'#app',
components:{
App
},
template:`
<App></App>
`
})
console.log(vm);
</script>
具名插槽
<div id = 'app'></div>
<script type="text/javascript" src="./vue.min.js"></script>
<script type="text/javascript">
Vue.component('myLi',{
template:`
<li>
预留的第一个坑
<slot name = 'two'></slot>
预留的第二坑
<slot name = 'three'></slot>
</li>
`
});
var App = {
template:`
<div>
<ul>
<myLi>
<h2 slot='two'>我是第一个坑</h2>
<h3 slot= 'three'>我是第二个坑</h3>
</myLi>
</ul>
</div>
`
}
new Vue({
el:"#app",
components:{
App
},
template:`<App />`
});
</script>