Vue笔记4--组件和插槽

1、组件基础

Vue的特点:组件开发。页面将为是一颗嵌套的组件树

src目录下有个components,多个页面公用组件一般都放在其中(如:顶部导航栏、轮播图等)。组件首字母一般为大写。组件是带有名称可复用的实例。


1.1 vue2做法

1、在components下新建Content.vue的文件

2、在App.vue中引入,并且components注册,标准写法Content:Content,前为方便别名后为引入的组件。也可以直接简写如下

export default {
  data() {
    return {
    };
  },
  components:{
   Content//简写
  }
};

3、使用组件。ps.直接写<Content然后会跳出来选项自动补全代码。

  <div>
    <Content></Content>
  </div>

组件嵌套,在Content.vue中引入另一个组件

<template>
    <div>
        <h2>我是组件内容</h2>
        <Hello></Hello>
    </div>
</template>
<script>
import Hello from './Hello.vue'
export default{
    components:{
        Hello
    }
}
</script>

组件复用

父组件和子组件,在上面的例子中App.vue是根组件,Content.vue是Hello.vue的父组件,组件是单独功能模块的封装。

组件数据存放

父子组件并不可以随意的获取对方的数据,需要使用对应的方法。并且连续使用三个同样的组件,修改其中某一组件的data(),另外两个组件是独立的不受影响的。

data()是一个函数,每一次执行完都是返回一个新的对象

    data(){
        return{msg:"helloworld"} 
    },

除非定义const,让三个组件用的同一个obj。但这是不推荐的,会造成数据的污染。

const obj={
    msg:"helloworld"
}
export default{
    data(){
        return obj
    },
    components:{
        Hello
    }
}



1.2 父传子Prop

Prop是可以在组件上注册的一些自定义的属性

Content.vue中

    data(){
        return{
            msg:"helloworld"
        } 
    },
<Hello :message='msg' aaa="123"></Hello>

Hello.vue中

export default{
    props:['message','aaa'],
}
    <div>
        <h2>--{{message}}--{{aaa}}</h2>
    </div>

以数组的形式传递数据过去,其中message是动态而且绑定的,aaa静态,两个都可以传

Prop常用法

不以数组而是对象的形式

1 限制类型,可以限制传递过来数据的格式,可多种

    props:{
        message:String
        //message:[String,Number]
    }

2 设置默认值default

3 设置必传值required

    props:{
        message:{
            type:String,
            default:"你好",
            required:true,
        }
    }

对于默认值对象和数组的默认值必须从一个工厂返回

    props:{
        ···
        list:{
            type:Array,
            //default:[],错误写法
            default(){
                return []
            },
        }
    }

单项数据流

prop让父子之间形成一个单向下行绑定,父更新会流动到子中,反过来却不行。


1.3 子传父$emit监听

在App.vue中监听Content.vue子组件数据,通过自定义事件

1、在子组件Content.vue中通过$emit来触发事件

this.$emit(' 自定义事件的名称 ',' 发送的事件参数 ')

    methods:{
        sendParent:function(){
            this.$emit('injectMsg',this.msg)
        }
    },
<button @click="sendParent">提交数据给父组件</button>

2、在父组件App.vue中,通过v-on监听子组件的自定义事件

通过@绑定了在子组件里写的injectMsg事件,点击按钮事件触发,进而运行getChildMsg方法。

<Content @injectMsg="getChildMsg"></Content>
  methods:{
    getChildMsg:function(value){
      console.log(value);
    }
  },

3、在父组件App.vue中,存储获得数据

默认参数value就是传过来的数据

  data() {
    return {
      message: ""
    };
  },
  methods: {
    getChildMsg: function (value) {
      this.message = value;
    }
  },



1.4 父访问子$refs

父组件访问子组件,$refs和$children。vue3已经废弃$children,他有缺陷因为传递的是数组类型。

$refs需要搭配一个ref指令来使用,ref:用来给元素或者子组件注册引用信息,开发中经常用到,给子组件绑定自己的起的id名。

在子组件Content.vue中

<Hello :message='msg' aaa="123" :list="list" ref="hello"></Hello>
<p ref="p"></p>
export default {
    ···
    mounted(){//生命周期函数
        console.log(this.$refs);
        console.log(this.$refs.hello.aaa);
    },
    ···
}

通过控制台即可看到访问成功,通过$refs.hello.aaa即可拿到其中的内容,又或者$refs.p.id拿到p标签的属性。


1.5 子访问父$parent

但是在实际开发中不推荐使用this.$parent.*去获取父组件。因为组件复用性很高,会像吕布一样分不清是哪个爸爸。

更推荐使用props传值,需要就从父传过来不需要就不传。

export default {
    ···
    mounted(){//生命周期函数
        console.log(this.$parent);
    },
    ···
}



