• 技术文章 >web前端 >前端问答

    vue插槽解决什么问题

    青灯夜游青灯夜游2023-01-14 10:45:16原创123

    vue插槽解决的问题:引入的子组件标签中间不允许写内容的。插槽(Slot)是vue为组件的封装者提供的能力;允许开发者在封装组件时,把不确定的、希望由用户指定的部分定义为插槽;可以把插槽认为是组件封装期间,为用户预留的内容的占位符。

    本教程操作环境:windows7系统、vue3版,DELL G3电脑。

    什么是插槽?

    我们知道,在vue中,引入的子组件标签中间是不允许写内容的。为了解决这个问题,官方引入了插槽(slot)的概念。

    插槽,其实就相当于占位符。它在组件中给你的HTML模板占了一个位置,让你来传入一些东西。插槽又分为匿名插槽具名插槽以及作用域插槽

    你可能不太明白,为什么我要给子组件中传入HTML,而不直接写在子组件中呢?答案是这样的。你可以想象一个场景,你有五个页面,这五个页面中只有一个区域的内容不一样,你会怎么去写这五个页面呢?复制粘贴是一种办法,但在vue中,插槽(slot)是更好的做法。

    1.png

    匿名插槽


    匿名插槽,我们又可以叫它单个插槽或者默认插槽。与具名插槽相对,它不需要设置name属性。(它隐藏的name属性为default。)

    例子:

    文件目录如下,Home组件是HelloWorld的父组件。

    2.png

    <template>
      <div class="hello">
         Helloworld组件
    
         <div class = 'slotTxt'>
           <slot></slot>
         </div>
    
      </div>
    </template>
    
    <script>
    export default {
    
    }
    </script>
    
    <!-- Add "scoped" attribute to limit CSS to this component only -->
    <style scoped lang="less">
    .hello{
      width:100%;
      height:300px;
      background:#ccc;
      margin-top:50px;
      .slotTxt{
        width:500px;
        height:200px;
        margin:30px auto;
        background:red;
      }
    }
    </style>
    <template>
      <div class="home">
        我是Home父组件
        <HelloWorld>
          <!-- 没有插槽,这里的内容不显示 -->
          <h1>我是helloworld中的插槽啊</h1>  
        </HelloWorld>
      </div>
    </template>
    
    <script>
    import HelloWorld from '@/components/HelloWorld.vue'
    export default {
      name: 'home',
      components: {
        HelloWorld
      }
    }
    </script>

    效果

    3.png

    不难看出,HelloWorld标签中的内容(红色部分)已经显示出来了。

    具名插槽


    上面已经说过,插槽有一个name属性。与匿名插槽相对,加了name属性的匿名插槽就是具名插槽。

    <template>
      <div class="hello">
         Helloworld组件
    
         <div class = 'slotLeft'>
           <slot name='left'></slot>
         </div>
    
         <div class = 'slotRight'>
           <slot name='right'></slot>
         </div>
    
      </div>
    </template>
    
    <script>
    export default {
    
    }
    </script>
    
    <!-- Add "scoped" attribute to limit CSS to this component only -->
    <style scoped lang="less">
    .hello{
      width:700px;
      height:300px;
      background:#ccc;
      margin: 0 auto;
      margin-top:50px;
      .slotLeft{
        width:300px;
        height:200px;
        float:left;
        background:red;
      }
      .slotRight{
        width:300px;
        height:200px;
        float:right;
        background:pink;
      }
    }
    </style>
    <template>
      <div class="home">
        我是Home父组件
        <HelloWorld>
          <template v-slot:left>
             <h1>name属性为left</h1> 
          </template>
          <template v-slot:right>
             <h1>name属性为right</h1> 
          </template>
         
        </HelloWorld>
      </div>
    </template>
    
    <script>
    import HelloWorld from '@/components/HelloWorld.vue'
    export default {
      name: 'home',
      components: {
        HelloWorld
      }
    }
    </script>
    <style lang="less" scoped>
    .home{
      width:900px;
      margin:0 auto;
      background:yellow;
      padding-bottom:100px;
    }
    </style>

    注意 v-slot 只能添加在template标签上 (只有一种例外情况)。

    4.png

    <template>
      <div class="home">
        我是Home父组件
        <HelloWorld>
          <h1 slot='left'>name属性为left</h1>  
          <h1 slot='right'>name属性为right</h1>  
        </HelloWorld>
      </div>
    </template>
    
    <script>
    import HelloWorld from '@/components/HelloWorld.vue'
    export default {
      name: 'home',
      components: {
        HelloWorld
      }
    }
    </script>
    <style lang="less" scoped>
    .home{
      width:900px;
      margin:0 auto;
      background:yellow;
      padding-bottom:100px;
    }
    </style>

    效果同上。

    作用域插槽


    作用域插槽其实就是可以传递数据的插槽。子组件中的一些数据想在父组件中使用,必须通过规定的方法来传递。在官方文档中提出了一条规则,**父级模板里的所有内容都是在父级作用域中编译的。子模板里的所有内容都是在子作用域中编译的。**如果你在父组件直接使用子组件中的值,是会报错的。

    匿名插槽的作用域插槽

    为了让 子组件中的数据 在父级的插槽内容中可用,我们可以将 数据 作为 元素的一个特性绑定上去:

    语法:v-bind:users="user"
    <template>
      <div class="hello">
         Helloworld组件  
         <div class='slotLeft'>
           <slot v-bind:users="user"></slot>
         </div> 
         
      </div>
    </template>
    
    <script>
    export default {
      data(){
        return{
          user:{
            name:'oralinge',
            age:18
          }
        }  
      }
    }
    </script>
    
    <!-- Add "scoped" attribute to limit CSS to this component only -->
    <style scoped lang="less">
    .hello{
      width:700px;
      height:300px;
      background:#ccc;
      margin: 0 auto;
      margin-top:50px;
      .slotLeft{
        width:300px;
        height:200px;
        // float:left;
        background:red;
        margin:20px auto
      }
      .slotRight{
        width:300px;
        height:200px;
        float:right;
        background:pink;
      }
    }
    </style>

    绑定在 元素上的特性(v-bind:users=“user”)被称为插槽 prop。现在在父级作用域中,我们可以使用带值的 v-slot 来定义我们提供的插槽 prop 的名字。

    语法:v-slot:default="随意取的名字"  // default可省略,简写为v-slot="随意取的名字"
    <template>
      <div class="home">
        我是Home父组件
        <HelloWorld>
          <template  v-slot:default="slotProps">
             <h1>{{slotProps.users.name}}</h1> 
          </template>
        </HelloWorld>
      </div>
    </template>
    
    <script>
    import HelloWorld from '@/components/HelloWorld.vue'
    export default {
      name: 'home',
      components: {
        HelloWorld
      }
    }
    </script>
    <style lang="less" scoped>
    .home{
      width:900px;
      margin:0 auto;
      background:yellow;
      padding-bottom:100px;
    }
    </style>

    注意:
    父组件中的slotProps可以是随意取的。
    子组件中users是随意取的,与之对应的是父组件中的users。
    子组件中的user为数据。

    效果

    5.png

    具名插槽的作用域插槽

    与匿名插槽同理,只需要把default替换成插槽的name值即可。

    <template>
      <div class="hello">
         Helloworld组件  
         <div class='slotLeft'>
           <slot name='helloWorld' v-bind:users="user"></slot>
         </div> 
         
      </div>
    </template>
    
    <script>
    export default {
      data(){
        return{
          user:{
            name:'hello world',
            age:18
          }
        }  
      }
    }
    </script>
    
    <!-- Add "scoped" attribute to limit CSS to this component only -->
    <style scoped lang="less">
    .hello{
      width:700px;
      height:300px;
      background:#ccc;
      margin: 0 auto;
      margin-top:50px;
      .slotLeft{
        width:300px;
        height:200px;
        // float:left;
        background:red;
        margin:20px auto
      }
      .slotRight{
        width:300px;
        height:200px;
        float:right;
        background:pink;
      }
    }
    </style>
    <template>
      <div class="home">
        我是Home父组件
        <HelloWorld>
          <template  v-slot:helloWorld="slotProps">
             <h1>{{slotProps.users.name}}</h1> 
          </template>
        </HelloWorld>
      </div>
    </template>
    
    <script>
    import HelloWorld from '@/components/HelloWorld.vue'
    export default {
      name: 'home',
      components: {
        HelloWorld
      }
    }
    </script>
    <style lang="less" scoped>
    .home{
      width:900px;
      margin:0 auto;
      background:yellow;
      padding-bottom:100px;
    }
    </style>

    效果

    6.png

    注意:
    默认插槽的缩写语法不能和具名插槽混用,因为它会导致作用域不明确。

    7.png

    另,slot-scope写法在2.6之后已废弃,作用与上面相同,在此不做解释。

    上面的写法是不是觉得有些麻烦?别着急,我们来看一看解构插槽 Prop

    解构插槽 Prop

    作用域插槽的内部工作原理是将你的插槽内容包括在一个传入单个参数的函数里:

    function (slotProps) {
      // 插槽内容
    }

    这意味着 v-slot 的值实际上可以是任何能够作为函数定义中的参数的 JavaScript 表达式。所以在支持的环境下 (单文件组件或现代浏览器),你也可以使用 ES2015 解构来传入具体的插槽 prop。

    语法:v-slot="{ users }"
    <template>
      <div class="hello">
         Helloworld组件  
         <div class='slotLeft'>
           <slot v-bind:users="user"></slot>
         </div> 
         
      </div>
    </template>
    
    <script>
    export default {
      data(){
        return{
          user:{
            name:'hello world',
            age:18
          }
        }  
      }
    }
    </script>
    
    <!-- Add "scoped" attribute to limit CSS to this component only -->
    <style scoped lang="less">
    .hello{
      width:700px;
      height:300px;
      background:#ccc;
      margin: 0 auto;
      margin-top:50px;
      .slotLeft{
        width:300px;
        height:200px;
        // float:left;
        background:red;
        margin:20px auto
      }
      .slotRight{
        width:300px;
        height:200px;
        float:right;
        background:pink;
      }
    }
    </style>
    <template>
      <div class="home">
        我是Home父组件
        <HelloWorld>
          <template  v-slot="{ users }">
             <h1>{{users.name}}</h1> 
          </template>
        </HelloWorld>
      </div>
    </template>
    
    <script>
    import HelloWorld from '@/components/HelloWorld.vue'
    export default {
      name: 'home',
      components: {
        HelloWorld
      }
    }
    </script>
    <style lang="less" scoped>
    .home{
      width:900px;
      margin:0 auto;
      background:yellow;
      padding-bottom:100px;
    }
    </style>

    8.png

    <template>
      <div class="home">
        我是Home父组件
        <HelloWorld>
          <template  v-slot="{ users:person }">
             <h1>{{person.name}}</h1> 
          </template>
        </HelloWorld>
      </div>
    </template>
    
    <script>
    import HelloWorld from '@/components/HelloWorld.vue'
    export default {
      name: 'home',
      components: {
        HelloWorld
      }
    }
    </script>
    <style lang="less" scoped>
    .home{
      width:900px;
      margin:0 auto;
      background:yellow;
      padding-bottom:100px;
    }
    </style>

    效果如上图。

    <template>
      <div class="home">
        我是Home父组件
        <HelloWorld>
          <template >
             <h1 v-slot="{ users = { name: '1111' } }">{{users.name}}</h1> 
          </template>
        </HelloWorld>
      </div>
    </template>
    
    <script>
    import HelloWorld from '@/components/HelloWorld.vue'
    export default {
      name: 'home',
      components: {
        HelloWorld
      }
    }
    </script>
    <style lang="less" scoped>
    .home{
      width:900px;
      margin:0 auto;
      background:yellow;
      padding-bottom:100px;
    }
    </style>

    使用场景


    <template>
      <div>
        <div class="title-box">
          <span class="title">{{title}}</span>
          <div class="right">
            <slot name="right"></slot>
          </div>
        </div>
        <div class="content-box">
          <slot></slot>
        </div>
      </div>
    </template>
    <script>
    export default {
      data () {
        return {
        }
      },
      props: {
        title: {
          type: String,
          required: true
        }
      }
    }
    </script>
    <style lang="scss" scoped>
    .title-box {
      padding: 16px 0;
      border-bottom: 1px solid #eff1f5;
      .title {
        font-family: MicrosoftYaHei;
        font-size: 24px;
        color: #283039;
        letter-spacing: 0;
        line-height: 24px;
        &::before {
          width: 4px;
          margin-right: 20px;
          content: "";
          background-color: #5da1ff;
          display: inline-block;
          height: 20px;
          vertical-align: middle;
        }
      }
      .right {
        float: right;
        margin-right: 20px;
      }
    }
    </style>

    使用的ui框架为ivew。

    相关推荐:vue.js视频教程

    以上就是vue插槽解决什么问题的详细内容,更多请关注php中文网其它相关文章!

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    专题推荐:Vue 插槽
    上一篇:vue3改了几个生命周期函数 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • .vue格式文件用什么软件打开• vue的内置指令有哪些构成• 图文详解Vue3实现全局搜索框步骤(附代码)• 在命令行执行命令什么表示初始化vue项目• vue3改了几个生命周期函数
    1/1

    PHP中文网