vue嵌套循环数组,选中其中某一项,添加选中的样式

本文介绍了Vue2中如何处理初始化数据的响应性,强调了$set方法在动态添加嵌套属性的重要性,并详细讲解了Vue对数组操作的检测规则,包括哪些方法会导致视图不更新。实例演示了如何正确使用$set来确保数据更新渲染。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

拓展:在一个组件实例中,只有在data里初始化的数据才是响应的,Vue2不能检测到对象属性的添加或删除,没有在data里声明的属性不是响应的。Vue不允许在已经创建的实例上动态添加根级响应式属性,但是可以使用$set方法将相应属性添加到嵌套的对象上。
数组数据变动,使用某些方法操作数组,变动数据时,有些方法无法被vue监测 push(),pop(),shift(),unshift(),splice(),sort(),reverse()可被vue检测到 filter(), concat(), slice()。这些不会改变原始数组,但总是返回一个新数组。当使用非变异方法时,可以用新数组替换旧数组。
vue2不能检测以下变动的数组:
1、当你利用索引直接设置一个项时,vm.items[indexOfItem] = newValue
2、当你修改数组的长度时,例如:vm.items.length = newLength

<template>  
   <div>        
      <div class="main" @click="open">            
         <text>点击</text>        
      </div>       
       <!-- 遮罩层 -->       
      <div class="mask" v-if="show" @touchmove.prevent.stop @click="close">
           <div class="screen" @touchmove.prevent.stop>            		                          
              <div class="screen-title">                 
                  <text class="screen-word">筛选</text>            
              </div>            
              <div v-for="(item,index) in skuNameList" :key="index">
                  <text class="condition">{{item.skuName}}</text>                              
              <div class="types" >                    
              <text class="time"  v-for="(a,b) in item.skuValues" :key="b" :class="[b == skuNameList[index].selectIndex ? 'bgc' : '']"    @click="selectTime(index,b)">{{a.name}}</text>                
              </div>            
           </div>            
           <div class="btn">              
               <text class="common" @click="reset">重置</text>              
               <text class="common sure" @click="confirm">确定</text>
           </div>         
        </div>       
     </div>  
   </div>
