vue组件 component

    科技2025-05-23  41

    vue组件 component

    简单理解一、定义二、分类全局组件局部组件 三、关系1.父子2.兄弟3.无关系 四、通信父向子通信子向父通信兄弟组件通信另外三种通信ref通信$children $parentprovide/inject 五、插槽普通插槽命名插槽(具名插槽)


    简单理解

    组件可以理解为网页上的的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.无关系


    四、通信

    父向子通信

    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 } } 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, } })
    Processed: 0.010, SQL: 8