vue组件 component


简单理解

  • 组件可以理解为网页上的的html元素,也可以理解为网页上一个独立的部分(比如说网页头部、主体、尾部等)
  • 组件实际上是让我们写好的代码复用性更高的一种方式
  • 通过多种基础组件的组合形成完整的功能,而且因为代码的复用不会增加多余的代码,这样的话修改相对而言也会更加方便
  • vue new出来的实例其实也是组件(实例的属性组件也都有)

一、定义

 let CommonHeader = {
  template:"",
  data(){
    return{
    }
  },
  methods:{
  }
}

二、分类

全局组件

在Vue上注册的就是全局组件,在任意的组件和实例上都可以使用

let CommonHeader = {
  template:"<h1>这是一个公共的头部文件</h1>",//里面写html标签,即视图文件
  data(){
    return{
    }
  },
  methods:{
  }
}
Vue.component("CommonHeader",CommonHeader)//组件命名建议使用大驼峰或连接符
const vm = new Vue({
  el: '#box',
  data: {
  },
  methods: {
  }
})

局部组件

1、在某个组件或者实例中注册的就是局部组件,只能在注册的组件或者实例上使用
2、局部组件可以在其他组件的conponents上注册(即既可以是new Vue,也可以是其他组件)

示例1:在 new Vue上注册

//在 new Vue上注册可以在这个实例中应用  当前是id为box的标签
let CommonTitle = {
  template:`<h1>这是局部组件标题</h1>`,
  data () {
    return {

    }
  },
  methods: {

  }
}
const vm = new Vue({
  el: '#box',
  data: {
  },
  methods: {
  },
  components: {
    'CommonTitle':CommonTitle
  }
})

示例2:在 其他组件的components属性上注册

//在其他组件注册则只能在当前组件的template模板中使用
let CommonTitle = {
  template:`<h1>这是局部组件标题</h1>`,
  data () {
    return {
    }
  },
  methods: {

  }
}
let CommonHeader = {
  template:`
  <div>
    <h1>这是大标题</h1>
    <common-title></common-title>
  </div>
  `,
  data(){
    return{

    }
  },
  methods:{

  },
  components: {
    'CommonTitle': CommonTitle
  }
}

Vue.component("CommonHeader",CommonHeader)
const vm = new Vue({
  el: '#box',
  data: {
  },
  methods: {
  },
  // components: {
  //   'CommonTitle':CommonTitle
  // }
})

注意

  • 组件中的data 必须是 一个函数 返回一个对象 (原因是 组件是需要复用的 ,如果直接是对象,多次使用时,使用的是同一个对象,不符合项目开发要求,而如果是返回对象的话(实际上是闭包),会让组件在每一次使用的时候都形成一个独立的空间 )
  • 每个组件有自己的作用域,组件内部的数据,和方法只能在组件内部使用(如向跨组件,需要组件间通信)
  • 组件的命名 可以有两种 1大驼峰 2下划线命名法
    eg:
    CommonHead common-head
    使用时二者都一样
  • 局部组件 在哪个组件的components中注册,就只能在这个组件的template中使用
  • 组件的template 有且只能有一个根标签(元素)

三、关系

组件间的嵌套使用形成了组件间的关系

1.父子

2.兄弟

3.无关系


四、通信

父向子通信

  1. props通信
//子组件的props属性  值是一个数组,数组内容是父组件传进来的参数列表
//父组件   相当于增加一个自定义属性

//1  传一个静态的数据
<body>
  <div id="box">
    <home></home>
  </div>
<script>
  let CommonTitle = {
    props:['title'],
    template: `
    <div>  
      这是标题
      <h2>{{ title }}</h2>
    </div>`,
  }
  let Home = {
    template: `
    <div> 
      <common-title title="我是首页"></common-title> 
      home页面内容  
    </div>`,
    data () {
      return {
        title:"我是home页"
      }
    },
    components: {
      CommonTitle
    }
  }
  let  vm = new Vue({
    el: '#box',
    components: {
      Home
    }
  })
</script> 
</body>

