首页 > 其他分享 >条件组合组件--vue3版

条件组合组件--vue3版

时间:2024-07-25 10:52:52浏览次数:8  
标签:const -- props pos value current vue3 组件 data

参考

手把手教你写一个条件组合组件
此随笔是借鉴以上写的vue版,记录一下

组件

image

前期准备

1.vue3的全套工具
2.element-plus
3.lodash

数据结构

主要是嵌套结构

image

关键点

在RelationGroup组件内引用本身,注意key值,不能用i,不然删除操作,会从最后删起
image

组件结构

主要是这3个文件

image
image

引用

 <template>
  <div class="relation-tree">
    <RelationGroup pos="" :data="relations" @onTermChange="handleTermChange" > </RelationGroup>
  </div>
</template>
 <script setup>
import { onMounted, reactive, ref, defineExpose, toRaw } from 'vue'
import RelationGroup from './relationGroup'
import { getNewValue } from '@/utils/model'
const defaultRelation = {
  ops: 'and',
  children: [
    { key: 'Key1',flag:false, op: '>', value: 0 },
    {
      ops: 'or',
      children: [
        { key: 'Key2', flag:false,op: '<', value: 20 },
        { key: 'Key3',flag:true, op: '>', value: 10,units: 'bar'},
      ],
    },
  ],
}
const relations = ref(defaultRelation)
const handleTermChange = (e, pos,v) => {  //获取增删改查的数据
  relations.value = getNewValue(relations.value, pos, e, v)
}
</script>

model.js

必须深拷贝,不然会出错
/**
 * @param {object} data RelationTree 完整的 value
 * @param {string} pos 位置字符串,形如:0_0_1
 * @param {string} type 操作类型,如:addTerm, addGroup, changeOps(改变逻辑运算符 &&、||), changeTerm, deleteTerm
 * @param {string} record 变更的单项值
 */
import _ from 'lodash'
export const getNewValue = (data = {}, pos = '', type, record) => {
  const arrPos = getArrPos(pos)
  const last = arrPos.length - 1
  let draft = _.cloneDeep(data)
  if (type !== 'changeOps' && !pos) {
    draft.children.push(record)
    return draft
  }
  let prev = { data: draft, idx: 0 }
  // 暂存遍历到的当前条件组的数据
  let current = draft.children || []
  // 根据 pos 遍历数据,pos 中的每一个数字代表它所在条件组的序号
  arrPos.forEach((strIdx, i) => {
    const idx = Number(strIdx)
    if (i === last) {
      console.log('current', arrPos, current)
      switch (type) {
        case 'addTerm':
        case 'addGroup': // 加条件或条件组,添加操作需要多一层children
          current = (current[idx] && current[idx].children) || []
          current.push(record)
          break
        case 'deleteTerm': // 删除条件项
          current.splice(idx, 1)
          if (!current.length && Array.isArray(prev.data)) {
            prev.data.splice(prev.idx, 1)
          }
          break
        case 'changeOps': // 变更逻辑连接符
          current[idx][record.key] = record.value
          break
        default: // 变更条件项内容
          current[idx] = record
      }
    } else {
      // 将下一个条件组的数据复制到 current
      prev = { data: current, idx }
      current = (current[idx] && current[idx].children) || []
    }
  })
  //  })
  console.log('draft', draft)
  return draft
}

export const getArrPos = pos => {
  return (pos && pos.split(posSeparator)) || []
}

export const posSeparator = '_'

线样式


.relation-tree {
  .relation-group {
    .relational {
      width: 85px;
      padding: 0 4px 0 18px;
      margin: 16px 0;
      border-right: 1px solid #d9d9d9;
      display: flex;
      align-items: center;
    }

    .conditions {
      > div {
        position: relative;
        padding-top: 8px;
        &::before {
          content: '';
          display: inline-block;
          position: absolute;
          top: 50%;
          left: 0px;
          width: 16px;
          height: 1px;
          border-bottom: 1px solid #d9d9d9;
          background-color: #fff;
        }
        &:first-child {
          &::before {
            width: 16px;
            height: 24px;
            top: 0px;
            left: -1px;
            width: 20px;
          }
        }

        &.relation-group:before {
          top: 20px;
        }
        &:last-child {
          &::before {
            top: inherit;
            bottom: 15px;
            left: -20px;
            width: 17px;
            border-bottom: 0;
            border-top: 1px solid #d9d9d9;
          }
        }
      }
    }
  }
}

所有代码

relationGroup.vue

