Bootstrap

SPC项目总结(树形结构/正态分布/杂碎知识点)

一、树形结构(< el-tree>< /el-tree>)

如下。详细情况查看链接(vue-elementui)

在这里插入图片描述

1.数组转树形

最开始 使用树形结构,是获取全部数据,然后将数组转为树形结构([{id:'',children[id:"",children:[]]}])。

const data=[
{partentId: "0",name: "Luxsan2", id: "271665283503099904"},
{partentId: "0",name: "A5",id: "261142640031043584"},
{partentId: "261142640031043584",name: "A5-1",id: "261142640031043586"},
{partentId: "261142640031043586",name: "A5-1-1",id: "261142640031043589"}
]
 // 数组转树形
    toTree (data) {
      let treeData = [];
      if (!Array.isArray(data)) return treeData;
      let map = {};
      data.forEach(item => {
        map[item.id] = item;
      });
      data.forEach(item => {
        let parent = map[item?.partentId || item.folderId];  //判断item的partentId是否是否存在map中
        if (item.partentId === '0') {
          treeData.push(item)  // 如果为0 则是顶层数据
        }
        if (parent) {
          item.partentIdname = map[item?.partentId || item.folderId].name;
          (parent.children || (parent.children = [])).push(item)
        }   //如果存在则表示item不是最顶层的数据
      });
      return treeData;
    },

2.懒加载(推荐)

后来 使用 :load="loadNode" lazy 来实现树形结构的懒加载 。
目的:是为了当树形结构数据量很大的时候,防止加载很慢
推荐使用懒加载

<el-tree :data="data" node-key="id" 
:load="loadNode" lazy 
:default-expanded-keys="[currentKey]"
 :current-node-key="currentKey" 
 :filter-node-method="filterNode" 
 :props="defaultProps"
  ref='tree' 
  highlight-current 
  @node-click="nodeClick">
 //懒加载节点
    loadNode (node, resolve) {
      switch (node.data.remark) {
        case 'mpc':
          getMpcDefList({ enabled: 1, folderId: node.data.id, partentId: "0" }).then(res => { return resolve(res.result); });
          break;
        case 'spc':
          getEntityListSpcChannelDef({ enabled: 1, folderId: node.data.id }).then(res => { return resolve(res.result); })
          break;
        default:
          getEntityListSpcFolder({ enabled: 1, partentId: node.data?.id || "0" }).then(res => { return resolve(res.result); })
      }
    },

3.刷新树节点

//获取创建的目录树
refreshNodeBy (id) {
  let node = this.$refs.tree.getNode(id);
  //node 有值 ....
  if (node) {
    node.loaded = false;
    node.expand(); // 主动调用展开节点方法,重新查询该节点下的所有子节点
  }
},

4.刷新最外层节点(不使用window.reload方法进行无感刷新)

因为没有办法使用refreshNodeBy 方法,所以决定刷新整个页面
原因:refreshNodeBy 是刷新子节点的,由于最外层节点没有没有父节点,所以自己没办法刷新。所以决定刷新整个页面。

不使用window.reload方法进行无感刷新
1.进入App.vue
在这里插入图片描述
在这里插入图片描述
2.进入要刷新的页面

成对出现provideinject是成对出现的
作用:用于父组件向子孙组件传递数据
使用方法provide在父组件中返回要传给下级的数据,inject在需要使用这个数据的子辈组件或者孙辈等下级组件中注入数据。
使用场景:由于vue有$parent属性可以让子组件访问父组件。但孙组件想要访问祖先组件就比较困难。通过provide/inject可以轻松实现跨级访问父组件的数据

在这里插入图片描述
使用:this.reload()即可

5.自定义树节点高亮

节点刷新后,先前选中的树节点高亮消失。会忘记前面user的操作。
所以:进行重新设定选中数据–树节点高亮。需设定属性如下:
node-key="id" :current-node-key="currentKey" :default-expanded-keys="[currentKey]" highlight-current

this.$nextTick(() => {
    this.currentKey = this.paramData?.id || '';//获取需要高亮的id进行赋值
    this.$refs.tree?.setCurrentKey(this.currentKey);
})

6.树形控件样式

右侧红色部分 ,当树节点部分需要的操作多的时候,用下拉框<el-dropdown>进行设定

在这里插入图片描述

使用事件 command --点击菜单项触发的事件回调 dropdown-item 的指令

