Vue组件

Vue组件

Vue实例与组件

通过new Vue()产生的是Vue实例,而Vue实例也可以看做根组件。

我们也可以通过Vue.component()产生Vue组件,所谓组件就是可以复用到其他的实例中的部件,它分为全局组件和局部组件。

  • 全局组件:全局组件又称根组件,它可以在任意位置被调用
  • 局部组件:局部组件只能在定义位置的实例/组件中使用

img

组件的基本使用

全局组件定义方法

Vue.component(
    'child',  // 组件标签名
              {
	template: `<h1>html模板</h1>
	用模板字符串编写即可,它的子组件只能在这里使用
	<grandchild></grandchild>
	`,  // 里面写html内容,必须包在一个标签中
    data() {       // 比起data:数据对象,这种返回对象的方式每次都是新产生的,可以复用
        return {
            name: '彭于晏',
            t: null
        }
    },
    methods: {},  // 组件方法,可以在组件标签范围内使用
    components: {  // 子组件
        'grandchild': {
            template: `
              <div>
              <h1>局部组件---{{ gcdata }}</h1>
              </div>`,
            data() {
                return {
                    gcdata: '孙子'
                }
            }
        },
    }
})

注意事项:

  • Vue实例是通过el挂载html的标签,而Vue组件是成为html的一种标签
  • template的html内容,必须最终包含在一个标签内
  • 因为对象都是引用型的,所以作为复用的组件,data要以函数的形式产出返回,而不能直接用键值对的形式,因为这种情况组件被用多次时会共用一份data
  • components字段可以作为组件的子组件,也可以作为实例的子组件

组件基础使用方法

<div id='app'>Vue实例通过el='#app'的方式绑定标签(挂载)
	# 组件标签名child,将对应组件的template中的模板添加到此标签的位置进行渲染
    <child></child>
    # 另一种调用形式
    <child/>
    # 不是根组件不能在全局使用 x
    <grandchild></grandchild>
</div>  
# 由于是根组件,什么位置都可以,和app实例也无关
<child></child>

局部组件定义的两种方式

  1. 第一种是上述示例代码中,直接嵌套的方式

  2. 第二种是先定义一个对象,然后在放入全局组件的component中

    let grandchild ={
                template: ``,
                data() {},
            }
    
    Vue.component(
        'child',  // 组件标签名
                  {
    	template:  ``  // 里面写html内容,必须包在一个标签中
        data() {},  // 返回数据的方法
        methods: {},  // 组件方法,可以在组件标签范围内使用
        components: {  // 子组件
            grandchild
        }
    })
    

组件间通信

父标签与子标签中的变量名默认是隔离的,想使用对方的数据则需要数据传递。

自定义属性 -- 实现父传子通信

<div id="app">
    <!--pdata就是在props中注册的属性,在这里通过属性方法绑定父组件的数据,
在子组件中可以通过pdata引用-->
    <child :pdata="parentData"></child>
</div>
<script>
    let child = {
        template: `
          <div>
          <p>父组件传过来的:{{pdata}}</p>
          <p>子组件自己的:{{childdata}}</p>
          </div>`,
        data() {
            return {childdata: '儿子数据'}
        },
        // props: ['pdata']
		props:{
            pdata:String,
        }
    }

    new Vue({
        el: '#app',
        data: {
            parentData: '父亲数据'
        },
        components:{
            child
        }
    })
</script>
  • 自定义属性需要注册在props中,props可以是数组形式和对象形式
    • 数组形式则就是直接注册了自定义属性
    • 对象形式的键作为自定义属性,后面用于数据属性限制如String、Number
  • 注册的属性可以通过属性方法:attr="pdata"绑定父组件的数据
  • 自定义属性最好采取单词,其他形式都有可能出错,尤其是小驼峰

自定义组件 -- 实现子传父通信

<div id="app">
    <p>子组件传递过来的数据:{{parentData}}</p>
    <!---myevent事件触发了父组件中的方法,并传入了子组件的数据-->
    <child @myevent="handleEvent"></child>
</div>
<script>
    let child = {
        template: `
          <div>
          <hr>
          <input type="text" v-model="childdata">
          <button @click="loadToParent">上传到父组件</button>
          <hr>
          </div>`,
        data() {
            return {childdata: ''}
        },
        methods:{
            loadToParent(){
                // $emit方法将数据传给myevent事件触发的函数
                this.$emit('myevent',this.childdata)
            }
        }
    }
    new Vue({
        el: '#app',
        data: {
            parentData: ''
        },
        methods: {
            handleEvent(childdata){
                // 父组件拿到了子组件的数据进行操作
                this.parentData=childdata
            }
        },
        components:{
            child
        }
    })
