前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >组件化详细

组件化详细

作者头像
用户11097514
发布2024-05-31 12:21:32
1510
发布2024-05-31 12:21:32
举报
文章被收录于专栏:技术分享技术分享

一、组件的组成部分

三大组成部分

代码语言:javascript
复制
<template>
  
</template>

<script>
export default {

}
</script>
<style scoped>
</style>

二、scoped解决样式冲突

默认情况:

写在组件中的样式会 全局生效 → 因此很容易造成多个组件之间的样式冲突问题。

  • 全局样式: 默认组件中的样式会作用到全局,任何一个组件中都会受到此样式的影响
  • 局部样式: 可以给组件加上scoped 属性,可以让样式只作用于当前组件
代码语言:javascript
复制
<template>

</template>

<script>
export default {

}
</script>
<style scoped>
</style>

scoped原理

通过上述的<style scoped>就可以使

  1. 当前组件内标签都被添加data-v-hash值 的属性
  2. css选择器都被添加 [data-v-hash值] 的属性选择器

最终效果: 必须是当前组件的元素, 才会有这个自定义属性, 才会被这个样式作用到

image.png
image.png

data必须是一个函数

一个组件的 data 选项必须是一个函数。目的是为了:保证每个组件实例,维护独立的一份数据对象。 每次创建新的组件实例,都会新执行一次data 函数,得到一个新对象。

代码语言:javascript
复制
<script>
export default {
  data: function () {
    return {
      count: 100,
    }
  },
}
</script>

组件通信

什么是组件通信 ?

组件通信,就是指组件与组件之间的数据传递

  • 组件的数据是独立的,无法直接访问其他组件的数据。
  • 想使用其他组件的数据,就需要组件通信

如何通信及其组件之间的关系分类

父子关系 非父子关系

image.png
image.png

父组件通过 props 将数据传递给子组件 子组件利用 $emit 通知父组件修改更新

父向子通信代码示例

父组件通过props将数据传递给子组件 父组件App.vue

image.png
image.png
代码语言:javascript
复制
//:title="msg"  表示动态赋予属性

父向子传值步骤

  1. 给子组件以添加属性的方式传值
  2. 子组件内部通过props接收
  3. 模板中直接使用 props接收的值
image.png
image.png

子传父通信代码示例

子向父传值步骤

  1. $emit触发事件,给父组件发送消息通知
  2. 父组件监听$emit触发的事件
  3. 提供处理函数,在函数的性参中获取传过来的参数
image.png
image.png

props

定义

组件上 注册的一些 自定义属性, 我们可以使用props属性来向子组件传递数据 两个特点:

  1. 可以 传递 任意数量 的prop
  2. 可以 传递 任意类型 的prop
image.png
image.png

案例: Main.vue为我们自己定义的父组件, UserInfo为自定义的子组件 , 通过props就可以实现组件之间的数据传递

image.png
image.png

props校验

我们使用组件的props属性, 但是数据不能乱传, 所以就需要使用props来校验数据 为组件的 prop 指定验证要求,不符合要求,控制台就会有错误提示 → 帮助开发者,快速发现错误

语法

类型: 类型校验、非空校验、默认值、自定义校验

代码语言:javascript
复制
props: {
	校验属性名:类型 
}

完整的校验写法

代码语言:javascript
复制
props: {
  校验的属性名: {
    type: 类型,  // Number String Boolean ...
    required: true, // 是否必填
    default: 默认值, // 默认值
    validator (value) {
      // 自定义校验逻辑
      return 是否通过校验
    }
  }
},

代码实例:

代码语言:javascript
复制
<script>
export default {
  // 完整写法(类型、默认值、非空、自定义校验)
  props: {
    w: {
      type: Number,
      //required: true,
      default: 0,
      // 校验逻辑
      validator(val) {
        // console.log(val)
        if (val >= 100 || val <= 0) {
          console.error('传入的范围必须是0-100之间')
          return false
        } else {
          return true
        }
      },
    },
  },
}
</script>

