vue循环渲染动态展示内容案例(“更多”按钮功能)

当我们在网页浏览时,常常会有以下情况:要展示的内容太多,但展示空间有限,比如我们要在页面的一部分空间中展示较多的内容放不下,通常会有两种解决方式:分页,“更多”按钮

今天我们的案例用于更多按钮的功能实现。

比如我们要展示这样的效果:

fedc8924d64147ae87b68518cc7467d4.png

红框框是我们要展示的内容,当我们点击更多时,就会依次排列更多的红色框框。

 比如我们有这样一些内容要展示:

const newCourseList = ref([
  {id:"1",name:"英特尔实时计算中级课程",type:"",videoNum:"10",studyNum:"5946",imgUrl:"src/assets/images/newcourse/newcourse1.png"},
  {id:"2",name:"英特尔实时计算初级课程",type:"",videoNum:"10",studyNum:"6682",imgUrl:"src/assets/images/newcourse/newcourse2.png"},
  {id:"3",name:"OpenCV高级认证课程",type:"",videoNum:"10",studyNum:"8963",imgUrl:"src/assets/images/newcourse/newcourse3.jpg"},
  {id:"4",name:"OpenCV初级认证课程",type:"",videoNum:"10",studyNum:"5869",imgUrl:"src/assets/images/newcourse/newcourse4.jpg"},
  {id:"5",name:"英特尔® OpenVINO™工具套件初级课程——2024焕新版",type:"",videoNum:"10",studyNum:"5869",imgUrl:"src/assets/images/newcourse/newcourse5.jpg"},
  {id:"6",name:"英特尔® OpenVINO™工具套件中级课程",type:"",videoNum:"10",studyNum:"5869",imgUrl:"src/assets/images/newcourse/newcourse6.png"},
  {id:"7",name:"英特尔® OpenVINO™工具套件高级课程",type:"",videoNum:"10",studyNum:"5869",imgUrl:"src/assets/images/newcourse/newcourse7.jpg"},
  {id:"8",name:"英特尔® Smart Edge Open初级认证课程",type:"",videoNum:"10",studyNum:"5869",imgUrl:"src/assets/images/newcourse/newcourse8.png"},
  {id:"9",name:"1",type:"",videoNum:"10",studyNum:"5869",imgUrl:"src/assets/images/newcourse/newcourse8.png"},
  {id:"10",name:"2",type:"",videoNum:"10",studyNum:"5869",imgUrl:"src/assets/images/newcourse/newcourse8.png"},
  {id:"11",name:"3",type:"",videoNum:"10",studyNum:"5869",imgUrl:"src/assets/images/newcourse/newcourse8.png"},
  {id:"12",name:"4",type:"",videoNum:"10",studyNum:"5869",imgUrl:"src/assets/images/newcourse/newcourse8.png"},
  {id:"13",name:"5",type:"",videoNum:"10",studyNum:"5869",imgUrl:"src/assets/images/newcourse/newcourse8.png"},
  {id:"14",name:"6",type:"",videoNum:"10",studyNum:"5869",imgUrl:"src/assets/images/newcourse/newcourse8.png"},
  {id:"15",name:"7",type:"",videoNum:"10",studyNum:"5869",imgUrl:"src/assets/images/newcourse/newcourse8.png"},
  {id:"16",name:"8",type:"",videoNum:"10",studyNum:"5869",imgUrl:"src/assets/images/newcourse/newcourse8.png"},
])

一共16条数据,但是我们最初始要展示七条数据,当单击一次更多按钮要展示13条数据。也就是每次单击都再展示6条数据。

首先我们要对布局分析,我们可以将整个布局看成一行,左边第一个元素独占一列。右边的其他元素可以占整体一个列,然后再分行分列。这里我们用到elementui中的格子模式,每行占24个格子。整体看,每行有4个元素。比如第一个元素我们给6个格子。那么其他位置我们需要每行展示3个元素,后边自己分一行就又是24个格子,三个元素,每个元素8个格子。

