Vue插槽理解

时间:2022-11-28 00:58:31

Vue插槽理解

插槽

slot又名插槽,vue内容分发机制,组件内部的模板引擎使用slot元素作为承载分发内容的出口
插槽slot是子组件的一个模板标签元素,而这一个元素是否显示,以及怎么显示是由父组件决定的
slot分为三类:默认插槽、具名插槽、作用域插槽

  • 默认插槽

父组件代码详情


<template>
	<div class="parent">
		<h1>这里是parent组件</h1>
		<Child>
			<h3>这是parent组件传递给child组件的值</h3>
		</Child>
	</div>
</template>
<script>
import Child from "../component/Child.vue"
</script>

子组件代码详情

<template>
	<div class="child">
		<h1>这里是child组件</h1>
		<Child>
			<h3>这是child组件</h3>
			<slot></slot>
		</Child>
	</div>
</template>

运行结果:
Vue插槽理解

又叫匿名插槽,当插槽slot没有指定name属性值的时候一个默认显示一个插槽,一个组件内只有一个匿名插槽

  • 具名插槽

带有具体名字的插槽,也就是带有name属性的slot,一个组件可以出现多个具名插槽
父组件代码详情

<template>
	<div class="parent">
		<h1>这里是parent组件</h1>
		<Child>
			<div slot="header">给header内容</div>
			<div slot="main">给main内容</div>
			<div slot="footer">给footer内容</div>
		</Child>
	</div>
</template>

子组件代码详情

<template>
	<div class="child">
		<h1>这里是parent组件</h1>
		<Child>
			<div name="header">给header内容</div>
			<div name="main">给main内容</div>
			<div name="footer">给footer内容</div>
		</Child>
	</div>
</template>

运行结果:
Vue插槽理解

  • 作用域插槽

在子组件渲染作用域插槽时,可以将子组件内部的数据传递给父组件,让父组件根据子组件传递过来的数据如何渲染该插槽
父组件代码详情

<template>
  <button @click="show">显示隐藏</button>
  <div class="home" v-show="isShow">
    <Dialog title="商品选择">
      <!-- 匿名插槽的使用 -->
      <!-- 写法一 -->
      <!-- 12243 -->

      <!-- 写法二 -->
      <template #default>
        <!-- 666666666666666666 -->
        <FruitList>
          <template #default="{goods}">{{ goods }}</template>
        </FruitList>
      </template>


      <!-- 具名插槽使用 -->
      <!-- 写法一 -->
      <!-- <template v-slot:footer>
        <Rbutton>取消</Rbutton>
        <Rbutton>确认</Rbutton>
      </template> -->

      <!-- 写法二 -->
      <template #footer>
        <Rbutton style=" display: inline-block;border-radius: 5px;margin-right: 10px;">取消</Rbutton>
        <Rbutton style="background-color: #1890ff; display: inline-block; border-radius: 5px;">确认</Rbutton>
      </template>
    </Dialog>
  </div>
</template>

<script>
import Dialog from '@/components/Dialog.vue'
import Rbutton from '@/components/Rbutton.vue';
import FruitList from '@/components/FruitList.vue';
export default {
  data(){
    return{
      isShow:false
    }
  },
  name: 'DialogParent',
  components: {
    Dialog,
    Rbutton,
    FruitList
  },
  methods:{
    onAddCart(gid,gname){
      console.log(gid,gname);
    },
    show(){
      this.isShow=!this.isShow
    }
  }
  
}
</script>
<style lang="scss" scoped>
.home{
  // position: relative;
  background-color: yellow;
}
</style>

子组件代码详情

<template>
    <div class="fruit">
        <table class="ftable">
            <thead>
                <tr>
                    <td>ID</td>
                    <td>名字</td>
                    <td>价格</td>
                </tr>
            </thead>
            <tbody>
                <tr v-for="f in fruits" :key="f.id" @click="onAddCart([f.id,f.name])">
                    <td>{{ f.id }}</td>
                    <td>{{ f.name }}</td>
                    <td>{{ f.price }}</td>
                </tr>
                <slot :goods="f"></slot>
            </tbody>
        </table>
    </div>
</template>

<script>
export default {
    data(){
        return{
            fruits:[
                {
                    id:'01',
                    name:'苹果~~????',
                    price:'3.90'
                },
                {
                    id:'01',
                    name:'西瓜~~????',
                    price:'3.70'
                },
                {
                    id:'01',
                    name:'葡萄~~????',
                    price:'3.80'
                },                
                {
                    id:'01',
                    name:'橙子~~????',
                    price:'3.50'
                },                
                {
                    id:'01',
                    name:'香蕉~~????',
                    price:'3.30'
                },
            ]
        }
    },
    methods:{
        onAddCart(params){
            this.$emit('add-cart',...params)
        }
    }
}
</script>

<style lang="scss" scoped>
.fruit{
    // li{
    //     list-style: none;
    // }
    width: 100%;
    // height: 100%;
    // background-color: plum;
    table{
        width: 95%;
        // border-radius: 20px;
        margin: 0 auto;
        border: 1px bolid black;
        thead{
            width: 100%;
            // border-radius: 20px;
            // background-color: blue;
            text-align: center;
        }
        tbody{
            // border-radius: 20px;
            width: 100%;
            background-color: aliceblue;
            text-align: center;
        }
    }
}
</style>

**原理:**当子组件vm实例化时,获取到父组件传入的slot标签的内容,存放在vm. s l o t 中,默认插槽为 v m . slot中,默认插槽为vm. slot中,默认插槽为vm.slot.default,具名插槽为vm. s l o t . x x x , x x x 是插槽的名字,当组件执行渲染函数时候,遇到 s l o t 标签,使用 slot.xxx,xxx是插槽的名字,当组件执行渲染函数时候,遇到slot标签,使用 slot.xxx,xxx是插槽的名字,当组件执行渲染函数时候,遇到slot标签,使用slot中的内容进行替换,此时可以为插槽传递数据,若存在数据,则就是作用域插槽