注意事项:

  1. default和required一般不同时写(因为当时必填项时,肯定是有值的)
  2. default后面如果是简单类型的值,可以直接写默认。如果是复杂类型的值,则需要以函数的形式return一个默认值

props和data、 单向数据流

1.共同点

都可以给组件提供数据

2.区别

  • data 的数据是自己的 —> 随便改
  • prop 的数据是外部的 —> 不能直接改,要遵循 单向数据流

单向数据流

父级props 的数据更新,会向下流动,影响子组件。这个数据流动是单向的

实现案例:

image.png
image.png

综合案例

组件之间数据的传输

代码地址: https://github.com/Ray2310/vue-demo 实现功能:

  • 拆分基础组件
  • 渲染待办任务
  • 添加任务
  • 删除任务
  • 底部合计 和 清空功能
  • 持久化存储

以组件TodoMain.vue(子组件)和组件App.vue(父组件) 为例 讲解父子数据传输的问题。

父传子 的 数据传输实现

  1. 在父亲组件中提供数据data并返回
  2. 在使用组件的template区域, 通过使用:list="list"来实现可以在子组件中接受数据
  3. 在子组件中通过使用props实现父亲组件传递内容的接收。
  4. 最后就可以在子组件的template中使用list中的数据
代码语言:javascript
复制
<template>
<!-- 列表区域 -->
  <section class="main">
    <ul class="todo-list">
      <li class="todo"  v-for="(item, index) in list" :key="item.id" >
        <div class="view" >
          <span class="index">{{ index + 1 }}</span> <label>{{ item.name }}</label>
          <button class="destroy"></button>
        </div>
      </li>
    </ul>
  </section>
</template>

<script>
  export default {
    // 使用对象的写法 ,接收父组件中传入的内容
      props: {
        list: Array
      }
  }

</script>

<style></style>

App.vue

代码语言:javascript
复制
<template>
  <!-- 主体区域 -->
  <section id="app">
    <TodoHeader></TodoHeader>
    <!-- 通过在这里写list, 就可以实现在子组件中作接收 -->
    <TodoMain :list="list"></TodoMain>
    <TodoFooter></TodoFooter>

  </section>
</template>

<script>
// 导入组件
  import TodoHeader from './components/TodoHeader.vue'
  import TodoMain from './components/TodoMain.vue'
  import TodoFooter from './components/TodoFooter.vue'

  export default {  
    // 注册组件
    components: {
      TodoHeader, 
      TodoMain,
      TodoFooter    
    },
  
  //TODO: 数据提供需要提供在父组件中, 这样如果我们想要使用, 直接使用props传递即可。 
  data () {
    return {
      list: [
        {id: 1, name: 'eat'},
        {id: 2, name: 'play'},
        {id: 3, name: 'write'}
      ]

    }
  }
}
</script>
<style>
</style>

子传父 的 数据传输实现

TodoHeader.vue 子组件向App.vue父子 传输添加的数据

  1. 在子组件中通过v-model实现数据收集并通过点击事件或回车 进行数据发送
  2. 然后通过this.$emit('addItem', this.name) 实现给父组件发送消息通知
  3. 父组件监听$emit触发的事件, 通过 @addItem="add", 并且通过add()函数接收数据
  4. 最后在函数中实现数据的update操作
代码语言:javascript
复制
<template>  
   <!-- 输入框 -->
  <header class="header">
    <h1>记事本</h1>
    <input placeholder="请输入任务" @keyup.enter="addItem()" v-model="name" class="new-todo" />
    <button class="add" @keyup.enter="addItem()" @click="addItem()">添加任务</button>
  </header>

</template>
<!-- 
  这里实现数据的 子传父
  完成添加功能
  1. 收集表单数据 v-model
  2. 监听时间 (回车+点击 都要进行添加)
  3. 子传父,将任务名称传递给父组件App.vue
  4. 父组件接受到数据后 进行添加 unshift(自己的数据自己负责)
 -->

