vue封装复选框组件

╰+攻爆jí腚メ 2022-01-31 15:27 895阅读 0赞

前言

根据百度前端技术学院2018 MVVM 学院 中的 2.5 表单实现Input、Checkbox组件 用 vue 实现的

checkbox复选框组件,使checkbox有三种状态: checked:ture (选中) / false (未选中) , indeterminate (部分选中)

1.利用slot插槽

2.在同一文件中用到父子通信 $emit $on

本文章的 github地址

实现思路

1.在mounted(附加到页面上)时绑定监听

因为只有在mounted(元素挂载到页面上)之后才能理清节点之间的关系,也才能找到目标节点的$parent,$children

  1. mounted() {
  2. // 得先检测其 $parent 是不是复选框组件(如果是,则其有onDispatch 函数)
  3. if (this.$parent.onDispatch) {
  4. // 如果组件的状态改变,则会执行其父组件的 onDispatch 函数
  5. this.$on("checkStatus", this.$parent.onDispatch);
  6. }
  7. },

2. 当复选框状态改变时,将自己的改变后的复选框状态通知给其父复选框

this.$emit(“checkStatus”, “indeterminate”/true/false);

3. onDispatch 函数分析

3.1 接收到的值为 子组件状态改变后 发送过来的状态:{“indeterminate”/true/false}

3.2 改变其#(id).checked属性,直接操作其绑定的isChecked即可:checked=”isChecked”

isChecked只有true/false

3.3 改变其#(id).indeterminate属性,得获取元素(需要id,所以每个chekbox需要绑定一个id:id=”id”),得到其indeterminate,

  1. _getIndeterminate() {
  2. return document.getElementById(this.id).indeterminate;
  3. },
  4. _setIndeterminate(bool) {
  5. document.getElementById(this.id).indeterminate = bool;
  6. },

3.4 当复选框状态为选中/未选中 时,设置其全部子组件为相对应值

(递归,多层改变,能对孩子,孙子,重孙等起作用。)

  1. _setAllSubItem(component, bool) {
  2. component.$children.map(i => {
  3. i.isChecked = bool;
  4. this._setAllSubItem(i, bool);
  5. });
  6. },

4. 最后执行形式

  1. <v-checkbox text="爱好" id="hobby">
  2. <v-checkbox text="种花" id="plant">
  3. <v-checkbox text="养鱼" id="fish"></v-checkbox>
  4. </v-checkbox>
  5. <v-checkbox text="购物" id="shop"></v-checkbox>
  6. <v-checkbox text="吃饭" id="eat"></v-checkbox>
  7. </v-checkbox>

代码实现

  1. <template>
  2. <div>
  3. <label>
  4. <input type="checkbox" @change="handleChange" :checked="isChecked" :id="id">
  5. <span class="checkbox"></span>
  6. <span class="text" s-if="text">{
  7. {text}}</span>
  8. </label>
  9. <div class="sub">
  10. <slot></slot>
  11. </div>
  12. </div>
  13. </template>
  14. <script>
  15. export default {
  16. props: ["text", "id"],
  17. mounted() {
  18. if (this.$parent.onDispatch) {
  19. this.$on("checkStatus", this.$parent.onDispatch);
  20. }
  21. },
  22. data() {
  23. return {
  24. id: this.id,
  25. parent: null,
  26. subItems: [],
  27. isChecked: false
  28. };
  29. },
  30. methods: {
  31. // 设置元素 Indeterminate 状态,若为true,表示部分选中
  32. _setIndeterminate(bool) {
  33. document.getElementById(this.id).indeterminate = bool;
  34. },
  35. // 获取元素 Indeterminate 状态
  36. _getIndeterminate() {
  37. return document.getElementById(this.id).indeterminate;
  38. },
  39. // 将元素所有子元素的选中状态统一设置成该元素的选中状态 true/false
  40. _setAllSubItem(component, bool) {
  41. component.$children.map(i => {
  42. i.isChecked = bool;
  43. this._setAllSubItem(i, bool);
  44. });
  45. },
  46. onDispatch(val) {
  47. //不是根元素
  48. // console.log(this.$parent.$parent._uid);
  49. console.log(this);
  50. // 恢复默认状态
  51. this._setIndeterminate(false);
  52. // 如果子组件传过来的值是"indeterminate",即子组件是部分选中状态,那么其父组件一定也是部分选中状态
  53. if (val == "indeterminate") {
  54. this._setIndeterminate(true);
  55. this.$emit("checkStatus", "indeterminate");
  56. return;
  57. }
  58. var subItems = this.$children;
  59. if (subItems.length > 0) {
  60. var check_num = 0;
  61. subItems.map(i => {
  62. // 或者如果子选项中有一个为indeterminate,那么其父组件也一定也是部分选中状态
  63. if (i._getIndeterminate()) {
  64. this._setIndeterminate(true);
  65. this.$emit("checkStatus", "indeterminate");
  66. return;
  67. }
  68. if (i.isChecked) {
  69. check_num++;
  70. }
  71. });
  72. if (check_num == subItems.length) {
  73. //选中子项目个数
  74. this.isChecked = true;
  75. this.$emit("checkStatus", true);
  76. } else if (check_num == 0) {
  77. this.isChecked = false;
  78. this.$emit("checkStatus", false);
  79. } else {
  80. this._setIndeterminate(true);
  81. this.$emit("checkStatus", "indeterminate");
  82. }
  83. }
  84. },
  85. handleChange() {
  86. this.isChecked = !this.isChecked;
  87. this.$emit("checkStatus", this.isChecked);
  88. if (this.isChecked) {
  89. this._setAllSubItem(this, true);
  90. } else {
  91. this._setAllSubItem(this, false);
  92. }
  93. }
  94. }
  95. };

结束

如果文章对你有帮助,麻烦点赞哦!一起走码农花路~

20190510130531760.jpg

发表评论

表情:
评论列表 (有 0 条评论,895人围观)

还没有评论,来说两句吧...

相关阅读

    相关 下拉组件

    说明需求 做报表的时候,筛选条件中需要用到复选下拉框,首先说明: 1. 复选框(复选框)无法满足我的需求,因为可选项有上百个,不可能都直接列在页面上 2. 下拉框(选