1.6 子访问根$root

更常用

export default {
    ···
    mounted(){//生命周期函数
        console.log(this.$root);
    },
    ···
}





2、插槽



2.1 基本使用

在移动端开发中用的较多。以导航栏举例:大多数移动应用导航栏都是左返回;中页面名称;右三点展开更多。

这时候就可以把左中右看成三个坑(插槽),由父组件来决定我需要填进什么萝卜。

Content.vue中通过Vue自定<slot>作为一个插入内容的占位符。

        <div>
            <slot></slot>
        </div>

在父组件中引用后使用它

    <Content><button>按钮</button></Content>
    <Content><input type="text"/></Content>

Content.vue中,如果父组件没有提供内容的时候默认展示备用内容

<slot name="button"><button>默认按钮</button></slot>



2.2 具名插槽

如果有多个值,同时放入组件进行替换式,一起作为替换元素。当子组件功能复杂,需要具体插槽具体对待。vue3和vue2区别

            <slot name="button"></slot>
            <slot name="input"></slot>
            <slot name="h2"></slot>

vue3做法

template元素上使用v-slot指令

<Content>
    <template v-slot:button><button>按钮</button></template>
    <template v-slot:input><input type="text"/></template>
    <template v-slot:h2><h2>插槽</h2></template>
</Content>

vue2做法

<button slot="button">按钮</button>



2.3 作用域插槽

App.vueContent.vue中data都存在massage的数据,这种方式将会显示App中的massage。

类似局部变量,父模板中所有内容都是在父级作用域中编制的,这个massage拿不到子的数据。

<template v-slot:button>
    <button>按钮{{ massage }}</button>
</template>

作用域于插槽是父组件替换插槽的标签,但是数据由子组件提供。vue3和vue2区别

vue3做法

Content.vue中绑定在slot上的属性值被成为插槽prop

export default {
    data() {
        return {
            message: '你好',
            list: [1, 2, 3, 5, 6],
        }
    }
}
<slot :list="list" :msg="message"></slot>

App.vue中使用带值的v-slot定义插槽名字,就会得到传过来的{ "list": [ 1, 2, 3, 5, 6 ], "msg": "你好" }的数据。

这里用过插槽prop的对象命名为slotProps,可以随便取

    <Content>
      <template v-slot:default="slotProps">
        {{ slotProps }}
      </template>
    </Content>

通过.list.msg拿到数据。(但实际上推荐Content.vue中:message="message",msg只是为了区分传过来的是等号前的自定义名字)

展示无序列表

    <Content>
      <template v-slot:default="slotProps">
        <ul>
          <li v-for="item in slotProps.list" :key="item">{{ item }}</li>
        </ul>
      </template>
    </Content>

展示有序列表

<ol>
    <li v-for="item in slotProps.list" :key="item">{{ item }}</li>
</ol>





3、组件跨级通信



3.1 Provide / Inject

祖先组件和孙子组件跨级通信,实际中一级级传递数据不现实。不论层次结构,父组件provide提供数据,子组件inject使用数据。

HelloWorld.vue祖先组件、Content.vue父组件、Hello.vue子组件。从Hello.vueHelloWorld.vue数据

HelloWorld.vue中provide以key-value的形式传字符串

export default{
  data(){
    return{
      massage:'HelloWorld'
    }
  },
  provide:{
    message:'HelloWorld'
  },
  ···
}

Hello.vue中inject

export default {
    data() {
        return {};
    },
    inject: ['message'] 
}
<h2>我是Hello组件</h2>
<h2>{{ message }}</h2>

其中需要注意HelloWorld.vue中,这种写法报错

  provide:{
    message:this.message
  },

如果想要访问组件实例的属性需要以函数的形式

  provide(){
    return{
      massage:this.massage
    }
  },



3.2 与prop区别

1、不会像prop父组件数据改变子组件也变,Provide / Inject不是响应式。在非组合式API下,传响应式对象or函数形式

传响应式对象

HelloWorld.vue

  data() {
    return {
      obj:{message: 'HelloWorld',}
    }
  },
  provide() {
    return {obj:this.obj}
  },

Hello.vue

export default {
    ···
    inject: ["obj"] 
}
<h2>{{ obj.message }}</h2>

函数形式

HelloWorld.vue

  data() {
    return {message: 'HelloWorld',}
  },
  provide() {
    return {//箭头函数返回响应式数据
      message: () => this.message
    }
  },

Hello.vue

export default {
    ···
    inject: ["message"] 
}
<h2>{{ message() }}</h2>

注:此处为了方便将函数直接写在{{}}中,这是不推荐的。应该使用computed属性

posted @   北溟有咸其名为鸽  阅读(61)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示