<script>
  export default {
    data(){
    return {
      name:''
    }
  },
    methods: {
      addItem(){
        // console.log(this.name);
        //传递给父亲组件
        if(this.name === "" ) {
          return
        }
        this.$emit('addItem', this.name)
        //清空表单
        this.name = ''
      }
    } 
  }
</script>
<style>
</style>
代码语言:javascript
复制
<template>
  <!-- 主体区域 -->
  <section id="app">
    <TodoHeader @addItem="add"></TodoHeader>
    <!-- 通过在这里写list, 就可以实现在子组件中作接收 -->
    <TodoMain @deleteItem="deleteItem" :list="list"></TodoMain>
    <TodoFooter @clear="clear" :list="list"></TodoFooter>

  </section>
</template>

<script>
// 导入组件
  import TodoHeader from './components/TodoHeader.vue'
  import TodoMain from './components/TodoMain.vue'
  import TodoFooter from './components/TodoFooter.vue'

  export default {  
    // 注册组件
    components: {
      TodoHeader, 
      TodoMain,
      TodoFooter    
    },
  
  //TODO: 数据提供需要提供在父组件中, 这样如果我们想要使用, 直接使用props传递即可。 
  data () {
    return {
      list: [
        {id: 1, name: 'eat'},
        {id: 2, name: 'play'},
        {id: 3, name: 'write'}
      ]
    }
  },
  methods: {
    add(newName){
      console.log(newName)
      //使用unshift添加
      this.list.unshift({
        id: +new Date(), //通过时间戳来实现id的唯一性
        name: newName
      })
      //还需要作的是清空表单
    },
    deleteItem(id) {
      console.log(id)
      //通过filter过滤器实现删除操作
      this.list = this.list.filter(item => item.id !== id) 
    },
    //清空任务栏
    clear(){
      this.list = []
    }
  }
}
</script>
<!-- 
  TODO:
  拆分基础组件
  渲染待办任务
  添加任务
  删除任务
  底部合计 和 清空功能
  持久化存储
 -->
<style>
</style>

非父子之间的数据通信—event bus事件总线

非父子组件之间,进行简易消息传递。(复杂场景→ Vuex) 发送通知不是一个一对一的关系, 但凡有人接收, 那么就都可以接受发送的内容

步骤:

在工具包utils

  1. 创建一个都能访问的事件总线 (空Vue实例)
代码语言:javascript
复制
import Vue from 'vue'
const Bus = new Vue()
export default Bus
  1. A组件(接受方),监听Bus的 $on事件
代码语言:javascript
复制
<script>
 import Bus form './utils/EventBus' 
  export default {
    created () {
      Bus.$on('sendMsg', (msg) => {
        this.msg = msg
      })
    },
    data: {
      return {
        msg: ''
      }
    }
  }
</script>
  1. B组件(发送方),触发Bus的$emit事件
代码语言:javascript
复制
<template>
	<button #click="clickSend"></button>
  
</template>
<script>
 import Bus form './utils/EventBus' 
  export default {
      methods: {
        clickSend(){
          Bus.$emit('sendMsg', '这是一个消息')
        }
      }
  }
</script>

image.png
image.png

非父子通信-provide&inject

跨层级共享数据 从祖辈层到后辈层(例如:爷爷到孙子)

image.png
image.png

语法 :

  1. 父组件 provide提供数据
代码语言:javascript
复制
export default {
  provide () {
    return {
      // 普通类型【非响应式】
      color: this.color, 
      // 复杂类型【响应式】
      userInfo: this.userInfo, 
    }
  }
}
  1. 子/孙组件 inject获取数据
代码语言:javascript
复制
export default {
  inject: ['color','userInfo'],
    created () {
    console.log(this.color, this.userInfo)
  }
}

4.注意

  • provide提供的简单类型的数据不是响应式的,复杂类型数据是响应式。(推荐提供复杂类型数据)
  • 子/孙组件通过inject获取的数据,不能在自身组件内修改

v-model实现表单类组件的封装

**实现子组件和父组件数据的双向绑定 (实现App.vue中的selectId和子组件选中的数据进行双向绑定) **