点击查看代码
<template>
  <div class="relation-group">
    <div class="relational">
      <type-select class="relation-sign" :dict="dict" v-model="value" @change="getChangePos"> </type-select>
    </div>
    <div class="conditions">
      <div v-for="(v, i) in children" :key="v">
       <RelationGroup
          v-if="v.children && v.children.length"
          :pos="getNewPos(i)"
          :data="v"
          @onTermChange="handleTermChange"
        >
        </RelationGroup>
        <RelationItem
          v-else
          :pos="getNewPos(i)"
          :data="v"
          @toDelete="toDelete"
          @getChange="getChange"
        >
       </RelationItem>
      </div>
      <div class="operators">
        <el-button plain class="add-term" @click="handleAddTerm('addTerm')">加条件</el-button>
        <el-button  plain class="add-group" @click="handleAddGroup('addGroup')">加条件组</el-button>
      </div>
    </div>
  </div>
</template>
<script setup>
import { onMounted, computed, ref, defineEmits, toRaw,reactive } from 'vue'
import RelationItem from './RelationItem'
import { posSeparator } from '@/utils/model'
const Gemit = defineEmits(['onTermChange']);
const props = defineProps({
  pos: {
    type: String,
    default: '',
  },
  data: {
    type: [Array,Object],
    default: () => {},
  },
})
onMounted(()=>{
console.log('props.data',props.data,props.data.children);
})
// const {children,ops}=reactive(props.data)
const children = computed(() => {
  return props.data.children;
});
const ops = computed(() => {
  return props.data.ops;
})
const defaultOpsValue = 'and'
const relationValue = ops.value || defaultOpsValue
const value=ref(relationValue)
const getNewPos = (i) => {
  // 如果当前项是整个 value (即组件的起始项)时,新位置即当前序号
  return props.pos?`${props.pos}${posSeparator}${i}`:String(i)
}
const dict = [
  { label: '且', value: 'and' },
  { label: '或', value: 'or' },
]
const record = { key: '', op: '', value: '' }
const group = {
  ops: 'and',
  children: [{ key: '', op: '', value: '' }]
}
const handleAddTerm=(e)=>{
  Gemit('onTermChange',e, props.pos,record)
}
const handleAddGroup=(e)=>{
  Gemit('onTermChange',e, props.pos,group)
}
const handleTermChange=(e,pos,v)=>{
  Gemit('onTermChange',e, pos,v)
}
const getChangePos=(e)=>{
 Gemit('onTermChange', 'changeOps', props.pos,{key:'ops',value:e})
}
const toDelete=(pos)=>{
  Gemit('onTermChange', 'deleteTerm', pos,'')
}
const getChange=(e,pos)=>{
  Gemit('onTermChange', 'changeTerm', pos,e )
}
</script>
<style lang="scss" scoped>
.relation-group{
    display: flex;
}
.operators{
    margin-left: 20px;
}

</style>

relationItem.vue

type-select 是自己写的一个通用选择组件,换成el-select就可以
点击查看代码
<template>
  <div class="relation-item">
    <div class="term">
      <span class="element">
        <type-select
          placeholder="请选择条件项"
          v-model="termvalue.key"
          :dict="Edict"
          @change="getChange"
        >
        </type-select>
      </span>
      <span class="comparison">
        <type-select placeholder="请选择关系符" v-model="termvalue.op" :dict="Cdict" @change="getChange">
        </type-select>
      </span>
      <span>
        <el-switch v-model="termvalue.flag" inline-prompt active-text="数值" inactive-text="条件"/>
      </span>
      <span class="value" v-if="termvalue.flag">
        <el-input-number
          v-model="termvalue.value"
          class="mx-4"
          :min="1"
          controls-position="right"
          style="width: 80px"
          @change="getChange"
        />
        <type-select
          placeholder="单位"
          v-model="termvalue.units"
          :dict="Unitsdict"
          style="width: 80px"
          @change="getChange"
        >
        </type-select>
      </span>
      <span class="value" v-else>
        <el-input placeholder="请输入条件值" v-model="termvalue.valueKey" style="width: 80px" @change="getChange" />
      </span>
    </div>
    <el-button plain class="delete-term" @click="toDelete"> 删除 </el-button>
  </div>