我们要确定,前七条数据先怎么展示出来,这里有个问题就是第一个框框的大小跟其他的不一样,而且第一个一直就是那唯一的一个,所以我们就不将第一个元素写在循环渲染内,除了第一个,其他都用循环写。

那么第一个元素我们可以这样写:

<el-row :span="24" style="width: 1240px;margin: 0px auto;" :gutter="15">
        <el-col :span="6">  
          <div style="height: 530px;width: 100%;background-color: #fff;border-radius: 5px;margin-bottom:10px;">
          <RouterLink :to="`/course/coursecontent/${newCourseList[0].id}`">
            <img style="width: 100%;height: 400px;border-radius: 5px 5px 0px 0px;" v-img-lazy="newCourseList[0].imgUrl" alt="" />
            <div>
              <div style="padding: 20px; font-size: 16px;font-family: PingFangSC-Regular, sans-serif;text-overflow: ellipsis;white-space: nowrap;overflow: hidden;">{{ newCourseList[0].name }}</div>
              <div style="font-size: 12px;margin-left: 20px;" >
                <el-icon size="20" style="position:relative;top:5px;margin: 0 5px 0 0px">
                  <VideoCamera/>
                </el-icon>
                <span>{{newCourseList[0].videoNum}}</span>
              </div>
            </div>
          </RouterLink>
        </div>
      </el-col>
<el-row>

说明:el-row是elementui中的行元素代表一个行,el-col代表一个列,:span后面是代表这个行/列占得格子数。

newCourseList的第一个元素也就是newCourseList[0],打点调用每条数据中的内容。上述代码就将第一个元素展示出来了。

其他元素我们就需要用到循环渲染了

因为第一个元素占了6个格子,后面其他元素一起占一列,那就是18个格子。内部再分行,那么每行又是24个格子,所以一个元素是8个格子。


      <el-col :span="18">
        <el-row :span="24">
          <el-col :span="8" v-for="course in newCourseList" :key="course.id">
            <div style="height: 256px;width: 100%;background-color: #fff;border-radius: 5px;margin-bottom:10px;">
          <RouterLink :to="`/course/coursecontent/${course.id}`">
            <img style="width: 100%;height: 160px;border-radius: 5px 5px 0px 0px;" v-img-lazy="course.imgUrl" alt="" />
            <div>
              <div style="padding: 20px; font-size: 16px;font-family: PingFangSC-Regular, sans-serif;text-overflow: ellipsis;white-space: nowrap;overflow: hidden;">{{ course.name }}</div>
              <div style="font-size: 12px;margin-left: 20px;" >
                <el-icon size="20" style="position:relative;top:5px;margin: 0 5px 0 0px">
                  <VideoCamera/>
                </el-icon>
                <span>{{course.videoNum}}</span>
              </div>
            </div>
          </RouterLink>
        </div></el-col>
         
        </el-row>
       
      </el-col>

我们在内部列中使用了循环渲染,这样实现了显示的功能,但是有个问题:这样写右侧不会只显示6个元素,而是将所有数据展示出来。

为了解决这个问题我们可以建立一个新对象,来装我们要展示的六条数据,然后去循环展示这个新对象,注意:循环时是从第二条数据开始的,因为第一条数据不参与循环。

创建对象:

const listCopy=ref(newCourseList.value.slice(1,7))

上述代码我们创建了一个对象listCopy,初始值用来装newCourseList的下标值为1-6的数据。

修改后的代码

<el-col :span="18">
        <el-row :span="24">
          <el-col :span="8" v-for="course in listCopy" :key="course.id">
            <div style="height: 256px;width: 100%;background-color: #fff;border-radius: 5px;margin-bottom:10px;">
          <RouterLink :to="`/course/coursecontent/${course.id}`">
            <img style="width: 100%;height: 160px;border-radius: 5px 5px 0px 0px;" v-img-lazy="course.imgUrl" alt="" />
            <div>
              <div style="padding: 20px; font-size: 16px;font-family: PingFangSC-Regular, sans-serif;text-overflow: ellipsis;white-space: nowrap;overflow: hidden;">{{ course.name }}</div>
              <div style="font-size: 12px;margin-left: 20px;" >
                <el-icon size="20" style="position:relative;top:5px;margin: 0 5px 0 0px">
                  <VideoCamera/>
                </el-icon>
                <span>{{course.videoNum}}</span>
              </div>
            </div>
          </RouterLink>
        </div></el-col>
         
        </el-row>
       
      </el-col>