v-model本质上实现的是双向绑定,而:value这中的是单向绑定, 但是我们子组件是不允许修改父组件的内容的, 所以如果直接使用v-model就会报错, 需要修改。

v-model其实就是 :value和@input事件的简写

  • 子组件:props通过value接收数据,事件触发 input
  • 父组件:v-model直接绑定数据
image.png
image.png

子组件

代码语言:javascript
复制
<select :value="value" @change="handleChange">...</select>
props: {
  value: String
},
methods: {
  handleChange (e) {
    this.$emit('input', e.target.value)
  }
}

父组件

代码语言:javascript
复制
<BaseSelect v-model="selectId"></BaseSelect>

.sync修饰符(vue3.x已排除)

:visible就是控制显示隐藏的 update是固定的。

image.png
image.png

ref 和 $refs (常用** 获取 dom 元素 **)

作用: 利用ref 和 $refs 可以用于 获取 dom 元素 或 组件实例

image.png
image.png

语法

  1. 给要获取的盒子添加ref属性
代码语言:javascript
复制
<div ref="chartRef">我是渲染图表的容器</div>
  1. 获取时通过 refs获取 this.refs.chartRef 获取
代码语言:javascript
复制
mounted () {
  console.log(this.$refs.chartRef)
}
image.png
image.png

vue异步更新、$nextTick

需求 编辑标题, 编辑框自动聚焦

  1. 点击编辑,显示编辑框
  2. 让编辑框,立刻获取焦点
image.png
image.png

“显示之后”,立刻获取焦点是不能成功的! 原因:Vue 是异步更新DOM (提升性能)

解决方案

nextTick:等 DOM更新后,才会触发执行此方法里的函数体**语法: **this.nextTick(函数体)

代码语言:javascript
复制
this.$nextTick(() => {
  this.$refs.inp.focus()
})

注意:$nextTick 内的函数体 一定是箭头函数,这样才能让函数内部的this指向Vue实例

自定义指令

  • 内置指令:v-html、v-if、v-bind、v-on… 这都是Vue给咱们内置的一些指令,可以直接使用
  • 自定义指令:同时Vue也支持让开发者,自己注册一些指令。这些指令被称为自定义指令每个指令都有自己各自独立的功能

概念:自己定义的指令,可以封装一些DOM操作,扩展额外的功能

案例, 通过自定义指令, 可以封装一些dom操作, 扩展额外的功能, 实现项目中的所有获取dom的操作都可以使用我们的自定义指令来实现获取dom

基本语法

  • 全局注册
代码语言:javascript
复制
//在main.js中
Vue.directive('指令名', {
  "inserted" (el) {
    // 可以对 el 标签,扩展额外功能
    el.focus()
  }
})
  • 局部注册
代码语言:javascript
复制
//在Vue组件的配置项中
directives: {
  "指令名": {
    inserted () {
      // 可以对 el 标签,扩展额外功能
      el.focus()
    }
  }
}
  • 使用指令语法: v-指令名

注意事项

  • 注意:在使用指令的时候,一定要先注册再使用,否则会报错 使用指令语法: v-指令名。如:注册指令时不用v-前缀,但使用时一定要加v-前缀

指令的值

需求: 实现一个 color 指令 - 传入不同的颜色, 给标签设置文字颜色

语法:

  1. 绑定指令时,可以通过“等号”的形式为指令 绑定 具体的参数值
代码语言:javascript
复制
<div v-color="color">我是内容</div>
  1. 通过 binding.value 可以拿到指令值,指令值修改会 触发 update 函数
代码语言:javascript
复制
directives: {
  color: {
    inserted (el, binding) {
      el.style.color = binding.value
    },
    update (el, binding) {
      el.style.color = binding.value
    }
  }
}

实现案例需求:

代码语言:javascript
复制
<template>

  <!-- 类名·最好和当前组件名同名 -->
  <div>
    <!--显示红色--> 
   <h2 v-color="color1">指令的值1测试</h2>
    <!--显示蓝色--> 
   <h2 v-color="color2">指令的值2测试</h2>
    <button @click="color1 = 'blue'">
       改变第一个h1的颜色
   </button>
 </div>

