Vue2基础八、插槽

这篇具有很好参考价值的文章主要介绍了Vue2基础八、插槽。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

零、文章目录

Vue2基础八、插槽

1、插槽

(1)默认插槽
  • 作用:让组件内部的一些 结构 支持 自定义
  • 需求: 将需要多次显示的对话框, 封装成一个组件
  • 问题:组件的内容部分,不希望写死,希望能使用的时候自定义。怎么办?

Vue2基础八、插槽,大前端,javascript,前端,css

  • 插槽基本语法:
    • 组件内需要定制的结构部分,改用<slot></slot>占位
    • 使用组件时, <MyDialog></MyDialog>标签内部, 传入结构替换slot

Vue2基础八、插槽,大前端,javascript,前端,css

  • 代码实现

    • 父组件App.vue
    <template>
      <div>
        <!-- 2. 在使用组件时,组件标签内填入内容 -->
        <MyDialog>
          <div>你确认要删除么</div>
        </MyDialog>
    
        <MyDialog>
          <p>你确认要退出么</p>
        </MyDialog>
      </div>
    </template>
    
    <script>
    import MyDialog from './components/MyDialog.vue'
    export default {
      data () {
        return {
    
        }
      },
      components: {
        MyDialog
      }
    }
    </script>
    
    <style>
    body {
      background-color: #b3b3b3;
    }
    </style>
    
    • 子组件MyDialog.vue
    <template>
      <div class="dialog">
        <div class="dialog-header">
          <h3>友情提示</h3>
          <span class="close">✖️</span>
        </div>
    
        <div class="dialog-content">
          <!-- 1. 在需要定制的位置,使用slot占位 -->
          <slot></slot>
        </div>
        <div class="dialog-footer">
          <button>取消</button>
          <button>确认</button>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      data () {
        return {
    
        }
      }
    }
    </script>
    
    <style scoped>
    * {
      margin: 0;
      padding: 0;
    }
    .dialog {
      width: 470px;
      height: 230px;
      padding: 0 25px;
      background-color: #ffffff;
      margin: 40px auto;
      border-radius: 5px;
    }
    .dialog-header {
      height: 70px;
      line-height: 70px;
      font-size: 20px;
      border-bottom: 1px solid #ccc;
      position: relative;
    }
    .dialog-header .close {
      position: absolute;
      right: 0px;
      top: 0px;
      cursor: pointer;
    }
    .dialog-content {
      height: 80px;
      font-size: 18px;
      padding: 15px 0;
    }
    .dialog-footer {
      display: flex;
      justify-content: flex-end;
    }
    .dialog-footer button {
      width: 65px;
      height: 35px;
      background-color: #ffffff;
      border: 1px solid #e1e3e9;
      cursor: pointer;
      outline: none;
      margin-left: 10px;
      border-radius: 3px;
    }
    .dialog-footer button:last-child {
      background-color: #007acc;
      color: #fff;
    }
    </style>
    
(2)后备内容(默认值)
  • 通过插槽完成了内容的定制,传什么显示什么, 但是如果不传,则是空白
  • 能否给插槽设置 默认显示内容 呢?