<el-tree :data="data">
<div class="custom-tree-node" slot-scope="{ node, data }" style="width:100%">
   <span class="tree-label">
     <i class="el-icon-folder"></i>
     {{ node.label }}
   </span>
   <span class="tree-icon">
     <el-dropdown @command="handleCommand" szie="mini" v-if="!data.folderId">
       <span class="el-dropdown-link">
         <i class="el-icon-arrow-down"></i>
       </span>
       <el-dropdown-menu slot="dropdown">
         <el-dropdown-item :command="{data:data,value:'ldsfolder'}">新建 LDS文件夹</el-dropdown-item>
       </el-dropdown-menu>
     </el-dropdown>
   </span>
 </div>
</el-tree>

二、正态分布图

组成部分是由 正态分布图+直方图。
正态分布图逻辑:正常情况—x:数据;y:概率密度(因为我的是倒着的,所以取反就好)
直方图逻辑:确定组数和组距,得到某个区间内数值个数

1.正态分布图

在这里插入图片描述
1.概率密度计算
[在这里插入图片描述](https://img-blog.csdnimg.cn/b8d2590f3153496eb54265693fd32ade.png)

//正态分布数据 
normalDistribution (value) {
  let res = []; // 正态分布数据
  //原始值排序
  let result = value.sort((x, y) => x - y);
  //   标准差
  //  1.求平均值
  let sum = value.reduce((prev, curr) => prev + curr);
  const avg = sum / value.length
  //2.返回偏差。 f(x) = x - avg
  const dev = value.map(x => x - avg);
  //3.求偏差平方和 
  const sumOfSquOfDev = dev.map(x => x * x).reduce((x, y) => x + y);
  // 4.返回方差
  const variance = sumOfSquOfDev / (value.length - 1)
  //5.开根号获取标准差
  const stdev = Math.sqrt(variance)
  result.forEach(i => {
    let a = 1 / (Math.sqrt(2 * Math.PI) * stdev);
    let b = Math.pow(Math.E, -(Math.pow(i - avg, 2) / (2 * Math.pow(stdev, 2))));
    const fx = a * b;
    res.push([fx, i]);//fx:概率密度,i:数值
  });
  return res
},
//series内部
 {
  name: '正态分布', // y 轴名称
   type: 'line', // y 轴类型
   symbol: 'none', //去掉折线图中的节点
   smooth: true, //true 为平滑曲线
   data: normalDistribution, // y 轴数据 -- 正态分布
   xAxisIndex: 1,
   yAxisIndex: 0,
 },

2.直方图

 //直方图数据
histogram (value, key) {
  let res = [];
  const min = Math.min.apply(null, value);//获取数据最小 最大值
  const max = Math.max.apply(null, value);
  //   组数K
  let k = Math.ceil(1 + Math.log10(value.length) / Math.log10(2));
  // 组距
  let r = (max - min) / k;
  for (let i = min - r; i <= max + r; i = i + r) {
    let count = 0;
    value.forEach(element => {
      if (element >= i && element < i + r) {
        count += 1;
      }
    });
    // count 不为0 [x起始位置,x结束位置,y结束位置,y起始位置]
    if (count) res.push([0, count, i + r, i]);
  }
  return res;
},

直方图的实现是利用echarts 的自定义图形实现

//series内部
{
	name: '直方图',
	// type: 'bar',
	type: 'custom',
	renderItem: function (params, api) {
	  // params 坐标系信息及数据信息,api 方法信息
	  //例:0,2,-25,-32----x1,x2,y1,y2               
	  let coord = api.coord([api.value(0), api.value(2)]);
	  //api.size([2, 4]) 返回 [12.4, 55],表示 x 轴数据范围为 2 映射得到长度是 12.4,y 轴数据范围为 4 时应设得到长度为 55。
	  let size = api.size([api.value(1), api.value(2) - api.value(3)]);
	  let style = api.style();
	  const res = {
	    type: 'rect',
	    shape: {
	      x: coord[0],//coord[0] 指x的像素起始位置
	      y: coord[1],//coord[1] 指y的像素起始位置
	      width: size[0],//size[0] 指x的长度
	      height: size[1],//size[1] 指y的长度
	    },
	    style: style
	  };
	  return res
	},
	label: {
	  show: true,
	  rotate: -90,
	  // position: 'top'
	  formatter: function (data) {
	    return data.data[1]
	  }
	},
	dimensions: ['start', 'profit', 'from', 'to'],
	encode: {
	  x: [0, 1],
	  y: [2, 3],
	  tooltip: [0, 1, 2, 3],
	  itemName: 1
	},
	data: histogram,
	xAxisIndex: 0,
	yAxisIndex: 0,
	markLine: markLine
	}

三、杂碎知识点

1.子组件调用父组件方法

  <!--父组件-->
  <lds-folder-setting  @changeChannelSetting='changeChannelSetting' />
 //子组件
  this.$emit('changeChannelSetting');

2.父组件调用子组件方法

使用穿梭框时为了获取到值。由于提交按钮是在父组件,所以需要在提交之前获取到穿梭框的值
原因: 穿梭框的v-model 绑定值不能用父组件parmasData.sync绑定。报异常Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "paramData"
总结:不能修改或者说双向绑定来自父组件的数据

<!--父组件-->
<spc-rule-setting  ref='spcrule' />
//调用
this.$refs.spcrule.changKey();
//子组件内部方法
changKey () {
  let tempArr = [];
  this.keyRelations_.forEach(item => {
    this.keyRelationsList.forEach(element => {
      if (item === element.keyName) {
        const { keyName, keyValue, sortCode } = element
        tempArr.push({ keyName, keyValue, enabled: 1, sortCode });
      }
    })
  })
  //修改父组件keyRelations值
  this.$emit('update:keyRelations', tempArr);
},

3.form表单自校验必填

:rules="ruleValidate" :model="paramData" ref="paramData" prop="name"

<el-form class="top-check clearFix" :model="paramData" ref="paramData" label-width="80px" size="mini" :rules="ruleValidate">
	 <el-form-item label="Name" prop="name">
         <el-input type="text" v-model="paramData.name"></el-input>
       </el-form-item>
</el-form>
 data(){
	 return {
		 // 验证实体
		  ruleValidate: {
		    name: [
		      { required: true, message: 'Name is Required' }
		    ],
		  },
	 }
 }
 //方法内部校验
 commit(){
   this.$refs.paramData.validate((valid) => {
        if (valid) {
        }
    })
}

4.两个数组合并(concat)

result.concat(settingResult)

const result =[1,2,3];
const settingResult=[4,5,6]
console.log(result.concat(settingResult));//[1,2,3,4,5,6]

5.数组sort排序

sort() 方法用于对数组的元素进行排序。排序顺序可以是字母或数字,并按升序或降序。默认排序顺序为按字母升序。
注意:当数字是按字母顺序排列时"40"将排在"5"前面。使用数字排序,你必须通过一个函数作为参数来调用。函数指定数字是按照升序还是降序排列。

返回值----Array----请注意,数组在原数组上进行排序,不生成副本。
在这里插入图片描述
在这里插入图片描述

this.keyRelationsList.sort((x, y) => {
  return x.id > y.id ? 1 : -1
})

6.判断是否为数组类型

1.intenanceof

const temp =[];
console.log(temp typeof Array);//false;
console.log(temp typeof Object);//true;
console.log(temp instanceof Array);//true;
console.log(temp instanceof Object);//true;
//以上  因为Array是Object的字类
const temp ={};
console.log(temp typeof Array);//true;
console.log(temp typeof Object);//true;
console.log(temp instanceof Array);//false;
console.log(temp instanceof Object);//true;

instanceof 与typeof 的区别
instanceof和typeof是两个运算符。
在程序设计中用到,常用来判断一个变量是否为空,或者是什么类型的。

typeof是一个一元运算,放在一个运算数之前,运算数可以是任意类型。
返回值是一个字符串,该字符串说明运算数的类型。
typeof 一般只能返回如下几个结果:number,boolean,string,function,object,undefined。一般可以使用 typeof 来获取一个变量是否存在。
if(typeof a!="undefined"){alert("ok")},而不要去使用 if(a) 因为如果 a 不存在(未声明)则会出错。
对于 Array,Null 等特殊对象使用 typeof 一律返回 object,这正是 typeof 的局限性。

instanceof 用于判断一个变量是否某个对象的实例。

a instanceof b?alert(“true”):alert(“false”); //a是b的实例?真:假
var a=new Array();alert(a instanceof Array); 会返回 true,
同时 alert(a instanceof Object)也会返回 true;这是因为 Array 是 object 的子类。

2.Array.isArray()
在这里插入图片描述

;