Vue.js 插槽、作用域插槽、商品、阶段案例

目录

一、插槽

1、概念

2、代码及演示

二、作用域插槽

1、概念

2、代码及演示

[三、插槽VS 作用域插槽区别](#三、插槽VS 作用域插槽区别)

四:阶段案例-商品管理

1、概念

2、代码及演示效果

3、核心代码讲解


一、插槽

1、概念

2、代码及演示

创建src\components\SlotSubComponent.vue文件,展示子组件的内容

复制代码
<template>
  <div>测试插槽的组件</div>
  <slot></slot>
</template>

创建src\components\MySlot.vue文件,用于展示插槽的相关内容。

复制代码
<template>
  父组件-----{{ message }}
  <hr>
  <!-- 子组件需要写成双标签形式 -->
  <SlotSubComponent>
    <!-- 这是传给子组件插槽的内容 -->
     <span style="color: blue;">下面是测试插槽组件,并传递数据给插槽</span>
    <p>{{ message }}</p>
  </SlotSubComponent>
</template>
<script setup>
import SlotSubComponent from './SlotSubComponent.vue'
const message = '这是组件的使用者自定义的内容'
</script>

具名插槽

代码及演示效果

创建src\components\ArticleInfo.vue文件,用于展示文章内容模板。

复制代码
<template>
  <div class="article-container">
    <div class="header-box"><slot name="header"></slot></div>
    <div class="content-box"><slot name="content"></slot></div>
    <div class="footer-box"><slot name="footer"></slot></div>
  </div>
</template>
<style>
.article-container > div { border: 1px solid black; }
</style>

创建src\components\MyArticle.vue文件,用于提供文章数据,在MyArticle组件中导入并使用ArticleInfo组件,并在<ArticleInfo>标签中为不同插槽添加不同的信息。

复制代码
<template>
  <ArticleInfo>
    <template v-slot:header><p>这是文章的头部区域</p></template>
    <template v-slot:content><p>这是文章的内容区域</p></template>
    <template #footer><p>这是文章的尾部区域</p></template>
  </ArticleInfo>
</template>
<script setup>import ArticleInfo from './ArticleInfo.vue' </script>

二、作用域插槽

1、概念

2、代码及演示

创建src\components\SubScopeSlot.vue文件,用于作用域插槽--定义数据。

复制代码
<template>
  <slot message="Hello 默认插槽"></slot>
  <hr>
  <slot message="Hello Vue.js" name="header"></slot>
  <hr>
  <slot :user="user" name="content"></slot>
</template>
<script setup>
import { reactive } from 'vue'
const user = reactive({ name: 'xiaoyuan', age: '15' })	    
</script>

创建src\components\ScopeSlot.vue文件,用于 接收从作用域插槽传递的数据。

复制代码
<template>
  <SubScopeSlot>
    <template v-slot:default="scope"><p>{{ scope }}</p></template>
    <template v-slot:header="scope">
      <p>{{ scope }}</p><p>{{ scope.message }}</p>
    </template>
    <template #content="{ user }">
      <p>{{ user.name }}</p><p>{{ user.age }}</p></template>
  </SubScopeSlot>
</template>
<script setup>import SubScopeSlot from './SubScopeSlot.vue'</script>

修改main.js ,切换显示ScopeSlot

复制代码
import ScopeSlot from './components/ScopeSlot.vue'
createApp(ScopeSlot).mount('#app')

三、插槽VS 作用域插槽区别

四:阶段案例-商品管理

1、概念

2、代码及演示效果

2.1、安装并全局引入Element Plus 组件

npm install element-plus2.2、全部代码

创建src\components\shangpin.vue文件,用于作用域插槽--定义数据。

复制代码
<!-- 商品管理完整可运行代码 -->
<template>
  <el-table :data="goodsList" border style="width: 100%">
    <!-- 编号列 -->
    <el-table-column type="index" label="编号" />

    <!-- 商品名称 -->
    <el-table-column prop="goods_name" label="商品名称" />

    <!-- 商品价格 -->
    <el-table-column prop="goods_price" label="商品价格" />

    <!-- 标签列(作用域插槽) -->
    <el-table-column label="标签">
      <template v-slot="{ row }">
        <div class="flex gap-2 items-center">
          <!-- 标签循环 -->
          <el-tag
            v-for="(tag, index) in row.tags"
            :key="index"
            closable
            disable-transitions
            @close="() => handleClose(row, tag)"
          >
            {{ tag }}
          </el-tag>

          <!-- 新增标签输入框 -->
          <el-input
            v-if="row.inputVisible"
            v-model="row.inputValue"
            size="small"
            class="w-20"
            @keyup.enter="() => handleInputConfirm(row)"
            @blur="() => handleInputConfirm(row)"
          />

          <!-- +Tag 按钮 -->
          <el-button
            v-else
            class="button-new-tag"
            size="small"
            @click="() => showInput(row)"
          >
            + Tag
          </el-button>
        </div>
      </template>
    </el-table-column>

    <!-- 操作列 -->
    <el-table-column label="操作">
      <template v-slot="{ row }">
        <el-button type="danger" plain @click="onRemove(row.id)">
          删除
        </el-button>
      </template>
    </el-table-column>
  </el-table>
</template>

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

// 商品列表数据
const goodsList = ref([
  {
    id: 1,
    goods_name: '夏季专柜同款女鞋',
    goods_price: 298,
    tags: ['舒适', '透气'],
    inputVisible: false,
    inputValue: ''
  },
  {
    id: 2,
    goods_name: '冬季保暖女士休闲雪地靴 舒适加绒防水短靴 防滑棉鞋',
    goods_price: 89,
    tags: ['保暖', '防滑'],
    inputVisible: false,
    inputValue: ''
  },
  {
    id: 3,
    goods_name: '秋冬新款女士毛衣 套头宽松针织衫 简约上衣',
    goods_price: 199,
    tags: ['秋冬', '毛衣'],
    inputVisible: false,
    inputValue: ''
  },
  {
    id: 4,
    goods_name: '2023春秋装新款大码女装 衬衫 上衣',
    goods_price: 19,
    tags: ['雪纺衫', '打底'],
    inputVisible: false,
    inputValue: ''
  },
  {
    id: 5,
    goods_name: '长款长袖圆领女士毛衣 2022秋装新款假两件连衣裙',
    goods_price: 178,
    tags: ['圆领', '连衣裙'],
    inputVisible: false,
    inputValue: ''
  }
])

// 关闭标签
const handleClose = (row, tag) => {
  const i = row.tags.indexOf(tag)
  if (i >= 0) row.tags.splice(i, 1)
}

// 显示输入框
const showInput = async (row) => {
  row.inputVisible = true
  await nextTick()
  // 让输入框自动聚焦
  const input = document.querySelector('.el-input__inner:focus')
  input?.focus()
}

// 确认添加标签
const handleInputConfirm = (row) => {
  if (row.inputValue.trim()) {
    row.tags.push(row.inputValue.trim())
  }
  row.inputValue = ''
  row.inputVisible = false
}

// 删除整行
const onRemove = (id) => {
  goodsList.value = goodsList.value.filter(item => item.id !== id)
}
</script>

<style scoped>
.flex {
  display: flex;
}
.gap-2 {
  gap: 8px;
}
.items-center {
  align-items: center;
}
.w-20 {
  width: 80px;
}
.button-new-tag {
  height: 24px;
  line-height: 24px;
  padding: 0 8px;
}
</style>

修改main.js

复制代码
// 👇 必须同时引入这两行
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'

createApp(shangpin).use(ElementPlus).mount('#app')

3、核心代码讲解

3.1 代码片段1

复制代码
 <!-- 标签列(作用域插槽) -->
    <el-table-column label="标签">
      <!-- row = 子组件(表格)传给父组件的所有数据 
        当前这一行的商品数据(最重要)-->
      <template v-slot="{ row }">
        <div class="flex gap-2 items-center">
          <!-- 标签循环 -->
          <el-tag
            v-for="(tag, index) in row.tags"
            :key="index"
           
            closable
            disable-transitions
            @close="() => handleClose(row, tag)"
          >
            {{ tag }}
          </el-tag>

          <!-- 新增标签输入框 -->
          <el-input
            v-if="row.inputVisible"
            v-model="row.inputValue"
            size="small"
            class="w-20"
            @keyup.enter="() => handleInputConfirm(row)"
            @blur="() => handleInputConfirm(row)"
          />

          <!-- +Tag 按钮 -->
           <!-- 点击 → 显示输入框
v-else:输入框隐藏时才显示按钮 -->
          <el-button
            v-else
            class="button-new-tag"
            size="small"
            @click="() => showInput(row)"
          >
            + Tag
          </el-button>
        </div>
      </template>
    </el-table-column>

3.2 代码片段2

3.3 代码片段3

3.4 代码片段4

3.5 代码片段5

3.6 代码片段6

v-if / v-else 极简入门 Demo

复制代码
<template>
  <div>
    <h3>v-if / v-else 简单演示</h3>

    <button @click="isShow = !isShow">切换显示/隐藏</button>

    <!-- 条件渲染 -->
    <div v-if="isShow">✅ 我是显示的内容</div>
    <div v-else>❌ 我是隐藏后的替代内容</div>
  </div>
</template>

<script setup>
import { ref } from 'vue'
// 定义布尔值变量
const isShow = ref(true)
</script>

3.7 代码片段7

v-for 极简入门 Demo

复制代码
<template>
  <div class="box">
    <h3>v-for 遍历商品简单案例</h3>

    <!-- v-for 遍历商品数组 -->
    <div v-for="(item, index) in goodsList" :key="index" class="item">
      <p>序号:{{ index + 1 }}</p>
      <p>商品名称:{{ item.goods_name }}</p>
      <p>商品价格:{{ item.goods_price }} 元</p>
      <hr>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'

// 和上面商品案例结构完全一样,只是精简了
const goodsList = ref([
  { id: 1, goods_name: '夏季女鞋', goods_price: 298 },
  { id: 2, goods_name: '保暖雪地靴', goods_price: 89 },
  { id: 3, goods_name: '秋冬毛衣', goods_price: 199 }
])
</script>

<style scoped>
.box { padding: 20px; }
.item { margin: 10px 0; padding: 10px; border: 1px solid #ccc; }
</style>
相关推荐
EF@蛐蛐堂2 小时前
TanStack NPM攻击 揭秘及应对方案
前端·vue.js·npm·安全威胁分析
恋猫de小郭2 小时前
终于,Flutter 修复 Android 中文字体异常,但是很草台,不知怎么吐槽
android·前端·flutter
亚空间仓鼠2 小时前
Docker容器化高可用架构部署方案(八)
android·docker·架构
Cobyte2 小时前
11.响应式系统演进:深入剖析 computed 实现原理与性能优化实践(Vue3.3)
前端·javascript·vue.js
xmdy58662 小时前
Flutter + 开源鸿蒙跨端实战|基于空间地理信息的城市全域智慧泊车调度与多维运维管理平台 Day3
flutter·华为·开源
极梦网络无忧2 小时前
我开源了一个 Vue 3 动态表单组件库 —— real-vue3-easy-form
前端·vue.js·开源
恋猫de小郭2 小时前
2026 Android I/O ,全新 AI 手机、 Android PC 和自动驾驶
android·人工智能·智能手机
MXN_小南学前端2 小时前
Vue + Quill:富文本的添加、传输、展示逻辑,以及 csReplyQuill 组件封装
前端·vue.js
qq_381338502 小时前
Vue3 组合式函数设计模式:从基础封装到高级复用实战
前端·vue.js·设计模式