</template>
<script>
  //导入组件
  
  export default {
    data () {
    return {
      color1: 'red',
      color2: 'blue'
    }
  },

    methods: {
     

    },

    // mounted (){
    //     let input = this.$refs.inp.focus()
    //     console.log("input"+ input)
    // },

    // 注册组件 (对于导入的组件名和名称一样时, 我们可以直接使用)
    components: {
      
    }
    ,
    
    directives: {
      color: {
        inserted (el, binding) {
          // 可以对 el 标签,扩展额外功能
          //这个el 就相当于是document.querySelecter('color')的意思
          el.style.color = binding.value // 可以获取对应的data中的数据 就是我们指令的值color2 ----》 <h2 v-color="color1">指令的值1测试</h2>
          el.focus()

        },
        // update 指令的值修改的时候触发, 提供值变化后, dom的更新逻辑
        update (el , binding){
           console.log('update 指令的val')
           el.style.color = binding.value
        }
      }
    }
  }
</script>

<style>


</style>

v-loading指令封装

需求: 实际开发过程中,发送请求需要时间,在请求的数据未回来时,页面会处于空白状态 => 用户体验不好 封装一个 v-loading 指令,实现加载中的效果

类似于这样

image.png
image.png

分析

  1. 本质 loading效果就是一个蒙层,盖在了盒子上
  2. 数据请求中,开启loading状态,添加蒙层
  3. 数据请求完毕,关闭loading状态,移除蒙层

实现

  1. 准备一个 loading类,通过伪元素定位,设置宽高,实现蒙层
  2. 开启关闭 loading状态(添加移除蒙层),本质只需要添加移除类即可
  3. 结合自定义指令的语法进行封装复用
代码语言:javascript
复制
<style>
  .loading:before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background: #fff url("./loading.gif") no-repeat center;
}
</style>

插槽

**作用: **让组件内部的一些 结构 支持 自定义

image.png
image.png

需求: 将需要多次显示的对话框,封装成一个组件

插槽的基本语法

  1. 组件内需要定制的结构部分,改用****占位
  2. 使用组件时, ****标签内部, 传入结构替换slot
  3. 给插槽传入内容时,可以传入纯文本、html标签、组件

默认插槽

如果想要修改其中的内容该怎么做呢 ?

image.png
image.png

封装组件时,可以为预留的 插槽提供后备内容(默认内容) 自定义的组件MyDialog.vue

代码语言:javascript
复制
<template>
  <div class="dialog">
    <div class="dialog-header">
      <h3>友情提示</h3>
      <span class="close">✖️</span>
    </div>

    <div class="dialog-content">
      <!-- 通过slot插槽来进行占位, 然后就可以在App中进行自定义传输 -->
      <slot></slot>
    </div>
    <div class="dialog-footer">
      <button>取消</button>
      <button>确认</button>
    </div>
  </div>
</template>

如果想要实现组件的占位操作: 在App.vue中 即可通过自定义内容来实现

代码语言:javascript
复制
<Mydialog>
    <p>are you shuer</p>
   </Mydialog>
image.png
image.png

后被内容

但是这样的操作 ,如果我们不传输内容, 那么就会显示为空。 这样明显不符合要求, 所以我们需要给slot来实现给其中的内容进行赋值

代码语言:javascript
复制
<template>
  <div class="dialog">
    <div class="dialog-header">
      <h3>友情提示</h3>
      <span class="close">✖️</span>
    </div>

    <div class="dialog-content">
      <!-- 通过slot插槽来进行占位, 然后就可以在App中进行自定义传输 -->
      <slot>这是后被内容</slot>
    </div>
    <div class="dialog-footer">
      <button>取消</button>
      <button>确认</button>
    </div>
  </div>
image.png
image.png
image.png
image.png

具名插槽

image.png
image.png

一个组件内有多处结构,需要外部传入标签,进行定制 上面的弹框中有三处不同,但是默认插槽只能定制一个位置,这时候怎么办呢?

