vue-element-ui-Cascader 級聯(lián)選擇器支持多選---折騰記

重大更新

最新版本的element已經(jīng)有級聯(lián)多選功能了

前沿


吐槽一下,程序猿最不愿聽到的話之一,(人家某某網(wǎng)站就做出來了,你怎么做不出來,簡直喪心病狂)小編最近一直在開發(fā)基于vue-elementui的pc端項目,就碰到了來自產(chǎn)品的這句話,都有種拿起顯示器了。不過吐槽歸吐槽,項目還是要寫的。。。。。。在本項目中產(chǎn)品提的一個需求,就是人家某某網(wǎng)站上有的,而element-ui上沒有,那就是Cascader 級聯(lián)選擇器,element-ui只支持單選,于是就開始了折騰,再折騰了快一周的時間吧,還是沒搞出來,最后由于項目著急上線,只能暫時先放棄,所以就先擱置了,后來幸得于空,于是乎又是開始折騰,畢竟也是自己的問題。哎,不說了,show time.

該多選菜單基于 element-ui 的Cascader 層級菜單, 但是在我的一番折騰下開發(fā)出一套支持多選的,有禁用狀態(tài),以及靈活控制選幾個,適應產(chǎn)品的奇葩需求,Cascader 層級菜單。羞于一提的是,我折騰了整整3天,才搞出來。在這里把我的心路歷程記錄下來,里邊的注釋寫的個人感覺都挺全的,有不明白的也可以與我交流,共同探討,方便后續(xù)學習與擴展。
先上個效果圖


微信圖片_20181012184700.png

現(xiàn)附上該插件的菜單配置項,以方便后期維護

attributes屬性說明

屬性名 描述 類型 默認值
width 菜單選擇面板的寬度 String 220px
height 菜單選擇面板的高度 String 240px
options 選擇器菜單數(shù)據(jù)配置項 Array []
inputValue 選擇器輸入框內顯示的內容 String 220px
outputType 選中項輸出的字段名,outputType 用于輸出選中選擇項對象的某一字段, 默認值: value, 當傳入 outputType 為item時, 輸出選中這一項的對象(不包括 children 屬性); String value
disabledPair 互斥選項對兒,就是選擇一個其他的就被禁用 Object --

事件名稱

事件名稱 說明 回調參數(shù)
on-selected 選擇器中的某一項被選中的時候觸發(fā)的事件 數(shù)組,數(shù)組內包含被選中的值

options 菜單配置,就是完全按照elementui Cascader 的options的格式

屬性名 描述 類型
value 選項的值 String or Number
label 選項的名稱 String
checked 該選項是否被選中 Boolean
children 如果存在下一級菜單,是屬于該選項的下一級選項值, 非必須 Array
multiple 是否多選 true為多選,false為單選
disabled 是否禁用 true為禁用,false為不禁用

再簡單介紹一下disabledPair屬性

disabledPair 用于設置禁用對, 對象形式, 接收兩個屬性: thisPair thatPair:

disabledPair: {
thisPair: [1], //這里的1是value的值
thatPair: [2],
}
那么, 當值為 1 的選項被選中的時候, 值為 2 的選項將會被禁用掉, 反之亦然。但其他選項的值不會受到影響 除了傳遞單獨的項之外, 還可以單獨傳入一個 all。

disabledPair: {
thisPair: [1],
thatPair: ["all"]
}

首先,先建一個公共的文件夾MulitileCascader,里邊包含有三個自己封裝的文件

一,index.vue 此頁面為主要出口文件,會發(fā)射出一個得到選中后的item的方法以及數(shù)組。

<template>
  <span class="dropTreeLists">
    <span class="benchmark">基準&nbsp;:</span>
    <multiCascader :options="configOptions"
                   @on-selected="getSelected"
                   :inputValue="configTips"></multiCascader>
  </span>
</template>
   <script>