//2 传一个动态的数据
//父组件 自定义属性之前加冒号:   自动去找data里面的变量
 let Home = {
    template: `
    <div> 
      <common-title :title="title" :title2="title2"></common-title> 
      home页面内容  
    </div>`,
    data () {
      return {
        title:"我是home页",
        title2:"我是home页2"
      }
    },
    components: {
      CommonTitle
    }
  }

  1. props验证
    props用法,没有校验 props数据类型,以及必须填写,默认值 等,会造成 程序 存在 不稳定性 (代码不健壮)

验证三种类型: 数据类型 是否必须填写 默认值

数据类型:String Number Boolean Array Object Date Function Symbol
是否必须填写: required:true/false true必填 false非必填
默认值 : default

// 此时props不是数组,而是对象
props:{
			//只验证类型
			a:String,
			//既验证类型,又要求必传
			b:{
				type:[String,Number],//类型是多个中的一个
				required:true
			},
			//验证类型,并设置默认值
			c:{
				type:Number,
				default:0
			}
		}
		

注意

  • props中定义的参数名会自动的编译成实例,属性
  • props名字不能和data中以及methods和计算属性,不能同名
  • 如果默认值是数组或者对象,则需要一个函数返回这个默认值
  • props能否改变props保持单向的 即父向子(子不能改变),易于维护

子向父通信

通过自定义事件触发

//子组件  methods中 this.$emit("事件名",携带的数据)
/* 
父组件 <子组件  @事件名="fn"></子组件>  
methods中 fn(data){  data就是子组件传过来的数据} 
*/
<script>
  let CommonTitle = {
    template: `
    <div>  
      子组件
      <button @click="change">单击传输数据</button>
    </div>`,
    data () {
      return {
        msg: '我是子组件的数据'
      }
    },
    methods: {
      change () {
        // this.$emit("事件名",this.msg)
        this.$emit("change1",this.msg)
      }
    }
  }
  let Home = {
    template: `
    <div> 
      <common-title @change1="fn"></common-title> 
      home页面内容  
    </div>`,
    data () {
      return {
        title:"我是home页",
        title2:"我是home页2"
      }
    },
    methods: {
      // fn () {
      //   alert("出发了fn")
      // }
      fn (msg) {
        alert(msg)
      }
    },
    components: {
      CommonTitle
    }
  }
  let  vm = new Vue({
    el: '#box',
    components: {
      Home
    }
  })
</script>  
</body>

兄弟组件通信

<body>
  <div id="box">
    <home></home>

  </div>
<script>
  //事件总线   ---中央事件总线
  /*
  利用了第三方的实例   
    this.$emit("事件名",参数)  //组件一
    this.$on("事件名",fn)   //组件二
   */
  let eventBus = new Vue() //事件总线 用来弹射和监听事件
  let CommonTitle = {
    template: `
    <div>  
      子组件1
      <button @click="change">单击传输数据</button>
    </div>`,
    data () {
      return {
        msg: '我是子组件1的数据'
      }
    },
    methods: {
      change () {
        eventBus.$emit("change1",this.msg)
      }
    }
  }
  let CommonTitle2 = {
    template: `
    <div>  
      子组件2
      {{ msg}}
    </div>`,
    mounted() {
      // eventBus.$on("change1",()=>{
      //   alert("接收到了")
      // })
      eventBus.$on("change1",(msg)=>{
        this.msg=msg
      })
    },
    data () {
      return {
        msg: '我是子组件2的数据'
      }
    }
  }
  let Home = {
    template: `
    <div> 
      <common-title ></common-title> 
      <hr/>
      <common-title2 ></common-title2> 
      home页面内容  
    </div>`,
    data () {
      return {
        title:"我是home页",
        title2:"我是home页2"
      }
    },
    components: {
      CommonTitle,
      CommonTitle2
    }
  }
  let  vm = new Vue({
    el: '#box',
    components: {
      Home

    }
  })

</script>  
</body>

注意
1 兄弟组件通信,是谁emit的谁去on,所以需要定义一个第三方组件eventBus
2 回调函数如果不写成箭头函数,需要处理this问题

  • 可以在外部定义一个变量接收this