Vue2基础八、插槽,大前端,javascript,前端,css

  • 插槽后备内容:封装组件时,可以为预留的 <slot> 插槽提供后备内容(默认内容)。

  • 语法: 在 <slot> 标签内,放置内容作为默认内容,<slot>后备内容</slot>

    • 外部使用组件时,不传东西,则slot会显示后备内容

      <MyDialog></MyDialog>
      
    • 外部使用组件时,传东西了,则slot整体会被换掉

    <MyDialog>我是内容</MyDialog>
    
  • 代码实现

    • 父组件App.vue
    <template>
      <div>
        <MyDialog></MyDialog>
    
        <MyDialog>
          你确认要退出么
        </MyDialog>
      </div>
    </template>
    
    <script>
    import MyDialog from './components/MyDialog.vue'
    export default {
      data () {
        return {
    
        }
      },
      components: {
        MyDialog
      }
    }
    </script>
    
    <style>
    body {
      background-color: #b3b3b3;
    }
    </style>
    
    • 子组件MyDialog.vue
    <template>
      <div class="dialog">
        <div class="dialog-header">
          <h3>友情提示</h3>
          <span class="close">✖️</span>
        </div>
    
        <div class="dialog-content">
          <!-- 往slot标签内部,编写内容,可以作为后备内容(默认值) -->
          <slot>
            我是默认的文本内容
          </slot>
        </div>
        <div class="dialog-footer">
          <button>取消</button>
          <button>确认</button>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      data () {
        return {
    
        }
      }
    }
    </script>
    
    <style scoped>
    * {
      margin: 0;
      padding: 0;
    }
    .dialog {
      width: 470px;
      height: 230px;
      padding: 0 25px;
      background-color: #ffffff;
      margin: 40px auto;
      border-radius: 5px;
    }
    .dialog-header {
      height: 70px;
      line-height: 70px;
      font-size: 20px;
      border-bottom: 1px solid #ccc;
      position: relative;
    }
    .dialog-header .close {
      position: absolute;
      right: 0px;
      top: 0px;
      cursor: pointer;
    }
    .dialog-content {
      height: 80px;
      font-size: 18px;
      padding: 15px 0;
    }
    .dialog-footer {
      display: flex;
      justify-content: flex-end;
    }
    .dialog-footer button {
      width: 65px;
      height: 35px;
      background-color: #ffffff;
      border: 1px solid #e1e3e9;
      cursor: pointer;
      outline: none;
      margin-left: 10px;
      border-radius: 3px;
    }
    .dialog-footer button:last-child {
      background-color: #007acc;
      color: #fff;
    }
    </style>
    
(3)具名插槽
  • 需求:一个组件内有多处结构,需要外部传入标签,进行定制
  • 默认插槽:一个的定制位置

Vue2基础八、插槽,大前端,javascript,前端,css

  • 具名插槽语法:
    • 多个slot使用name属性区分名字
    • template配合v-slot:名字来分发对应标签
    • v-slot:插槽名 可以简化成 #插槽名

Vue2基础八、插槽,大前端,javascript,前端,css

  • 代码实现:

    • 父组件App.vue
    <template>
      <div>
        <MyDialog>
          <!-- 需要通过template标签包裹需要分发的结构,包成一个整体 -->
          <template v-slot:head>
            <div>我是大标题</div>
          </template>
          
          <template v-slot:content>
            <div>我是内容</div>
          </template>
    
          <template #footer>
            <button>取消</button>
            <button>确认</button>
          </template>
        </MyDialog>
      </div>
    </template>
    
    <script>
    import MyDialog from './components/MyDialog.vue'
    export default {
      data () {
        return {
    
        }
      },
      components: {
        MyDialog
      }
    }
    </script>
    
    <style>
    body {
      background-color: #b3b3b3;
    }
    </style>
    
    • 子组件MyDialog.vue
    <template>
      <div class="dialog">
        <div class="dialog-header">
          <!-- 一旦插槽起了名字,就是具名插槽,只支持定向分发 -->
          <slot name="head"></slot>
        </div>
    
        <div class="dialog-content">
          <slot name="content"></slot>
        </div>
        <div class="dialog-footer">
          <slot name="footer"></slot>
        </div>
      </div>
    </template>
    
    <script>
    export default {
      data () {
        return {
    
        }
      }
    }
    </script>
    
    <style scoped>
    * {
      margin: 0;
      padding: 0;
    }
    .dialog {
      width: 470px;
      height: 230px;
      padding: 0 25px;
      background-color: #ffffff;
      margin: 40px auto;
      border-radius: 5px;
    }
    .dialog-header {
      height: 70px;
      line-height: 70px;
      font-size: 20px;
      border-bottom: 1px solid #ccc;
      position: relative;
    }
    .dialog-header .close {
      position: absolute;
      right: 0px;
      top: 0px;
      cursor: pointer;
    }
    .dialog-content {
      height: 80px;
      font-size: 18px;
      padding: 15px 0;
    }
    .dialog-footer {
      display: flex;
      justify-content: flex-end;
    }
    .dialog-footer button {
      width: 65px;
      height: 35px;
      background-color: #ffffff;
      border: 1px solid #e1e3e9;
      cursor: pointer;
      outline: none;
      margin-left: 10px;
      border-radius: 3px;
    }
    .dialog-footer button:last-child {
      background-color: #007acc;
      color: #fff;
    }
    </style>
    