import multiCascader from "./MulCheckCascader.vue";
//這個也是我們項目的接口,不必糾結,倒是換位自己的接口就好了
import { getlistBenchmark } from "@/api/basicManage";
export default {
  components: {
    multiCascader
  },
  data() {
    return {
      configTips: "請選擇基準",
      //模板勿刪
      configOptions: [
        {
          value: "1",
          label: "一級菜單",
          checked: false,  //控制是否默認選中
          multiple: false,   //是否多選   false為該一級菜單不多選,true表示多選
          children: [
            {
              value: 11,
              checked: false,
              multiple: false,
              disabled:true,    //是否禁用
               label: "二級菜單",
              children: [
                {
                  value: "21",
                  checked: false,
                  multiple: false,   //是否多選   false為該一級菜單不多選,true表示多選
                  disabled :true,    //是否禁用
                  label: "三級菜單1"
                },
                {
                  value: "22",
                  checked: false,
                  label: "三級菜單2"
                }
              ]
            },
            {
              value: "12",
              checked: false,
              multiple: false,
              label: "二級菜單",
              children: [
                {
                  value: "399300",
                  checked: true,
                  label: "三級菜單復制"
                },
                {
                  value: "399300",
                  checked: false,
                  label: "三級菜單"
                }
              ]
            }
          ]
        }
      ],
      commonLength: ""
    };
  },
  mounted() {
    this.MulitGetlistBenchmark(); //多選
  },
  methods: {
    // 點擊每一個item的時候的操作   在這個方法內靈活判斷多選的狀態(tài)以及禁用狀態(tài)
    getSelected(val) {
      let strnum = val.length;
      console.log(val);
      // 當選中的指數(shù)大于1并且小于10的時候讓所有的指數(shù)都可以選擇(沒有禁用狀態(tài))
      if (val.length > 1 && val.length < 10) {
        this.LessThanThen(this.configOptions);
      }
      // 必須保留一個選中的
      if (val.length == 1) {
        let moreOne = val[0];
        this.LessThanMoreOne(this.configOptions, moreOne);
      }
      // 當選中的指數(shù)大于10的時候讓除選中的之外的指數(shù)都變?yōu)榻脿顟B(tài)
      if (val.length >= 10) {
        let moreOne = val;
        this.LessThanMoreTen(this.configOptions, moreOne);
      }
      if (strnum !== this.commonLength) {
//將選中后的數(shù)組暴漏出去,在需要的頁面使用
        this.$emit("CheckedsIndexCodes", val);
      }
      this.commonLength = val.length;
      // 勿刪后期需求改變會用
      // this.selectGroups = val;
      // this.configTips = `已選擇${val.length}個分組`;
    },
    // 此遞歸為當選中的指數(shù)大于10的時候讓除選中的之外的指數(shù)都變?yōu)榻脿顟B(tài)
    LessThanMoreTen(datas, moreOne) {
      for (var i in datas) {
        if (datas[i].multiple !== false) {
          // console.log(datas[i]);
          datas[i].disabled = true;
          for (let d = 0; d < moreOne.length; d++) {
            if (datas[i].value == moreOne[d]) {
              datas[i].disabled = false;
            }
          }
        } else {
          this.LessThanMoreTen(datas[i].children, moreOne);
        }
      }
    },
    // 此遞歸為當選中的為選中的只剩下一個的時候禁止取消,也就是必須保留一個選中的
    LessThanMoreOne(datas, moreOne) {
      for (var i in datas) {
        if (datas[i].multiple !== false) {
          // console.log(datas[i]);
          if (datas[i].value == moreOne) {
            datas[i].disabled = true;
          }
        } else {
          this.LessThanMoreOne(datas[i].children, moreOne);
        }
      }
    },
    // 此遞歸為當選中的為  滿足該條件時(val.length > 1 && val.length < 10)  所有的item的都可以選則
    LessThanThen(datas) {
      for (var i in datas) {
        if (datas[i].multiple !== false) {
          // console.log(datas[i]);
          datas[i].disabled = false;
        } else {
          this.LessThanThen(datas[i].children);
        }
      }
    },
    // 此遞歸為初始化時默認選中滬深300,由于只有一個所以禁用滬深300
    getArrayList(datas) {
      for (var i in datas) {
        if (datas[i].multiple !== false) {
          // console.log(datas[i]);
          datas[i].disabled = false;
          if (datas[i].value === "399300") {
            datas[i].disabled = true;
            datas[i].checked = true;
          }
        } else {
          // console.log(datas[i]);
          //每次在傳入父節(jié)點的childreg去查找,自己調用自己的方法
          this.getArrayList(datas[i].children);
        }
      }
    },
    MulitGetlistBenchmark() {
//此接口為我們項目中的接口,上邊有數(shù)據(jù)模板,可根據(jù)數(shù)據(jù)模板來寫數(shù)據(jù)。
      getlistBenchmark({}).then(response => {
        this.configOptions = response.data.data;
        this.getArrayList(this.configOptions);
      });
    }
  }
};
</script>
   
   <style lang="scss" scoped>