let _this=this
eventBus.$on("change1",function(msg){
       _this.msg=msg
 })
  • 可以使用bind(this)
eventBus.$on("change1",function(msg){
       this.msg = msg
}.bind(this))

另外三种通信

ref通信

直接在父组件里面拿到了子组件这个实例

  let CommonTitle = {
    template: `
    <div>  
      子组件1  
    </div>`,
    data () {
      return {
        msg: 123
      }
    },
  
  }
  let Home = {
    template: `
    <div> 
      <common-title ref="commonTitle" ></common-title>   
    </div>`,
    mounted () {
      console.log(this.$refs.commonTitle)//此时打印得到的是子组件这个实例本身
    },
    components: {
      CommonTitle, 
    }
  }
  let  vm = new Vue({
    el: '#box',
    components: {
      Home
    }
  })
  //不建议直接使用ref操作子组件

$children $parent

子组件里引用$parent

mounted () {
      console.log(this.$parent)//得到的是当前组件的父组件
    }
/*
VueComponent {_uid: 1, _isVue: true, $options: {…}, _renderProxy: Proxy, _self: VueComponent, …}
*/

父组件引用$children

mounted ()  {
      console.log(this.$parent)    // 得到的当前组件的所有子组件,是数组,通过下标可以直接得到子组件
    }
//   [VueComponent]

provide/inject

父组件 提供provide

let msg=12345
let Home = {
    provide:{
      msg:msg,
      num:107
    },
 }

子组件 接收inject

  let CommonTitle = {
    inject: ["msg","num"],
    mounted () {
      console.log(this.msg)//12345
      console.log(this.num)//107
    }
}

五、插槽

其实是用来占位的,是vue的系统组件

<solt></slot>
//在使用组件时,自定义标签内容,会自动的灌入到solt占的位置上
//可以实现组件在不同的父组件中使用时,内部可以有不一样的代码块(布局)

普通插槽

// News 组件和 Home组件是父组件  在当前页面使用
// CommonTitle 是子组件 组件中使用了插槽<slot>插槽的默认值</slot>
/*
1 如果是在父组件中直接使用子组件<common-title><common-title>
则渲染的的是内容    插槽的默认值
2 如果是在父组件中使用
<common-title>
	<div>
		你好
	<div>
<common-title>
则渲染的内容是  你好
*/ 
let CommonTitle = {
    template: `
    <div>
      <h2>我是子组件</h2>
      <slot>插槽的默认值</slot>
    </div>
    `
  }
  let msg = 12345
  let Home = {
   template:`
    <div>
      home页内容
      <common-title>
        <h5>我是插槽对应的内容</h5>
        <p>lllll</p>
      </common-title>
    </div>`,
    data () {
      return {
        title:"我是home页"
      }
    },
    components: {
      CommonTitle, 
    }
  }
  let News = {
   template:`
    <div>
      news页内容
      <common-title>
        <button>按钮</button>
      </common-title>

    </div>`,
    data () {
      return {
        title:"我是news页"
      }
    },
    components: {
      CommonTitle, 
    }
  }
  let  vm = new Vue({
    el: '#box',
    components: {
      Home,
      News
    }
  })

命名插槽(具名插槽)

可以在子组件中,定义多个插槽,且每个插槽,有自己的名字,在代码传入时,指定传入哪个

  let CommonTitle = {
    template: `
    <div>
      <h2>我是子组件</h2>
      <slot name="xm"></slot>
      <slot name="xq"></slot>
    </div>
    `
  }
  let Home = {
   template:`
    <div>
      home页内容
      <common-title>
        <template slot="xq">
          <button>我是小强</button>//此时的button会占用 name="xq"的位置
        </template >
        <div slot="xm">
          <button>我是小明</button>//此时的button会占用 name="xm"的位置
        </div>
      </common-title>
    </div>`,  
    components: {
      CommonTitle, 
    }
  }
  let  vm = new Vue({
    el: '#box',
    components: {
      Home,
 
    }
  })
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值