vue-插槽作用域实用场景

news2024/10/12 12:23:00

vue-插槽作用域实用场景

  • 1.插槽
    • 1.1 自定义列表渲染
    • 1.2 数据表格组件
    • 1.3 树形组件
    • 1.4 表单验证组件
    • 1.5 无限滚动组件

1.插槽

插槽感觉知道有这个东西,但是挺少用过的,每次看到基本都会再去看一遍用法和概念。但是在项目里,自己还是没有用到过。总结下一些可能用到的场景,下次直接这样写了。

1.1 自定义列表渲染

<script setup>
import HelloWorld from './components/HelloWorld.vue'
import { reactive } from 'vue';
const myItems = reactive(
  [
  {
    name: 'A',
    age: 18
  },
  {
    name: 'B',
    age: 19
  },
  {
    name: 'C',
    age: 20
  }
]
)
</script>
<template>
  <HelloWorld :items="myItems">
    <template v-slot:default="slotProps">
    <span>{{ slotProps.item.name }}</span>
    <button @click="doSomething(slotProps.item)">操作</button>
  </template>
  </HelloWorld>
</template>

<script setup>
import { defineProps } from 'vue';
 defineProps({
  items: {
    type: Array,
    default: () => []
  }
})
</script>
<template>
  <ul>
    <li v-for="item in items" :key="item.id">
      <slot :item="item"></slot>
    </li>
  </ul>
</template>

效果:
在这里插入图片描述
拓展性很强。

1.2 数据表格组件

<script setup>
import HelloWorld from './components/HelloWorld.vue'
import { reactive } from 'vue';
const tableData = reactive(
  [
    {
      name: 'A',
      age: 18
    },
    {
      name: 'B',
      age: 19
    },
    {
      name: 'C',
      age: 20
    }
  ]
)

const columns = reactive(
  [
    {
      label: '姓名',
      key: 'name'
    },
    {
      label: '年龄',
      key: 'age'
    },
    {
      label: '性别',
      key: 'sex'
    },
    { key: 'actions', label: '操作' }
  ]
)
</script>
<template>
  <HelloWorld :columns="columns" :data="tableData">
    <template v-slot:actions="{ row }">
      <button @click="edit(row)">编辑</button>
      <button @click="del(row)">删除</button>
    </template>
  </HelloWorld>
</template>

<template>
  <table>
    <thead>
      <tr>
        <th v-for="column in columns" :key="column.key">
          {{ column.label }}
        </th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="row in data" :key="row.id">
        <td v-for="column in columns" :key="column.key">
          <slot :name="column.key" :row="row">
            {{ row[column.key] }}
          </slot>
        </td>
      </tr>
    </tbody>
  </table>
</template>

<script setup>
import { defineProps } from 'vue';
defineProps({
  columns: Array,
  data: Array,
});
</script>

效果:
在这里插入图片描述

1.3 树形组件

<template>
  <div class="tree-node">
    <slot :node="node" :toggle="toggle" :expandTree="expandTree" name="trangle">
      <span v-if="node.children.length > 0" @click="toggle">{{ expanded ? '▼' : '▶' }}</span>
    </slot>
    <slot :node="node" :toggle="toggle" :expandTree="expandTree">
      <div>
        {{ node.label }}
      </div>
    </slot>
    <div v-if="expanded" class="tree-node-children">
      <HelloWorld v-for="child in node.children" :key="child.id" :node="child">
        <template v-slot="childSlotProps">
          <slot v-bind="childSlotProps"></slot>
        </template>
      </HelloWorld>
    </div>
  </div>
</template>
<script setup>
import HelloWorld from './HelloWorld.vue'
import { defineProps, ref } from 'vue';
const props = defineProps({
  node: {
    type: Object,
    required: true
  }
})
const expanded = ref(false)
const toggle = () => {
  console.log(999)
  expanded.value = !expanded.value
}
const expandTree = () => {
  expanded.value = true
}
</script>
<style>
.tree-node {
  position: relative;
  cursor: pointer;
}

.tree-node-children {
  position: relative;
  padding-left: 20px;
  /* 这个值决定了每一层的缩进量 */
}

.tree-node>span {
  margin-left: 0;
}
</style>

<script setup>
import HelloWorld from './components/HelloWorld.vue'
import { reactive } from 'vue';