.benchmark {
  font-size: 14px;
}
</style>

二,MulCheckCascader.vue //此頁面為基礎模板,會在該頁面引用遞歸出來的多選的item的字模板,并且該頁面會接受引用頁面?zhèn)鬟^來的數(shù)據(jù),方便靈活控制尺寸,數(shù)據(jù),是否禁用等的狀態(tài)。

<template lang='html'>
    <div class='multil-cascader'>
        <el-popover placement="top-start" popper-class="multi-cascader-popover" :visible-arrow="showArrow" trigger="click" @hide="whenPopoverHide" @show="whenPopoverShow">
            <muContent
                :height="height"
                :width="width"
                :option="options"
                @handleOutPut="whenOutPut"
                :selectedValues="selectedValues"
                :outputType="outputType"
                :disabledPair="disabledPair">
            </muContent>
            <el-input popper-class="slect-panel" v-if="activeItem[0] && activeItem[0].level === 0"  v-model="inputValue" readonly slot="reference" :suffix-icon="inputArrow"/>
        </el-popover>
    </div>
</template>

<script>
import muContent from "./multiContent";
export default {
    name: "multiCascader",
    props: {
        options: {
            type: Array,
            default() {
                return [];
            }
        },
        width: {
            type: String,
            default: ""
        },
        height: {
            type: String,
            default: ""
        },
        inputValue: {
            type: String,
            default() {
                return "";
            }
        },
        // 輸出值的類型
        outputType: {
            type: String,
            default() {
                return "value";
            }
        },
        // 互斥對兒
        disabledPair: {
            type: Object,
            default() {
                return {};
            }
        }
    },
    data() {
        return {
            // 被選中的值
            selectedValues: [],
            showArrow: true,
            activeItem: [],
            outputValue: [],
            optionDicts: [],
            inputArrow: "el-icon-arrow-down",
            popoverWidth: "",
            // 展開之后的數(shù)組, 將每一個children 展開
            flatOptions: []
        };
    },
    watch: {
        "options": function () {
            this.initData();
        }
    },
    components: {
        muContent
    },
    created() {
        this.initData();
        this.setOptionDicts(this.options);
        this.toFlatOption(this.options);
    },
    methods: {
        whenPopoverHide() {
            this.inputArrow = "el-icon-arrow-down";
        },
        whenPopoverShow() {
            this.inputArrow = "el-icon-arrow-up";
        },
        // 初始化數(shù)據(jù) 對于每一項 options 添加相關字段并且獲取到當前被點擊到的元素
        initData() {
            this.setLevel();
            const { width, height } = this;
            const checkedValues = [];
            let childrenValues = [];
            const getChecked = (item) => {
                const { checked, value, children, level, siblingValues } = item;
                if (siblingValues) {
                    const tempValues = [...siblingValues];
                    item.siblingValues = tempValues;
                }
                childrenValues.push(value);
                if (children && children.length > 0) {
                    children.forEach(child => {
                        getChecked(child);
                    });
                } else {
                    if (checked && item[this.outputType]) checkedValues.push(item[this.outputType]);
                }
            };
            this.activeItem = this.options;            
            this.options.forEach(child => {
                getChecked(child);
                // 設置當前item 的 childrenValues, 包含當前item 下的所有值的 value
                child.childrenValues = [...childrenValues];
                childrenValues = [];
            });
            this.selectedValues = checkedValues;
            this.whenOutPut(this.selectedValues);
        },
        getTypeOptions(values, outputType) {
            const outputValues = [...values];
            const finalOutputArr = [];
            return this.flatOptions.reduce((pev, cur) => {
                const { value: curVal } = cur;
                if (outputType === "item") {
                    if (outputValues.includes(curVal)) pev.push(cur);
                } else {
                    if (outputValues.includes(curVal) && cur[outputType]) pev.push(cur[outputType]);
                }
                return pev;
            }, []);
        },
        // 展開配置中的各項, [{}], 排除 children 屬性
        toFlatOption(option) {
            const getItems = (arr, cur) => {
                const keys = Object.keys(cur);
                const newObj = {};
                const curChild = cur.children;
                const hasChild = curChild && curChild.length > 0;          
                keys.forEach(key => key !== "children" && (newObj[key] = cur[key]));
                arr.push(newObj);
                return (hasChild ? curChild.reduce(getItems, arr) : arr);
            };
            this.flatOptions = option.reduce(getItems, []);
        },
        // 設置配置的字典
        setOptionDicts(options) {
            if (!Array.isArray(options)) {
                const { label, value } = options;
                this.optionDicts.push({ value, label });
                const children = options.children;
                if (children) {
                    this.setOptionDicts(children);
                }
            } else {
                options.forEach(opt => {
                    this.setOptionDicts(opt);
                });
            }
        },
        // 觸發(fā) on-selected 事件
        whenOutPut(value) {
            // 根據(jù)選中的值數(shù)組 value 輸出特定 outputType 類型
            if (this.outputType !== "value") {
                this.outputValue = this.getTypeOptions(value, this.outputType);
            } else {
                this.outputValue = value;
            }
            this.$emit("on-selected", this.outputValue);
        },
        // 設定層級
        setLevel() {
            const siblingValues = [];
            let tempLevel = 0;
            if (this.options.length) {
                const addLevel = option => {
                    const optChild = option.children;
                    if (option.level === tempLevel) {
                        siblingValues.push(option.value);
                    }
                    if (optChild) {
                        optChild.forEach(opt => {
                            opt.level = option.level + 1;
                            addLevel(opt);
                        });
                    }
                };
                this.options.forEach(option => {
                    if (!option.level) {
                        option.level = 0;
                        tempLevel = option.level;
                    }
                    addLevel(option);
                    option.siblingValues = siblingValues;
                });
            }
        },
        showSecondLevel(item) {
            this.activeItem = item;
        }
    }
};
</script>
<style lang='scss' scoped>
.vk-menu-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    list-style-type: none;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    cursor: pointer;
    outline: none;
    padding: 8px 20px;
    font-size: 14px;
    width: 100%;
    &:hover {
        background-color: rgba(125,139,169,.1);
    }
}
.multil-cascader{
    width: 155px;
    display: inline;
}
.multil-cascader:hover{
    cursor: pointer;
}