</template>
<script setup>
import { onMounted, reactive, ref, defineEmits, toRaw } from 'vue'
const Demit = defineEmits(['toDelete','getChange'])
const props = defineProps({
  pos: {
    type: String,
    default: '',
  },
  data: {
    type: [Array, Object],
    default: () => {},
  },
})
const { key, op, value,valueKey, flag, units } = reactive(props.data)
const termvalue = reactive({
  key: key,
  op: op,
  flag:flag??false,
  value: value,
  valueKey: valueKey,
  units: units,
})
const Cdict = [
  { label: '等于', value: '==' },
  { label: '不等于', value: '!=' },
  { label: '大于', value: '>' },
  { label: '小于', value: '<' },
  { label: '大于等于', value: '>=' },
  { label: '小于等于', value: '<=' },
]
const Edict = [
  { label: 'Key1', value: 'Key1' },
  { label: 'Key2', value: 'Key2' },
  { label: 'Key3', value: 'Key3' },
]
const Unitsdict = [
  { label: 'Key1', value: 'Key1' },
  { label: 'Key2', value: 'Key2' },
  { label: 'Key3', value: 'Key3' },
]
const toDelete = () => {
  Demit('toDelete', props.pos)
}
const getChange = () => {
  Demit('getChange',termvalue,props.pos)
}
</script>
<style lang="scss" scoped>
.relation-item {
  display: flex;
  margin-left: 20px;
}
.term {
  display: flex;
  > span {
    margin-right: 2px;
  }
}
.value {
  display: flex;
  > div {
    margin-left: 2px;
  }
}
.element {
  width: 100px;
}
.comparison {
  width: 80px;
}
</style>

标签:const,--,props,pos,value,current,vue3,组件,data
From: https://www.cnblogs.com/yun10011/p/18322475

相关文章

  • 六西格玛方法
    六西格玛方法涵盖了多种工具和技术,用于帮助组织通过减少变异性和提高过程效率来达到质量改进的目标。以下是一些常用的六西格玛工具和技术:DMAIC方法:DMAIC是六西格玛项目的核心方法论,包括以下步骤:Define(定义):确定项目的关键目标和客户需求。Measure(测量):量化当前过程的性能水......
  • Codeforces 929 div3 D
    题目:D.TurtleTenacity:ContinualMods题目链接:https://codeforces.com/contest/1933/problem/D算法:数论、贪心。一开始没思路,后面看了别人的题解才搞懂的。思路:1.将原数组a从大到小排序后可以得到的数组b有两种情况。一种是b0!=b1,另一种则是b0=b1(下标从0开始)。对于第一......
  • 代码随想录算法训练营第43天 | 动态规划7:买卖股票
    121.买卖股票的最佳时机https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/description/代码随想录https://programmercarl.com/0121.买卖股票的最佳时机.html#算法公开课and-sell-stock/description/122.买卖股票的最佳时机IIhttps://leetcode.cn/problems/be......
  • Django get_or_create和update_or_create 的作用和使用
    Djangoget_or_create和update_or_create的作用和使用:get_or_create和update_or_create是Django中的两个有用的方法,用于在数据库中获取或创建记录。如果记录不存在,则创建它们;如果存在,则返回现有记录。这两个方法帮助简化了避免重复记录的逻辑,并提供了一种简洁的方法来更新......
  • 所见即所得,赋能RAG:PDF解析里的段落识别
    前几天,有一位用户使用OCR产品识别多栏论文后向我们询问:要怎么解决不合适的断句、分段以及错误阅读顺序的问题?我们用一个相似案例为大家直观展示这位用户遇到的情况。 如图中的多栏期刊,如果用OCR识别,或直接在一些办公软件对文字进行复制黏贴,我们就会得到右侧的效果——按PDF排......
  • 「杂题乱刷2」P3107
    题目链接P3107[USACO14OPEN]OdometerS解题思路数位dp模板。令某个数的特殊数字为在一个数字中至少出现过一半的数位的数字。首先我们可以依次拆分数位来枚举当某个数位为特殊数字时来进行数位dp,状态为\(dp_{last,len,num,sum,\_1,\_0}\)来代表还剩余\(last\)个数位......
  • 如何在Python中对轮廓图应用点画?
    我想向XarrayDataArray数据添加点画以指示重要性。该数据是经纬度网格上的二维气候数据。我想提供一个True/False掩码来绘制映射的变量数据。我正在尝试使用contourf来达到此目的,但如果它们更合适,我愿意接受其他方法。我尝试过使用contourf孵化点画重要区域,但......
  • Team - 协同工具Jira
    Jira官网信息Jira简介https://www.atlassian.com/zh/software/jira/guides/getting-started/introductionJira入门教程:6个基本步骤https://www.atlassian.com/zh/software/jira/guides/getting-started/basics视频教程敏捷必备工具Jira&Confluence使用http://ww......
  • 题解:Codeforces Round 961 (Div. 2) A
    A.Diagonals*timelimitpertest:1secondmemorylimitpertest:256megabytesinput:standardinputoutput:standardoutputVitaly503isgivenacheckeredboardwithasideof\(n\)and\(k\)chips.Herealizedthatallthese\(k\)chipsneedto......
  • 代码随想录算法训练营第42天 | 动态规划7:打家劫舍入门
    打家劫舍https://leetcode.cn/problems/house-robber/description/代码随想录https://programmercarl.com/0198.打家劫舍.html打家劫舍-环形https://leetcode.cn/problems/house-robber-ii/description/代码随想录https://programmercarl.com/0213.打家劫舍II.html#思路......