(4)作用域插槽
  • 作用域插槽: 定义 slot 插槽的同时, 是可以传值的。给 插槽 上可以 绑定数据,将来 使用组件时可以用

  • 场景:封装表格组件

    • 父传子,动态渲染表格内容
    • 利用默认插槽,定制操作列
    • 删除或查看都需要用到 当前项的 id,属于 组件内部的数据通过 作用域插槽 传值绑定,进而使用

    Vue2基础八、插槽,大前端,javascript,前端,css

  • 基本使用步骤:

    • 给 slot 标签, 以 添加属性的方式传值
    <slot :id="item.id" msg="测试文本"></slot>
    
    • 所有添加的属性, 都会被收集到一个对象中
    { id: 3, msg: '测试文本' }
    
    • 在template中, 通过 #插槽名= "obj" 接收,默认插槽名为 default
    <MyTable :list="list">
    	<template #default="obj">
    		<button @click="del(obj.id)">删除</button>
    	</template>
    </MyTable>
    
  • 代码实现

    • 父组件App.vue
    <template>
      <div>
        <MyTable :data="list">
          <!-- 3. 通过template #插槽名="变量名" 接收 -->
          <template #default="obj">
            <button @click="del(obj.row.id)">
              删除
            </button>
          </template>
        </MyTable>
        
        <MyTable :data="list2">
          <template #default="{ row }">
            <button @click="show(row)">查看</button>
          </template>
        </MyTable>
      </div>
    </template>
    
    <script>
    import MyTable from './components/MyTable.vue'
    export default {
      data () {
        return {
          list: [
            { id: 1, name: '张小花', age: 18 },
            { id: 2, name: '孙大明', age: 19 },
            { id: 3, name: '刘德忠', age: 17 },
          ],
          list2: [
            { id: 1, name: '赵小云', age: 18 },
            { id: 2, name: '刘蓓蓓', age: 19 },
            { id: 3, name: '姜肖泰', age: 17 },
          ]
        }
      },
      methods: {
        del (id) {
          this.list = this.list.filter(item => item.id !== id)
        },
        show (row) {
          // console.log(row);
          alert(`姓名:${row.name}; 年纪:${row.age}`)
        }
      },
      components: {
        MyTable
      }
    }
    </script>
    
    • 子组件MyTable.vue
    <template>
      <table class="my-table">
        <thead>
          <tr>
            <th>序号</th>
            <th>姓名</th>
            <th>年纪</th>
            <th>操作</th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="(item, index) in data" :key="item.id">
            <td>{{ index + 1 }}</td>
            <td>{{ item.name }}</td>
            <td>{{ item.age }}</td>
            <td>
              <!-- 1. 给slot标签,添加属性的方式传值 -->
              <slot :row="item" msg="测试文本"></slot>
    
              <!-- 2. 将所有的属性,添加到一个对象中 -->
              <!-- 
                 {
                   row: { id: 2, name: '孙大明', age: 19 },
                   msg: '测试文本'
                 }
               -->
            </td>
          </tr>
        </tbody>
      </table>
    </template>
    
    <script>
    export default {
      props: {
        data: Array
      }
    }
    </script>
    
    <style scoped>
    .my-table {
      width: 450px;
      text-align: center;
      border: 1px solid #ccc;
      font-size: 24px;
      margin: 30px auto;
    }
    .my-table thead {
      background-color: #1f74ff;
      color: #fff;
    }
    .my-table thead th {
      font-weight: normal;
    }
    .my-table thead tr {
      line-height: 40px;
    }
    .my-table th,
    .my-table td {
      border-bottom: 1px solid #ccc;
      border-right: 1px solid #ccc;
    }
    .my-table td:last-child {
      border-right: none;
    }
    .my-table tr:last-child td {
      border-bottom: none;
    }
    .my-table button {
      width: 65px;
      height: 35px;
      font-size: 18px;
      border: 1px solid #ccc;
      outline: none;
      border-radius: 3px;
      cursor: pointer;
      background-color: #ffffff;
      margin-left: 5px;
    }
    </style>
    