接下来又有一个问题,就是怎么在单击“更多”时,多展示六条数据。

我们可以为“更多”设置一个单击事件,然后触发一个函数修改被循环的对象:listCopy的值。

<el-row style="background-color:#f6f8fb; height: 150px;" justify="center" align="middle" type="flex">
      <div style="width:200px;background: transparent;border: 1px solid #999;color: #999;text-align: center;font-size: 12px;padding: 18px 75px;border-radius: 4px;" @click="changeList()">更多竞赛</div>
  </el-row>

我设置了名为changeList的函数。

接下来我们需要考虑两种情况:

1、剩余数据大于6条,2、剩余数据不足6条

第一种情况,我们需要控制listCopy的数据只增加6条。

第二种情况,剩余几条增加几条就可以。

函数内部代码:

const changeList=()=>{
  let count=listCopy.value.length+1;
  let maxCount=newCourseList.value.length-1;
  let sub=maxCount-count>6?6:maxCount-count;

  for(let i=0;i<sub;i++){
    listCopy.value.push(newCourseList.value[count+i])
  }
  
}

说明:count变量用来装我们需要newCourseList的哪个下标值开始增加给listCopy。maxCount用来装剩余数据的最大下标值sub用来装我们要追加几条数据:如果大于6,sub就是6,如果不大于6就是剩余数据的最大下标值减去从哪个下标值开始,也就是还剩几条。

for循环就是对listCopy对象的数值进行追加。

例如第一次:count的值为7,也就是从id为8的数据开始追加给listCopy。maxCount值为15,一共16条,最大下标值为15。sub值为6,因为maxCount-count=15-7=8,8>6所以sub的值为6。那么for循环将执行6次。第一次向listCopy中push:newCourseList下标值为7的数据,第二次是newCourseList下标值为8的数据。

这样我们就实现了最初的功能。

页面效果:f2becdded46d4ac2ab11af66457f1832.png

单击一次:

 192a5de88761434f9a1156491eebaed9.png

单击两次:

953b3e6ff16741fd87a31574c0f9af0a.png