</style>

三,multiContent.vue 該頁面為遞歸的所有children的Li的顯示,以及選中點擊事件

<template lang="html">
    <div class="popver-content">
        <div class="multiCascader-multil-content" :style="contentStyle">
            <ul class="multiCascader-multi-menu">
                <li v-for="(item, index) of option"
                    :key="index"
                    style="border:1px solid transparent;"
                    :class="[ 'multiCascader-menu-item', { 'item-disabled': item.disabled }]"
                    @click="showNextLevel(item)">
                    <el-checkbox v-if="item.multiple != false" :disabled="item.disabled" v-model="item.checked" @change="checkChange(item)">{{ item.label }}</el-checkbox>
                    <span v-else>{{ item.label }}</span>
                    <i class="el-icon-arrow-right" v-show="item.children && item.children.length > 0"></i>
                </li>
            </ul>
        </div>
        <!-- 遞歸調用自身組件 -->
        <muContent
            @handleSelect="whenSelected"
            :height="height"
            :width="width"
            v-if="(activeItem && activeItem.children) && (activeItem.children.length > 0)"
            :selectedValues="selectedValues"
            @handleOutPut="whenOutPut"
            :disabledPair="disabledPair"
            :option="activeItem.children" >
        </muContent>
    </div>
</template>

<script>
const vm = this;
import Vue from "vue";
export default {
  name: "muContent",
  props: {
    option: {
      type: Array,
      default() {
        return [];
      }
    },
    // 被選中的值
    selectedValues: {
      type: Array,
      default() {
        return [];
      }
    },
    // 設置的寬度
    width: {
      type: String,
      default: ""
    },
    height: {
      type: String,
      default: ""
    },
    // 禁用字段
    disabledPair: {
      type: Object,
      default() {
        return {};
      }
    }
  },
  data() {
    return {
      activeItem: "",
      tempActiveItem: "",
      contentStyle: {
        width: "",
        height: ""
      },
      checkArr: [],
      checkDisabled: false
    };
  },
  created() {
    this.initData();
    this.whenOutPut(this.selectedValues);
  },
  methods: {
    // 逐級上傳
    whenOutPut(val) {
      this.$emit("handleOutPut", val);
    },
    initData() {
      const { width, height } = this;
      this.contentStyle = Object.assign({}, this.contentStyle, {
        width,
        height
      });
    },
    // 獲取到選中的值
    checkChange(item) {
      const getCheckedItems = item => {
        const { value, checked, level } = item;
        if (checked && level) {
          this.selectedValues.push(value);
        } else if (!checked) {
          item.disabled = false;
          if (this.selectedValues.includes(value)) {
            this.selectedValues.splice(
              this.selectedValues.findIndex(slectVal => slectVal === value),
              1
            );
          }
        }
        const itemChild = item.children;
        if (itemChild) {
          itemChild.forEach(child => (child.checked = checked));
        }
      };

      this.recursiveFn(item, getCheckedItems);
      this.disabeldAction(item);
      this.activeItem = item;
      this.$emit("handleSelect", this.option);
      this.$emit("handleOutPut", this.selectedValues);
    },
    // 當二級菜單改變的時候
    whenSelected(val) {
      let allChildCancelChecked = true;
      if (Array.isArray(val) && val.length > 0) {
        allChildCancelChecked = val.every(child => child.checked === false);
      }
      this.activeItem.checked = !allChildCancelChecked;
      this.disabeldAction(this.activeItem);
      this.$emit("handleSelect", this.option);
    },
    // 遞歸函數(shù)
    recursiveFn(curItem, cb) {
      cb(curItem);
      const children = curItem.children;
      if (children && children.length > 0) {
        children.forEach(item => {
          this.recursiveFn(item, cb);
        });
      }
    },
    // 設置 disabled 值 values: 互斥的另一方數(shù)組, curItem 當前選中的值
    setDisabled(exceptValues, curItem, values) {
      const {
        checked: curChecked,
        childrenValues,
        value: curValue,
        siblingValues
      } = curItem;
      this.checkArr = [];
      if (values.includes("all")) {
        if (siblingValues) {
          this.checkArr = new Array(
            siblingValues.length - exceptValues.length
          ).fill(true);
        }
      } else {
        this.checkArr = new Array(values.length).fill(true);
      }
      const getCheckArr = item => {
        const { value, checked } = item;
        if (!exceptValues.includes(value)) return;
        this.checkArr.push(checked);
        this.checkArr.shift();
      };
      const resetDistable = child => {
        if (!values.includes(child.value)) return;
        child.disabled = this.checkArr.some(val => val === true);
      };
      this.option.forEach(opt => {
        this.recursiveFn(opt, getCheckArr);
      });
      this.option.forEach(opt => {
        this.recursiveFn(opt, resetDistable);
      });
    },
    // disabled action
    // 根據(jù)選中的值進行設置是否可選
    disabeldAction(item) {
      const { thatPair, thisPair } = this.disabledPair;
      if (!thatPair || !thisPair) {
        return;
      }
      const pairs = [...thatPair, ...thisPair];
      const { value: itemVal } = item;
      const belongPair = pairs.includes(itemVal) || pairs.includes("all");
      let distableValues = [];
      let ableValues = [];
      if (!belongPair) return;
      if (
        thisPair.includes(item.value) ||
        (thisPair.includes("all") && !thatPair.includes(item.value))
      ) {
        this.setDisabled(thisPair, item, thatPair);
        return;
      }
      if (
        thatPair.includes(item.value) ||
        (thatPair.includes("all") && !thisPair.includes(item.value))
      ) {
        this.setDisabled(thatPair, item, thisPair);
      }
      this.$emit("handleSelect", this.option);
      this.disabeldAction(this.activeItem);
    },
    // 設置 disabled 值 values: 互斥的另一方數(shù)組, curItem 當前選中的值
    setDisabled(exceptValues, curItem, values) {
      const {
        checked: curChecked,
        childrenValues,
        value: curValue,
        siblingValues
      } = curItem;
      this.checkArr = [];
      if (values.includes("all")) {
        if (siblingValues) {
          this.checkArr = new Array(
            siblingValues.length - exceptValues.length
          ).fill(true);
        }
      } else {
        this.checkArr = new Array(values.length).fill(true);
      }
      const toDisabled = item => {
        const { value, checked } = item;
        if (
          values.includes(value) ||
          (values.includes("all") && !exceptValues.includes(value))
        ) {
          if (siblingValues && siblingValues.includes(value)) {
            this.checkArr.push(checked);
            this.checkArr.shift();
          }
        }
        const itemChild = item.children;
        if (itemChild && itemChild.length > 0) {
          itemChild.forEach(child => {
            toDisabled(child);
          });
        }
      };
      this.option.forEach(child => {
        toDisabled(child);
      });
      this.option.forEach(child => {
        if (
          exceptValues.includes(child.value) ||
          (exceptValues.includes("all") && !values.includes(child.value))
        ) {
          child.disabled = this.checkArr.some(val => val === true);
        }
      });
    },
    // disabled action
    // 根據(jù)選中的值進行設置是否可選
    disabeldAction(item) {
      const { thatPair, thisPair } = this.disabledPair;
      if (!thatPair || !thisPair) {
        return;
      }
      const pairs = [...thatPair, ...thisPair];
      if (pairs.includes(item.value) || pairs.includes("all")) {
        if (
          thisPair.includes(item.value) ||
          (thisPair.includes("all") && !thatPair.includes(item.value))
        ) {
          this.setDisabled(thatPair, item, thisPair);
          return;
        }
        if (
          thatPair.includes(item.value) ||
          (thatPair.includes("all") && !thisPair.includes(item.value))
        ) {
          this.setDisabled(thisPair, item, thatPair);
        }
      }
    },
    //點擊每一個列表的操作并且給下一個列表賦值
    showNextLevel(item) {
        //先清空,后賦值,否則會導致多級列表同時存在
      this.activeItem = "";
      if (item.disabled) return;
      setTimeout(() => {
        this.activeItem = item;
      }, 10);
    }
  }
};
</script>
<style lang='scss' scoped>
.popver-content {
  display: flex;
  justify-content: space-between;
}
.multiCascader-multil-content {
  display: inline-block;
  max-height: 250px;
  overflow-y: auto;
  // border-right: 1px solid red;

}
.multiCascader-menu-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  list-style-type: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
  outline: none;
  padding: 8px 20px;
  font-size: 14px;
  &:hover {
    background-color: rgba(125, 139, 169, 0.1);
  }
}
.item-disabled {
  color: #c0c4cc;
  cursor: not-allowed;
}
</style>