具名插槽的使用

通过在slot标签中使用 name属性来进行区分不同的插槽, 然后在需要使用的组件中, 通过v-slot:name属性value来进行赋值。 从而达到多个弹框出现多个值的情况

image.png
image.png

作用域插槽

插槽分类

  • 默认插槽
  • 具名插槽

插槽只有两种,作用域插槽不属于插槽的一种分类

作用

定义slot 插槽的同时, 是可以传值的。给 插槽 上可以 绑定数据,将来 使用组件时可以用

使用步骤

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

组件的封装 - 综合案例实现

my-tag 组件的封装

(1) 双击显示输入框,输入框获取焦点 (2) 失去焦点,隐藏输入框 (3) 回显标签信息 (4) 内容修改,回车 → 修改标签信息

实现双击显示输入框, 并且获取输入框的焦点

  1. 首先, 双击显示输入框, 我们可以通过双点击事件dblclick="handleClick"实现,然后在实现的函数中 通过使v-if的内容为true, 实现点击显示输入框
  2. 获取输入框的焦点可以有两种方式:
  • 方式一: 通过双击, 然后在其中的函数里通过this.$nextTick(()=> {})的方式 实现
  • 方式二: 通过在main.js中全局注册, 然后封装全局指令focus,然后就可以直接通过v-focus来进行使用
image.png
image.png

失去焦点

因为获取焦点,我们是通过v-if来向选择的, 所以如果想要失去焦点, 可以直接将if中的信息修改即可。 所以就可以通过@blur="isEdit = false"实现失去焦点

回显标签信息

回显的信息是通过父组件传入的, 可以通过v-model实现, 也可以通过前面所学的props实现。 这里我们使用v-model实现, v-model ==> :value 和 input的组合

  1. 父组件中<MyTag v-model="tempText"></MyTag>, 通过v-model将需要修改的信息传入子标签
  2. 子标签中通过props来进行接受标签内容
  3. 接下来就可以在结构页面通过{{ value}}实现内容的显示。

通过上述的步骤就可以实现数据从父标签传入子标签, 实现标签内容的回显

回车修改标签内容

上述的回显示标签信息是通过父标签传子标签的形式实现的, 但是如何实现子标签传入父标签呢 ? 这里通过回车实现事件的触发, 那么我们就·在回车事件内实现数据的回显。

  1. 首先,我们知道, 回显的内容是在我们输入的input标签中, 同样,我们回车触发事件的内容也是在input中, 所以我们可以通过e.target.value获取触发事件的标签的内容, 也就是我们input标签中的内容, 也就是我们需要回显 的内容。
  2. 所以在回车事件中, 我们就可以通过this.$emit('input', e.target.value)实现子标签的内容向父标签传递的功能。
代码语言:javascript
复制
<template>
  <div class="my-tag">
    <input 
      v-if="isEdit"
      refs="inp"
      v-focus
      :value="value"
      class="input"
      type="text"
      placeholder="输入标签"
      @blur="isEdit = false"
      @keyup.enter="handleEnter"
    />
    <!-- 
       :value="values"绑定
       v-focus 自动聚焦的方法二 : 在main.js中封装全局指令
      @blur="isEdit = false" 失去焦点隐藏 -->
    <div class="text" v-else
      @dblclick="handleClick">{{ value }}</div>
  </div>

</template>
<!-- 
  (1) 双击显示输入框,输入框获取焦点
  (2) 失去焦点,隐藏输入框
  (3) 回显标签信息
      信息是由外部父组件传入的
  (4) 内容修改,回车 → 修改标签信息
 -->