2、综合案例-商品列表

(1)功能需求
  • my-tag 标签组件封装
    • (1) 双击显示输入框,输入框获取焦点
    • (2) 失去焦点,隐藏输入框
    • (3) 回显标签信息
    • (4) 内容修改,回车 → 修改标签信息
  • my-table 表格组件封装
    • (1) 动态传递表格数据渲染
    • (2) 表头支持用户自定义
    • (3) 主体支持用户自定义

Vue2基础八、插槽,大前端,javascript,前端,css文章来源地址https://www.toymoban.com/news/detail-613789.html

(2)代码实现
  • 父组件App.vue
<template>
  <div class="table-case">
    <MyTable :data="goods">
      <template #head>
        <th>编号</th>
        <th>名称</th>
        <th>图片</th>
        <th width="100px">标签</th>
      </template>

      <template #body="{ item, index }">
        <td>{{ index + 1 }}</td>
        <td>{{ item.name }}</td>
        <td>
          <img
            :src="item.picture"
          />
        </td>
        <td>
          <MyTag v-model="item.tag"></MyTag>
        </td>
      </template>
    </MyTable>
  </div>
</template>

<script>
// my-tag 标签组件的封装
// 1. 创建组件 - 初始化
// 2. 实现功能
//    (1) 双击显示,并且自动聚焦
//        v-if v-else @dbclick 操作 isEdit
//        自动聚焦:
//        1. $nextTick => $refs 获取到dom,进行focus获取焦点
//        2. 封装v-focus指令

//    (2) 失去焦点,隐藏输入框
//        @blur 操作 isEdit 即可

//    (3) 回显标签信息
//        回显的标签信息是父组件传递过来的
//        v-model实现功能 (简化代码)  v-model => :value 和 @input
//        组件内部通过props接收, :value设置给输入框

//    (4) 内容修改了,回车 => 修改标签信息
//        @keyup.enter, 触发事件 $emit('input', e.target.value)

// ---------------------------------------------------------------------

// my-table 表格组件的封装
// 1. 数据不能写死,动态传递表格渲染的数据  props
// 2. 结构不能写死 - 多处结构自定义 【具名插槽】
//    (1) 表头支持自定义
//    (2) 主体支持自定义

import MyTag from './components/MyTag.vue'
import MyTable from './components/MyTable.vue'
export default {
  name: 'TableCase',
  components: {
    MyTag,
    MyTable
  },
  data () {
    return {
      // 测试组件功能的临时数据
      tempText: '水杯',
      tempText2: '钢笔',
      goods: [
        { id: 101, picture: './assets/img/news.png', name: '梨皮朱泥三绝清代小品壶经典款紫砂壶', tag: '茶具' },
        { id: 102, picture: './assets/img/news.png', name: '全防水HABU旋钮牛皮户外徒步鞋山宁泰抗菌', tag: '男鞋' },
        { id: 103, picture: './assets/img/news.png', name: '毛茸茸小熊出没,儿童羊羔绒背心73-90cm', tag: '儿童服饰' },
        { id: 104, picture: './assets/img/news.png', name: '基础百搭,儿童套头针织毛衣1-9岁', tag: '儿童服饰' },
      ]
    }
  }
}
</script>

<style lang="less" scoped>
.table-case {
  width: 1000px;
  margin: 50px auto;
  img {
    width: 100px;
    height: 100px;
    object-fit: contain;
    vertical-align: middle;
  }
}

</style>
  • 子组件MyTable.vue
<template>
  <table class="my-table">
    <thead>
      <tr>
        <slot name="head"></slot>
      </tr>
    </thead>
    <tbody>
      <tr v-for="(item, index) in data" :key="item.id">
        <slot name="body" :item="item" :index="index" ></slot>
      </tr>
    </tbody>
  </table>