<think>嗯,用户想了解Vue图书管理系统购物车案例。首先,我需要整理这个案例的基本组成部分。Vue通常用于前端开发,所以购物车功能应该包括添加图书、显示列表、数量增减、总价计算和删除功能。可能需要组件化结构,比如图书列表组件和购物车组件。数据管理方面,可能需要Vuex来管理状态,或者使用组件间的通信。 接下来,用户可能需要具体的实现步骤。比如,如何设计数据结构,图书对象可能有id、名称、价格、库存等属性。购物车项可能包括图书id、数量。然后,需要处理添加商品到购物车的逻辑,检查是否已存在,库存是否足够。 然后,前端展示部分,使用v-for循环渲染购物车列表,每个项有增减按钮,绑定点击事件,调用对应的方法修改数量。总价计算可以用计算属性,遍历购物车项累加价格乘以数量。删除功能则是从购物车数组中移除对应项。 还要考虑数据持久化的问题,比如使用localStorage来保存购物车状态,防止页面刷新后数据丢失。或者,如果与后端交互,可能需要调用API接口,这里可能需要异步处理。 用户可能还希望看到代码示例,比如模板部分的结构,数据、方法、计算属性的写法。比如使用Vue3的组合式API,setup函数,ref和reactive的使用。或者使用选项式API,根据用户的熟悉程度来决定。 另外,需要注意的一些细节,比如库存不足时的提示,数量不能低于1,删除前的确认提示等用户体验方面的优化。还有样式设计,如何用CSS美化购物车界面,使其看起来更友好。 最后,可能会提到常见的功能扩展,比如优惠券应用、结算功能、路由跳转到结算页面等。但核心是购物车的基本功能实现。需要确保代码结构清晰,可维护,遵循Vue的最佳实践,比如单向数据流,合理的组件拆分等。</think>以下是一个基于 Vue.js 的图书管理系统购物车案例实现思路(使用 Vue 3 组合式 API 演示): ```html <!-- 图书列表组件 --> <template> <div class="book-list"> <div v-for="book in books" :key="book.id" class="book-item"> <h3>{{ book.title }}</h3> <p>价格:¥{{ book.price }}</p> <button @click="addToCart(book)">加入购物车</button> </div> </div> </template> <script setup> import { ref } from 'vue'; import { useCartStore } from '@/stores/cart'; const cartStore = useCartStore(); const books = ref([ { id: 1, title: 'Vue.js实战', price: 68, stock: 10 }, { id: 2, title: 'JavaScript高级编程', price: 99, stock: 5 }, // 更多图书数据... ]); const addToCart = (book) => { if (book.stock > 0) { cartStore.addItem(book); book.stock--; } else { alert('库存不足!'); } }; </script> ``` ```html <!-- 购物车组件 --> <template> <div class="cart"> <h2>购物车 ({{ totalItems }})</h2> <div v-for="item in cartItems" :key="item.id" class="cart-item"> <span>{{ item.title }}</span> <div class="quantity-control"> <button @click="decrement(item)">-</button> <input type="number" v-model.number="item.quantity" min="1" /> <button @click="increment(item)">+</button> </div> <span>¥{{ item.price * item.quantity }}</span> <button @click="removeItem(item)">删除</button> </div> <div class="total">总价:¥{{ totalPrice }}</div> <button @click="checkout">去结算</button> </div> </template> <script setup> import { computed } from 'vue'; import { useCartStore } from '@/stores/cart'; const cartStore = useCartStore(); const cartItems = computed(() => cartStore.items); const totalItems = computed(() => cartStore.totalItems); const totalPrice = computed(() => cartStore.totalPrice); const increment = (item) => cartStore.updateQuantity(item, 1); const decrement = (item) => cartStore.updateQuantity(item, -1); const removeItem = (item) => cartStore.removeItem(item); const checkout = () => { // 结算逻辑... }; </script> ``` **核心实现要点:** 1. **状态管理(推荐 Pinia)** ```javascript // stores/cart.js import { defineStore } from 'pinia'; export const useCartStore = defineStore('cart', { state: () => ({ items: [] }), actions: { addItem(book) { const existing = this.items.find(item => item.id === book.id); existing ? existing.quantity++ : this.items.push({ ...book, quantity: 1 }); }, updateQuantity(item, delta) { item.quantity = Math.max(1, item.quantity + delta); }, removeItem(item) { this.items = this.items.filter(i => i.id !== item.id); } }, getters: { totalItems: (state) => state.items.reduce((sum, item) => sum + item.quantity, 0), totalPrice: (state) => state.items.reduce((sum, item) => sum + (item.price * item.quantity), 0) } }); ``` 2. **关键功能实现** - 图书库存验证 - 购物车商品数量增减(最小值为1) - 实时计算总价和总数 - 数据持久化(可选 localStorage) 3. **扩展功能建议** - 添加优惠券/折扣功能 - 购物车本地存储持久化 - 结算页面路由跳转 - 后端 API 集成(Axios) 4. **样式建议** - 使用 Flex/Grid 布局实现响应式设计 - 添加过渡动画提升用户体验 - 库存不足时的视觉提示 这个案例展示Vue 的核心特性: - 组件化开发 - 响应式数据绑定 - 状态管理(Pinia) - 计算属性 - 事件处理 - 条件渲染和列表渲染 实际开发中需要根据具体需求添加表单验证、错误处理、Loading状态等交互优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值