接下來就到需要引用的頁面了。

<template>
  <div class="performanceBox">
          <!-- 級聯(lián)選擇器多選 -->
          <choiceindex v-on:CheckedsIndexCodes="FromTreeCheckeds"></choiceindex>
  </div>
</template>
<script>
引用上邊創(chuàng)建的MultipleChoice文件夾下的index出口文件就好了。
import choiceindex from "@/components/MultipleChoice/index"; //級聯(lián)選擇多選 完成
export default {
  components: {
    choiceindex,
  },
  data() {
    return {
      SaveCascadeIndexCodes: [], //保存級聯(lián)選擇器多選的基準code
      SaveJiZhunParams: [], //保存業(yè)績表現(xiàn)需要的參數(shù)

    };
  },
  methods: {
    //多選選擇基準時的code
    FromTreeCheckeds(IndexCodes) {
//IndexCodes就是選中的item的數(shù)組,操作他就好了
      // console.log(IndexCodes);
      this.SaveCascadeIndexCodes = IndexCodes;
    },
  }
};
</script>
<style  rel="stylesheet/scss" lang="scss">
</style>

結束語


這個插件到此也就完成了,終于解決了這個深坑,希望能幫助到小伙伴們,有什么不足的大家多多提出寶貴的意見,共同探討,進步。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容