const rootNode = reactive({
  id: 1,
  label: '根节点',
  children: [
    {
      id: 2, label: '子节点1', children: [
        { id: 3, label: '子节点1-1', children: [] }
      ]
    },
    { id: 4, label: '子节点2', children: [] }
  ]
})

const addChild = (node, expandTree) => {
  const newId = Date.now()
  expandTree()
  node.children.push({
    id: newId,
    label: `新子节点${newId}`,
    children: []
  })
}
</script>
<template>
  <HelloWorld :node="rootNode">
    <template v-slot="{ node, toggle, expandTree }">
      <span @click="toggle">{{ node.label }}</span>
      <button @click="addChild(node, expandTree)">添加子节点</button>
    </template>
  </HelloWorld>
</template>

效果:
在这里插入图片描述

1.4 表单验证组件

<script setup>
import { ref, watch, defineProps, defineEmits } from 'vue'

const props = defineProps({
  rules: {
    type: Array,
    default: () => []
  },
  modelValue: {
    type: String,
    default: ''
  }
})

const emit = defineEmits(['update:modelValue'])

const value = ref(props.modelValue)
const error = ref('')

const validate = () => {
  for (const rule of props.rules) {
    if (!rule.validate(value.value)) {
      error.value = rule.message
      return false
    }
  }
  error.value = ''
  return true
}

watch(() => props.modelValue, (newValue) => {
  value.value = newValue
})

watch(value, (newValue) => {
  emit('update:modelValue', newValue)
})
</script>

<template>
  <div class="a">
    <slot :value="value" :error="error" :validate="validate"></slot>
    <span v-if="error">{{ error }}</span>
  </div>
</template>
<style lang="scss" scoped>
.a{
  position: relative;
  span{
    color: red;
    position: absolute;
    left: 0;
    bottom: -24px;
    font-size: 14px;
  }
}</style>

//使用
<script setup>
import FormField from './components/HelloWorld.vue'
import { ref } from 'vue';


const email = ref('')

const emailRules = [
  {
    validate: (value) => /.+@.+\..+/.test(value),
    message: '请输入有效的电子邮件地址'
  }
]
</script>
<template>
  <FormField :rules="emailRules" v-model="email">
    <template v-slot="{ value, error, validate }">
      邮箱
      <input :value="value" @input="$event => { email = $event.target.value; validate(); }"
        :class="{ 'is-invalid': error }" />
    </template>
  </FormField>
</template>

<style >
input{
  outline: none;
}
.is-invalid:focus {
  border-color: red;
}
</style>

效果:
在这里插入图片描述

1.5 无限滚动组件


<script setup>
import { ref, onMounted, defineProps } from 'vue'

const props = defineProps({
  fetchItems: {
    type: Function,
    required: true
  }
})

const visibleItems = ref([])
const loading = ref(false)

const handleScroll = async (event) => {
  const { scrollTop, scrollHeight, clientHeight } = event.target
  if (scrollTop + clientHeight >= scrollHeight - 20 && !loading.value) {
    loading.value = true
    const newItems = await props.fetchItems()
    visibleItems.value = [...visibleItems.value, ...newItems]
    loading.value = false
  }
}

onMounted(async () => {
  visibleItems.value = await props.fetchItems()
})
</script>

<template>
  <div @scroll="handleScroll" style="height: 200px; overflow-y: auto;">
    <slot :items="visibleItems"></slot>
    <div v-if="loading">加载中...</div>
  </div>
</template>

//使用
<script setup>
import InfiniteScroll from './components/HelloWorld.vue'
import { ref } from 'vue';



let page = 0
const fetchMoreItems = async () => {
  // 模拟API调用
  await new Promise(resolve => setTimeout(resolve, 1000))
  page++
  return Array.from({ length: 10 }, (_, i) => ({
    id: page * 10 + i,
    content: `Item ${page * 10 + i}`
  }))
}
</script>
<template>
  <InfiniteScroll :fetch-items="fetchMoreItems">
    <template #default="{ items }">
      <div v-for="item in items" :key="item.id">
        {{ item.content }}
      </div>
    </template>
  </InfiniteScroll>
</template>


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2207900.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

QD1-P1 开始学习前端,HTML、CSS与JS三者之间的关系