<script>
  export default {
     //接受父组件传入的信息
    props: {
      value: String
    },
    data() { 
      return { 
        isEdit: false
      }
    },
    methods: {
      // 使用双击点击事件
      handleClick(){ 
        // 需要实现自动聚焦的方式一: ,通过this.$nextTick()
        // this.$nextTick(()=> {
        //   //立刻获取焦点
        //   this.$refs.inp.focus()
        // })
        this.isEdit = true
      },
      //e :可以获取触发事件的事件源
      handleEnter(e) {
        if(e.target.value.trim() === '') return alert("标签内容不为空")
        //获取回车之后里面的内容, 所以获取内容, 然后更新给父组件
        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>

my-table 组件的封装

(1) 动态传递表格数据渲染 (2) 表头支持用户自定义 (3) 主体支持用户自定义

动态定义表

通过<slot name="head"></slot>占位, 然后在父标签中实现内容传递

image.png
image.png

在父组件App.vue中, 通过使用<template #head...>的方式, 实现组件插槽的自定义编辑。

代码语言:javascript
复制
<template>
   <div class="table-case">
   <!-- 动态的定义表头 -->
     <MyTable :data="goods">
      <template #head>
        <th>编号</th>
        <th>图片</th>
        <th>名称</th>
        <th width="100px">标签</th>

      </template> 

      <!-- 通过表头 ,自定义主体部分. 通过obj对象来接收传入的内容 -->
      <template #body="obj">
          <td>{{ obj.index + 1}}</td>
          <td> <img :src="obj.item.picture" /> </td>
          <td> {{  obj.item.name }} </td>
          <td> <MyTag v-model="obj.item.tag"></MyTag> </td>

      </template>
    </MyTable>
  
   </div>
</template>

在子组件MyTable.vue组件中,通过<slot name="body" :item="item" :index="index"></slot>占位符的方式, 实现组件内容的占位, 然后再通过:参数=“参数”的方式, 实现占位中的内容传输

代码语言:javascript
复制
<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插槽占位 ,之后又使用:item 进行插槽传值 -->
        <slot name="body" :item="item" :index="index"></slot>
      </tr>
  
    </tbody>
  </table>

</template>
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2023-10-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、组件的组成部分
  • 二、scoped解决样式冲突
    • 默认情况:
      • scoped原理
      • data必须是一个函数
      • 组件通信
        • 什么是组件通信 ?
          • 如何通信及其组件之间的关系分类
            • 父向子通信代码示例
            • 子传父通信代码示例
        • props
          • 定义
            • props校验
              • 语法
              • 完整的校验写法
              • 注意事项:
            • props和data、 单向数据流
              • 1.共同点
              • 2.区别
              • 单向数据流
            • 综合案例
              • 组件之间数据的传输
                • 父传子 的 数据传输实现
                • 子传父 的 数据传输实现
            • 非父子之间的数据通信—event bus事件总线
              • 步骤:
              • 非父子通信-provide&inject
                • 语法 :
                  • 4.注意
              • v-model实现表单类组件的封装
                • .sync修饰符(vue3.x已排除)
                  • ref 和 $refs (常用** 获取 dom 元素 **)
                    • 语法
                  • vue异步更新、$nextTick
                    • 解决方案
                • 自定义指令
                  • 基本语法
                    • 注意事项
                  • 指令的值
                    • 语法:
                      • 实现案例需求:
                    • v-loading指令封装
                      • 分析
                      • 实现
                      • 插槽的基本语法
                  • 插槽
                    • 默认插槽
                      • 后被内容
                        • 具名插槽
                          • 具名插槽的使用
                        • 作用域插槽
                          • 插槽分类
                          • 作用
                          • 使用步骤
                      • 组件的封装 - 综合案例实现
                        • my-tag 组件的封装
                          • 实现双击显示输入框, 并且获取输入框的焦点
                          • 失去焦点
                          • 回显标签信息
                          • 回车修改标签内容
                        • my-table 组件的封装
                          • 动态定义表
                      相关产品与服务
                      事件总线
                      腾讯云事件总线(EventBridge)是一款安全,稳定,高效的云上事件连接器,作为流数据和事件的自动收集、处理、分发管道,通过可视化的配置,实现事件源(例如:Kafka,审计,数据库等)和目标对象(例如:CLS,SCF等)的快速连接,当前 EventBridge 已接入 100+ 云上服务,助力分布式事件驱动架构的快速构建。
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档