</template>

<script>
export default {
  props: {
    data: {
      type: Array,
      required: true
    }
  }
};
</script>

<style lang="less" scoped>
.my-table {
  width: 100%;
  border-spacing: 0;
  img {
    width: 100px;
    height: 100px;
    object-fit: contain;
    vertical-align: middle;
  }
  th {
    background: #f5f5f5;
    border-bottom: 2px solid #069;
  }
  td {
    border-bottom: 1px dashed #ccc;
  }
  td,
  th {
    text-align: center;
    padding: 10px;
    transition: all .5s;
    &.red {
      color: red;
    }
  }
  .none {
    height: 100px;
    line-height: 100px;
    color: #999;
  }
}
</style>
  • 子组件MyTag.vue
<template>
  <div class="my-tag">
    <input
      v-if="isEdit"
      v-focus
      ref="inp"
      class="input"
      type="text"
      placeholder="输入标签"
      :value="value"
      @blur="isEdit = false"
      @keyup.enter="handleEnter"
    />
    <div 
      v-else
      @dblclick="handleClick"
      class="text">
      {{ value }}
    </div>
  </div>
</template>

<script>
export default {
  props: {
    value: String
  },
  data () {
    return {
      isEdit: false
    }
  },
  methods: {
    handleClick () {
      // 双击后,切换到显示状态 (Vue是异步dom更新)
      this.isEdit = true
      
      // // 等dom更新完了,再获取焦点
      // this.$nextTick(() => {
      //   // 立刻获取焦点
      //   this.$refs.inp.focus()
      // })
    },
    handleEnter (e) {
      // 非空处理
      if (e.target.value.trim() === '') return alert('标签内容不能为空')

      // 子传父,将回车时,[输入框的内容] 提交给父组件更新
      // 由于父组件是v-model,触发事件,需要触发 input 事件
      this.$emit('input', e.target.value)
      // 提交完成,关闭输入状态
      this.isEdit = false
    }
  }
}
</script>

<style lang="less" scoped>
.my-tag {
  cursor: pointer;
  .input {
    appearance: none;
    outline: none;
    border: 1px solid #ccc;
    width: 100px;
    height: 40px;
    box-sizing: border-box;
    padding: 10px;
    color: #666;
    &::placeholder {
      color: #666;
    }
  }
}
</style>
  • 入口main.js注册自定义指令
import Vue from 'vue'
import App from './App.vue'

Vue.config.productionTip = false

// 封装全局指令 focus
Vue.directive('focus', {
  // 指令所在的dom元素,被插入到页面中时触发
  inserted (el) {
    el.focus()
  }
})

new Vue({
  render: h => h(App),
}).$mount('#app')