今天开始学习前端基础&#xff0c;新建专题《前端学习笔记1》保存前端基础学习笔记。 专题文章命名以qd1开头。 源课程 视频教程&#xff1a;【Web前端-最通俗易懂HTML、CSS与JS合集 1天速成】 up&#xff1a;遥遥温柔乡 在B站随便搜索了一个前端课程&#xff0c;共91节&am…

JVS低代码轻应用是什么?是如何拼装的?这篇文章讲的非常详细

1.1JVS轻应用是什么&#xff1f; 轻应用与传统应用的开发过程区别 传统开发&#xff08;原生开发&#xff09;采用的方式&#xff1a;①需求了解 ②产品原型③UI设计④建库建表⑤前端还原⑥后端开发⑦前后端联调⑧功能测试⑨部署上线轻应用开发方式&#xff08;配置化拼装&…

SpringBoot定时任务@Scheduled完整功能详解(提供Gitee源码)

目录 一、实现定时任务 1.1、fixedRate 1.2、fixedDelay 1.3、initialDelay 1.4、cron 二、cron表达式 三、读取配置文件 四、实现并行执行定时任务 五、Gitee源码 一、实现定时任务 首先在主应用类或者任何配置类上添加@EnableScheduling注解,以启用定时任务功能。…

基于monaco-editor的web日志组件

基于monaco-editor封装的编辑器&#xff0c;支持如下功能&#xff1a; 日志内容颜色配置&#xff1a;info、primary、success、warning、error支持主题配置&#xff1a;dark、light支持滚动到顶部、底部、全屏编辑器默认带的全局搜索扩展性强&#xff0c;支持monaco的所有配置…

STM32学习--4-1 OLED显示屏

接线图 OLED.c #include "stm32f10x.h" #include "OLED_Font.h"/*引脚配置*/ #define OLED_W_SCL(x) GPIO_WriteBit(GPIOB, GPIO_Pin_8, (BitAction)(x)) #define OLED_W_SDA(x) GPIO_WriteBit(GPIOB, GPIO_Pin_9, (BitAction)(x))/*引脚初始化*/ void …

selenium:WebElement类的核心操作方法(3)

当我们通过webdriver中的find_element函数定位到元素后&#xff0c;其实返回的是WebElement对象&#xff0c;而该对象有很多重要的方法&#xff0c;比如输入文本&#xff0c;点击按钮&#xff0c;获取属性&#xff0c;截屏等 WebElement类的方法介绍 文本输入与清除 send_key…

【原创教程】电气电工23:电气柜的品牌及常用型号

电气电工要清楚常用的电气柜品牌及型号,对于电器柜的选择,现在我们一般常用的品牌有3个。分别是好夫满、上海上海桐赛电气和南京巴哈曼电气,还有一种就是网上订制。 一、好夫满系列电气箱 好夫满有很多种类的机箱,EB精巧控制箱系列、KL接线箱系列、BKL不锈钢接线箱系列、…

构建基于 阻塞队列 / 环形队列 的高效生产消费者模型系统

1. 生产者-消费者问题 概述 生产-消费者模型 &#xff1a;一个或多个 生产者线程 产生数据并将其放入共享缓冲区&#xff0c;同时一个或多个 消费者线程 从该缓冲区中读取数据进行操作的情景。 缓冲区 是一个用于存储生产者产生数据的中间容器&#xff1b;缓冲区 的容量通常是…

【操作系统】四、文件管理:1.文件系统基础(文件属性、文件逻辑结构、文件物理结构、文件存储管理、文件目录、基本操作、文件共享、文件保护)

文件管理 文章目录 文件管理八、文件系统基础1.文件的属性2.文件的逻辑结构2.1顺序文件2.2索引文件2.3索引顺序文件2.4多级索引顺序文件 3.目录文件❗3.1文件控制块FCB3.1.1对目录进行的操作 3.2目录结构3.2.1单级目录结构3.2.2两级目录结构3.2.3多级目录结构&#xff08;树形目…

vue2引入i18n插件实现中英文切换

vue2引入i18n插件实现中英文切换 1.安装i18n插件2.引入3.使用4.数据渲染 1.安装i18n插件 npm install vue-i18n --save-dev注意&#xff1a; vue2环境下安装i18n插件时 有可能会报错&#xff08;我的这个项目比较老&#xff0c;vue2.5.x版本的&#xff09;&#xff0c;报错信息…