</script>
  • $emit方法将数据传给myevent事件触发的函数

  • myevent事件触发了父组件中的方法,并传入了子组件的数据

    @myevent事件可以写在子组件的属性中

  • 父组件定义的方法要定义一个形参接收子组件的数据

ref属性 -- 实现完全通信

在Vue实例/组件中的标签或者组件都可以添加ref属性,添加了ref属性的标签/组件都会被根组件的this.$refs接收组织成一个对象。

  • html原生标签加ref属性,$refs中对应的值为DOM标签
  • vue组件添加ref属性,$refs中对应的值为Vue组件对象,包含组件的所有属性包括数据属性,并且因为对象的引用传值,我们也可以对其进行修改。

由于ref属性取和修改组件属性都非常方便,所以就可以用于父子组件间的完全通信。

<div id="app">
    <p ref="pEle">子组件传递过来的数据:{{parentData}}</p>
    <child ref="child"></child>
    <button @click="handleClick">上传</button>
</div>
<script>
    let child = {
        template: `
          <div>
          <hr>
          <input type="text" v-model="childdata">
          <hr>
          </div>`,
        data() {
            return {childdata: ''}
        },
    }

    new Vue({
        el: '#app',
        data: {
            parentData: ''
        },
        methods: {
            handleClick(){
                this.parentData=this.$refs.child.childdata
                console.log(this.$refs)
            }
        },
        components:{
            child
        }
    })
</script>

组件进阶方法

动态组件

组件标签,vue提供用来根据组件名反射组件的:

<component is="组件名"></component>

那么我们可以对is属性做数据绑定,通过:is="变量"达到动态组件的效果。

<div id="app">
    <span @click="handleClick('aComponent')">a组件</span>|
    <span @click="handleClick('bComponent')">b组件</span>|
    <span @click="handleClick('cComponent')">c组件</span>
    <br>
    <component :is="showComponent"></component>
</div>
<script>
    let aComponent = {template: `<h1>a组件</h1>`}
    let bComponent = {template: `<h1>b组件</h1>`}
    let cComponent = {template: `<h1>c组件</h1>`}
    new Vue({
        el: '#app',
        data: {
            showComponent: 'aComponent'
        },
        methods: {
            handleClick(componentName){
                this.showComponent = componentName
            }
        },
        components: {aComponent, bComponent, cComponent}
    })
</script>

keep-alive标签

在上述代码的基础上,只需要在component标签外侧添加keep-alive标签嵌套,就能保证内部的所有产生的组件只会隐藏不会销毁,这样就保证了一些组件在进行一些操作后能够保存状态,而不会重新加载导致状态丢失。

<keep-alive>
    <component :is="showComponent"></component>
</keep-alive>

image

插槽

组件的模板中可以使用slot标签预留位置,当在组件被调用时,可以在组件标签体中书写html标签,这样增强了组件的拓展性和灵活性。

匿名插槽

  • 在child组件标签内书写html代码,标签就会渲染到组件模板slot的位置
  • 如果预留了多个slot并没有命名则每个slot的位置都会渲染插入的html代码
<div id="app">
<child>
    <h1>匿名插入</h1>
</child>
</div>
<script>
    let child = {
        template: `
          <div>
          <hr>
          <slot></slot>
          <hr>
          <slot></slot>
          <hr>
          </div>`,
    }

    new Vue({
        el: '#app',
        data: {},
        methods: {},
        components: {child}
    })
</script>

具名插槽

  • 给模板slot标签加上name,则就变成了具名插槽
  • 通过具名插槽插入的标签,需要添加对应的slot属性 slot="slot1"
  • 组件标签体中的其他标签(没有slot属性)都插入到匿名插槽中。
<div id="app">
<child>
    <h1>匿名插入</h1>
    <h1 slot="slot1">slot1插入</h1>
    <h1 slot="slot2">slot2插入</h1>
    <h1>没添加slot属性的标签都是匿名插入</h1>
</child>
</div>
<script>
    let child = {
        template: `
          <div>
          <slot></slot>
          <hr>
          <slot name="slot1"></slot>
          <hr>
          <slot name="slot2"></slot>
          <hr>
          </div>`,
    }

    new Vue({
        el: '#app',
        data: {},
        methods: {},
        components: {child}
    })
</script>
posted @ 2023-02-16 22:28  leethon  阅读(45)  评论(0编辑  收藏  举报