到了这里,关于Vue2基础八、插槽的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Vue2向Vue3过度核心技术插槽

    1.作用 让组件内部的一些 结构 支持 自定义 2.需求 将需要多次显示的对话框,封装成一个组件 3.问题 组件的内容部分, 不希望写死 ,希望能使用的时候 自定义 。怎么办 4.插槽的基本语法 组件内需要定制的结构部分,改用****占位 使用组件时, ****标签内部, 传入结构替换slo

    2024年02月11日
    浏览(39)
  • 前端随笔:HTML/CSS/JavaScript和Vue

    最近因为工作需要,需要接触一些前端的东西。之前虽然大体上了解过 HTML 、 CSS 和 JavaScript ,也知道 HTML 定义了内容、 CSS 定义了样式、 JavaScript 定义了行为,但是却没有详细的学习过前端三件套的细节。而最近的工作中需要使用 Vue ,并且想到未来的工作中使用 Vue 能够更

    2024年02月16日
    浏览(41)
  • 前端技术Html,Css,JavaScript,Vue3

    1.基本标签 2.文本格式化 3.链接 4.图片 5.无序列表 6.有序列表 7.表格 8.表单 1.选择器 2.文本和字体 3.链接 4.隐藏 5.定位position 6.浮动 7.对齐 8.图像 1.输出 2.函数 3.常用事件 4.DOM 5.改变Html 6.DOM 元素 (节点) 尾部创建新的 HTML 元素 (节点) - appendChild() 头部创建新的 HTML 元素 (节点)

    2024年02月13日
    浏览(50)
  • 前端学习--vue2--2--vue指令基础

    写在前面: 前置内容 - vue配置 vue指令只的是带有v-前缀的特殊标签属性 插值表达式{{}}是一种vue模板语法。 利用表达式进行差值,渲染到页面。 表达式可以是被求值的代码,js会计算 不能用差值表达式的 不存在的数据 {{data里面不存在的字段 js {{if}} 标签属性 span id=“

    2024年02月14日
    浏览(38)
  • vue(32) : win10创建vue2基础前端框架

    vue2 element-ui axios 含接口调用示例 开发工具为HBuilderX 3.7.3 等待创建项目 代理后端配置如下, 三个test改成相同的uri前缀即可, uri该签注会代理到后端 proxy: {       // 代理test开头的uri       \\\'/test\\\': {         target: \\\'http://192.168.1.1:8080\\\', // 后端地址         changeOrigin: true, // 开启代

    2024年02月06日
    浏览(39)
  • 持续不断更新中... 自己整理的一些前端知识点以及前端面试题,包括vue2,vue3,js,ts,css,微信小程序等

    答: 在普通的前端项目工程中,在script标签中增加setup即可使用api 使用setup()钩子函数 答: 不要在计算属性中进行异步请求或者更改DOM 不要直接修改computed的值 区别: 计算属性值基于其响应式依赖被缓存,意思就是只要他之前的依赖不发生变化,那么调用他只会返回之前缓

    2024年02月11日
    浏览(58)
  • 零基础学前端(二)用简单案例去理解 HTML 、CSS 、JavaScript 概念

    该篇适用于从零基础学习前端的小白 初学者不懂代码得含义也要坚持模仿逐行敲代码,以身体感悟带动头脑去理解新知识 HTML,CSS,JavaScript 都是单独的语言;他们构成前端技术基础; (1)HTML:负责网页的架构; (2)CSS:负责网页的样式,美化; (3)JavaScript(JS):负责

    2024年02月08日
    浏览(50)
  • [HTML]Web前端开发技术26(HTML5、CSS3、JavaScript )JavaScript基础——喵喵画网页

    希望你开心,希望你健康,希望你幸福,希望你点赞! 最后的最后,关注喵,关注喵,关注喵,佬佬会看到更多有趣的博客哦!!! 喵喵喵,你对我真的很重要! 目录 前言 数据类型 数据类型-字符型 数据类型-数值型 数据类型-布尔型 数据类型-其它类型 变量 转义字符 运算

    2024年02月20日
    浏览(65)
  • [HTML]Web前端开发技术5.2(HTML5、CSS3、JavaScript )CSS基础,decoration,selector,properties,Cascading——喵喵画网页

    希望你开心,希望你健康,希望你幸福,希望你点赞! 最后的最后,关注喵,关注喵,关注喵,佬佬会看到更多有趣的博客哦!!! 喵喵喵,你对我真的很重要! 目录 前言 CSS基础 CSS继承与层叠 使用CSS控制Web页面 CSS选择器类型 CSS选择器声明 课后练习 应用CSS链接外部样式

    2024年02月05日
    浏览(68)
  • [HTML]Web前端开发技术5.1(HTML5、CSS3、JavaScript )CSS基础,selector,properties,font,Cascading,@import——喵喵画网页

    希望你开心,希望你健康,希望你幸福,希望你点赞! 最后的最后,关注喵,关注喵,关注喵,佬佬会看到更多有趣的博客哦!!! 喵喵喵,你对我真的很重要! 目录 前言 CSS概念   传统HTML的缺点 CSS的优势 浏览器与CSS 3 CSS编辑方法 使用CSS控制Web页面 CSS基本语法 CSS定义与

    2024年02月05日
    浏览(67)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包