保姆级教程 | Linux中grep命令使用 分子动力学轨迹文件输出特定原子电荷值

背景 由于课题需要&#xff0c;现根据lammps运行得到的轨迹需要提取出目标原子的电荷值 步骤 思路 首先确定目标原子在轨迹中的序号&#xff08;lammps每个原子都有自己独立的【分子号原子号】&#xff09; 其次要十分清楚体系中的分子号排序方式&#xff0c;然后只要筛选出…

安卓13禁止锁屏 关闭锁屏 android13禁止锁屏 关闭锁屏

总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析4.代码修改5.彩蛋1.前言 设置 =》安全 =》屏幕锁定 =》 无。 我们通过修改系统屏幕锁定配置,来达到设置屏幕不锁屏的配置。像网上好多文章都只写了在哪里改,改什么东西,但是实际上并未写明为什么要改那…

浅谈虚拟电厂在分布式光伏发电应用示范区中的应用及前景

0引言 随着电力体制改革的持续推进&#xff0c;电力市场将逐步建立和完善&#xff0c;未来的售电主体也将随着配售电业务的逐步放开而日益多元化&#xff0c;新的政策不断鼓励分布式电源和微电网作为独立的配售电市场主体推动运营模式的创新。与微电网所采取的就地应用为控制目…

离散数学-逻辑与证明基础1.4(谓词和量词)

谓词 1.4.2 谓词 涉及变量的语句&#xff0c;例如&#xff1a; “ x > 3 x > 3 x>3”&#xff0c;“ x y 3 x y 3 xy3”&#xff0c;“ x y z x y z xyz” 以及 \quad “Computer x x x is under attack by an intruder” \quad “Computer x x x is f…

nginx虚拟主机配置与locaion规则

目录 1.虚拟主机 1.1分类 1.2基于域名的虚拟机 1.2.1测试 1.3基于端口的虚拟主机 1.3.1测试 ​编辑1.4基于IP的虚拟主机 2.nginx日志 3.location 1.虚拟主机 虚拟主机:相当于1个网站&#xff0c;在nginx中通过server{}区域实现。 nginx虚拟主机有不同的配置类型…

科研论文必备:10大平台和工具助你高效查找AI文献

申博、留学、评职称的同学&#xff0c;逃不过要发表论文。对很多人尤其是对于论文新手来说&#xff0c;写论文可能是一个极具挑战性的过程。今天Bulu分享以下10个论文平台、论文检索工具&#xff0c;会大大提高论文撰写效率&#xff0c;告别熬夜肝论文&#xff01;建议收藏哦&a…

【原创】java+springboot+mysql劳动教育网系统设计与实现

个人主页&#xff1a;程序猿小小杨 个人简介&#xff1a;从事开发多年&#xff0c;Java、Php、Python、前端开发均有涉猎 博客内容&#xff1a;Java项目实战、项目演示、技术分享 文末有作者名片&#xff0c;希望和大家一起共同进步&#xff0c;你只管努力&#xff0c;剩下的交…

78.【C语言】EOF的解释

1.cplusplus网的介绍 在这几篇文章提到过,但没有详细阐释过EOF的细节 24.【C语言】getchar putchar的使用E4.【C语言】练习&#xff1a;while和getchar的理解32.【C语言】详解scanf 75.【C语言】文件操作(3) cplusplus网的介绍 点我跳转 翻译 常量 EOF 文件结束(End-Of-Fi…

STM32F103C8T6 - 定时器

一、定时器简介 定时器总共分为4部分&#xff0c;8小结。 第一部分&#xff08;定时中断、内外时钟源选择&#xff09;&#xff1a;定时器基本定时计数功能&#xff0c;定一个时间&#xff0c;让定时器每隔一段时间定时中断一次 。 第二部分&#xff08;输出比较&#xff09…

21年408数据结构

第一题&#xff1a; 解析&#xff1a;q指针指向要被删除的元素&#xff0c;当这个元素是链表中唯一一个元素时&#xff0c;q指针和尾指针都指向同一个元素&#xff0c;那么在删除掉这个元素之前&#xff0c;需要将尾指针调整到指向头指针的位置&#xff0c;此时链表为空&#x…