</template>
<script>
   import Light from "light";
   const modal = Light.requireModule("modal");
   export default {  
      data() {   
       return {     
           show: false,      
           skuNameList: [        
                         {          
                            id: "1",          
                            skuName: "颜色",          
                            skuValues: [
                                     { name: "红色", id: "1-1" }, 
                                     { name: "蓝色", id: "1-2" }
                                     ]        
                           },       
                           {          
                              id: "2",         
                              skuName: "尺寸",          
                              skuValues: [            
                              { name: "大", id: "2-1" },            
                              { name: "小", id: "2-2" },            
                              { name: "中", id: "2-3" }          
                                         ]        
                            },        
                            {          
                                id: "3",          
                                skuName: "风格",          
                                skuValues: [{ name: "波西米亚", id: "3-1" }]
                             } 
                        ],      
                        confirmList: []    
                      };  
                  }, 
              mounted() {    
              //页面加载给数据遍历添加selectIndex 属性
               this.skuNameList.forEach(element => {      
               element.selectIndex = -1;    
               }); 
             },  
             methods: {    
             // 打开弹窗    
             open() {      this.show = true;    },    
             //  关闭    
             close() {      this.show = false;      this.reset();    },    
             //选择    
             selectTime(index, b) {     
              // this.skuNameList[index].selectIndex = b;      
              //vue中修改了数组或对象某条数据的某个属性,数据变了,页面不渲染
                     var josn = this.skuNameList[index];      
                         josn.selectIndex = b;
                      this.$set(this.skuNameList, index, josn); 
                      //$set可以触发更新视图     
                       console.log(this.skuNameList);   
               },    
                 // 确定    
              confirm() {      
              this.confirmList = [];      
              this.skuNameList.map(item => {
                  item.skuValues.map((element, index) => {          
                     if (item.selectIndex == index) {
                           this.confirmList.push(element);         
                            }        
                      });      
               });      
                  console.log(this.confirmList);      
                if (this.confirmList.length == 0) {        
                  console.log("请选择筛选条件");        
                   return;      
                   }    
               },    
               // 重置    
               reset() {      
                   this.confirmList = [];      
                   this.skuNameList.map((item, index) => {
                           item.selectIndex = -1;
                           this.$set(this.skuNameList, index, item); //$set可以触发更新视图      
                    });      
                    console.log(this.skuNameList);    
                }  
       }
};
</script>
<style scoped>
.main {  margin-top: 200px;  margin-left: 100px;  width: 400px;  border-style: solid;  border-width: 1px;  border-color: #ccc;  height: 200px;  justify-content: center;  align-items: center;}
.mask {  position: fixed;  left: 0;  bottom: 0;  right: 0;  top: 0;  min-height: 100vh;  background-color: rgba(1, 1, 1, 0.5);}
.screen {  position: fixed;  left: 0;  right: 0;  bottom: 0px;  height: 600px;  background-color: #fff;  padding: 20px 20px 0px 20px;}
.screen-title {  align-items: center;  font-weight: 700;}
.condition {  font-weight: 700;  font-size: 28px;}
.types {  flex-direction: row;  flex-wrap: wrap;  padding: 10px;  width: calc(100% + 24px);}
.time {  width: 200px;  height: 50px;  text-align: center;  line-height: 50px;  font-size: 24px;  border-color: #ccc;  border-style: solid;  border-width: 1px;  margin-right: 20px;  margin-top: 10px;}
.bgc {  background-color: red;}
.btn {  position: fixed;  left: 0;  bottom: 0;  right: 0;  flex-direction: row;  justify-content: space-between;  height: 130px;  background-color: aquamarine;}
.common {  height: 130px;  line-height: 130px;  text-align: center;  background-color: #ccc;  flex: 1;}
.sure {  background-color: firebrick;  color: #fff;}
</style>
使用 Vue 3 和 JavaScript 实现一个类似 Ant Design (antd) 的树组件是一个非常有趣的项目。这个过程涉及创建一个能够递归渲染节点、处理展开/折叠以及选择操作等交互功能的自定义组件。 ### 步骤概述 #### 1. **设置基础环境** - 确保已经安装了 Vue CLI 或者 Vite 来快速搭建 Vue 3 项目。 ```bash npm install -g @vue/cli # 如果未安装VueCLI的话先装上它 vue create my-tree-component-project cd my-tree-component-project # 安装依赖库如axios或其他必要的工具包(如果需要) ``` #### 2. **设计数据模型** 你需要为每个节点定义结构化信息,比如 `id`, `title` (显示文本), 是否有子元素(`children`)及其状态 (`expanded`, `selected`)等等。 ```javascript const treeData = [ { id: '0-0', title: 'Parent Node', // 节点标题 children: [ { id: '0-0-0', title: 'Child Node 1' }, { id: '0-0-1', title: 'Child Node 2' } ], expanded: false, selected: false }, ]; ``` #### 3. **构建 Tree 组件** 接下来编写Tree.vue 文件,在其中实现核心逻辑: ##### 模板部分: 这里我们将利用 Vue 的 `<template>` 标签结合 JSX 或常规 HTML 创建视图,并通过 v-for 循环遍历节点数组生成 DOM 结构;同时添加事件监听器用于捕获用户的点击动作并触发相应的方法改变当前节点的状态属性值(expanded / selected). ```html <template> <div class="tree"> <ul style="padding-left: 0;"> <!-- 递归组件 --> <TreeNode :node="root" /> </ul> </div> </template> <script setup lang="ts"> import TreeNode from './TreeNode.vue'; // 假设这是根节点的数据源... defineProps<{ root?: any; }>(); </script> ``` 注意我们还导入了一个名为 `TreeNode.vue`的新文件作为单个节点项表示。这将允许我们的主列表只关注于顶级条目而让子级由其自身迭代管理。 ##### 子组件(`TreeNode.vue`) 此组件负责呈现单一节点及潜在嵌套层次下的所有后代成员. ```html <!-- TreeNode.vue --> <template> <li> <!-- 展开图标 + 文本内容 --> {{ node.title }} <!-- 若存在子集则有条件地展示它们 --> <transition name="expand"> <ul v-if="!isLeaf && isExpanded" > <TreeNode v-for="(childNode, index) in node.children" :key="index" :node="childNode"/> </ul> </transition> <!-- 添加一些基本样式来模拟“手风琴”效果... --> <style scoped> .expand-enter-active, .expand-leave-active { transition: max-height 0.5s ease-out; } .expand-enter-from, .expand-leave-to{ overflow:hidden; max-height: 0px; /* 开始时高度隐藏 */ } /* 其他样式规则略 */ </style> </li> </template> <script setup lang="ts"> defineProps<{ node: any; }>(); // 计算是否叶子结点 及 当前节点展开与否 const isLeaf = computed(() => !props.node?.children || props.node?.children.length === 0); const isExpanded = ref(false); function toggleExpand() { if (!isLeaf.value){ isExpanded.value=!isExpanded.value; } } onMounted(()=>{ console.log("mounted"); }); </script> ``` 在这个例子中,我简化了一些细节以保持清晰度,例如如何初始化默认选中的节点或者是更复杂的交互体验改进,你可以根据需求调整和完善这些特性。 #### 4. **增强用户体验和功能性** 可以考虑加入更多实用的功能,比如搜索过滤特定关键字匹配到的相关分支高亮显示,拖拽排序支持甚至右键菜单编辑选项等高级用法都会让你的作品更加出色! --- 以上就是基于 Vue 3 构建简易版 Antd 风格树形控件的基本流程说明啦~希望对你有所帮助!
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值