• Vue2 实现时空穿梭框功能模块


    前言

    这篇文章主要是分享一个时空穿梭框功能,也就是我们平时用的选择功能。勾选了的项就会进入到另一个框中。

    时空穿梭框之旅

    示例演示:

    Vue 实现时空穿梭框功能模块

    这个时空穿梭框实现了:

    • 1、可以全选、反选
    • 2、没有选中时,不可以点穿梭按钮
    • 3、自动计数(共有多少个,选中了多少个)
    • 4、没有数据时,全选不可点击

    这里主要是想通过这个示例来抛砖引玉,更多的功能,你可以根据自己的实践需要来实现。下面我们就来看看这示例的相关文件及代码。

    文件结构
    1. ├── index.html
    2. ├── main.js
    3. ├── router
    4. └── index.js # 路由配置文件
    5. └── components # 组件目录
    6. ├── App.vue # 根组件
    7. ├── Home.vue # 大的框架结构组件
    8. ├── ChangeBox.vue
    9. └── ChangeBoxArea.vue

    文件也不多,只要有两个(ChangeBox.vue 和 ChangeBoxArea.vue)下面我们就来看看实现这个示例的代码:

    index.html
    1. <!DOCTYPE html>
    2. <html>
    3. <head>
    4. <meta charset="utf-8">
    5. <meta name="viewport" content="width=device-width,initial-scale=1.0">
    6. <title>changebox</title>
    7. <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css">
    8. </head>
    9. <body>
    10. <div id="app"></div>
    11. <!-- built files will be auto injected -->
    12. </body>
    13. </html>

    本示例主要用到了 bootstrap ,所以我们就在 index.html 中引入了 bootstrap 的 cdn。然后我们就可以直接在示例中使用 bootstrap 给我们提供的 UI 了。

    router/index.js
    1. import Vue from 'vue'
    2. import Router from 'vue-router'
    3. import Home from '@/components/Home'
    4. Vue.use(Router)
    5. export default new Router({
    6. routes: [{
    7. path: '/',
    8. name: 'Home',
    9. component: Home
    10. }]
    11. })

    在这里我们直接把 / 路径的配置到 Home 组件。

    App.vue
    1. <template>
    2. <div id="app">
    3. <Home></Home>
    4. </div>
    5. </template>
    6. <script>
    7. import Home from "@/components/Home";
    8. export default {
    9. name: "App",
    10. components: { Home }
    11. };
    12. </script>
    13. <style>
    14. #app {
    15. font-family: "Avenir", Helvetica, Arial, sans-serif;
    16. -webkit-font-smoothing: antialiased;
    17. -moz-osx-font-smoothing: grayscale;
    18. color: #2c3e50;
    19. margin-top: 60px;
    20. }
    21. </style>

    在根组件中,我们只是做了一件很简单的事,就是引入Home 组件。

    Home.vue
    1. <template>
    2. <div>
    3. <change-box></change-box>
    4. </div>
    5. </template>
    6. <script>
    7. import ChangeBox from "@/components/ChangeBox";
    8. export default {
    9. name: "Home",
    10. components: {
    11. ChangeBox
    12. }
    13. };
    14. </script>

    Home.vue 组件代码非常地简单,这里其实也可以直接写到根组件上的,但为了养成良好的习惯,我们还是有必要把示例的整体结构往写成更接近实战一些。

    好了,上面的基本功做好了之后,我就可以开始这个时空穿梭框的主要代码了的展示了。

    ChangeBox.vue
    1. <template>
    2. <div class="container">
    3. <div class="row">
    4. <div class="col-md-5">
    5. <change-box-area :title="sourceTitle" :data="sourceList"></change-box-area>
    6. </div>
    7. <div class="col-md-2 text-center">
    8. <p><button :disabled="sourceList.length === 0 || sourceRefNum === 0" class="btn btn-primary" @click="toTarget()"></button></p>
    9. <p><button :disabled="targetList.length === 0 || targetRefNum === 0" class="btn btn-primary" @click="toSource()"></button></p>
    10. </div>
    11. <div class="col-md-5">
    12. <change-box-area :title="targetTitle" :data="targetList"></change-box-area>
    13. </div>
    14. </div>
    15. </div>
    16. </template>
    17. <script>
    18. import ChangeBoxArea from "./ChangeBoxArea";
    19. // 这里的 isSeleted 属性可以不用添加,可以在 JS 中进行处理,一般情况下后端返回的数据也不会带有类似这种静态状态的属性
    20. let dataList = [
    21. { id: 1, name: "HTML5", isSelected: false },
    22. { id: 2, name: "CSS3", isSelected: false },
    23. { id: 3, name: "Angular", isSelected: false },
    24. { id: 4, name: "Vue", isSelected: false },
    25. { id: 5, name: "Linux", isSelected: false },
    26. { id: 6, name: "JavaScript", isSelected: false }
    27. ];
    28. export default {
    29. components: {
    30. ChangeBoxArea
    31. },
    32. name: "ChangeBox",
    33. data() {
    34. return {
    35. sourceTitle: "请选择",
    36. targetTitle: "已选择",
    37. sourceList: dataList,
    38. targetList: []
    39. };
    40. },
    41. methods: {
    42. exchange(fd, td) {
    43. let selectedItem = fd.filter(item => item.isSelected).map(item => {
    44. return {
    45. ...item,
    46. isSelected: false
    47. };
    48. });
    49. td.push(...selectedItem);
    50. return fd.filter(item => !item.isSelected);
    51. },
    52. // 把选择数据转移到目标(右框)
    53. toTarget() {
    54. this.sourceList = this.exchange(this.sourceList, this.targetList);
    55. },
    56. // 把选择数据转回到源(左框)
    57. toSource() {
    58. this.targetList = this.exchange(this.targetList, this.sourceList);
    59. }
    60. },
    61. computed: {
    62. // 源数据中选中的数量
    63. sourceRefNum() {
    64. return this.sourceList.filter(item => item.isSelected).length;
    65. },
    66. // 目标数据中选中的数量
    67. targetRefNum() {
    68. return this.targetList.filter(item => item.isSelected).length;
    69. }
    70. }
    71. };
    72. </script>

    接下来我们再来看看最后一个

    ChangeBoxArea.vue
    1. <template>
    2. <div class="panel panel-default">
    3. <div class="panel-heading clearfix">
    4. <div class="pull-left">
    5. <div class="checkbox">
    6. <label>
    7. <input :disabled="data.length === 0" type="checkbox" @click="toggleAll()" :checked="selectedAllStatus"><span>{{title}}</span>
    8. </label>
    9. </div>
    10. </div>
    11. <span class="pull-right">{{selectItemNumber}}/{{data.length}}</span>
    12. </div>
    13. <div class="panel-body">
    14. <ul>
    15. <li v-for="item in data" :key="item.id">
    16. <div class="checkbox">
    17. <label>
    18. <input type="checkbox" v-model="item.isSelected"> {{item.name}}
    19. </label>
    20. </div>
    21. </li>
    22. </ul>
    23. </div>
    24. </div>
    25. </template>
    26. <script>
    27. export default {
    28. name: "ChangeBox",
    29. props: ["title", "data"],
    30. computed: {
    31. // 选择的数量
    32. selectItemNumber() {
    33. return this.data.filter(item => item.isSelected).length;
    34. },
    35. // 全选状态
    36. selectedAllStatus() {
    37. if (
    38. this.selectItemNumber === this.data.length &&
    39. this.selectItemNumber !== 0
    40. ) {
    41. return true;
    42. } else {
    43. return false;
    44. }
    45. }
    46. },
    47. methods: {
    48. // 全选及反选
    49. toggleAll() {
    50. let len = this.data.length;
    51. let slen = this.data.filter(item => item.isSelected).length;
    52. if (len !== slen) {
    53. this.data.map(item => (item.isSelected = true));
    54. } else {
    55. this.data.map(item => (item.isSelected = false));
    56. }
    57. }
    58. }
    59. };
    60. </script>
    61. <style scoped>
    62. ul {
    63. list-style: none;
    64. padding: 0;
    65. }
    66. .checkbox {
    67. margin: 0;
    68. }
    69. </style>

    在上面的代码中,有一个地图需要特别的注意下:在全选的input 中我们要使用 :checked 来绑定 selectedAllStatus,而不用 v-model,因为我们的 selectedAllStatus 是一个计算属性,如果把它绑定到 v-model,会报错的:

    报错

    [Vue warn]: Computed property “selectedAllStatus” was assigned to but it has no setter.

    大概意思是说 selectedAllStatus 没有 setter 方法,不能给它赋值,当然,你可以把给这个属性添加 setter 方法,但这样做好像又有点累赘了。为此我们直接使用 :checked 来绑定 selectedAllStatus  属性。

    Vue 实现时空穿梭框功能模块就分享到这里,其实这样的需求示例在真实的项目中是有可能出现的,但在项目中这个很有可能会更加复杂,比如:

    • 1、左边的框不是平铺的,而是多级,可展开收缩,勾选了的项才会出现在右边的框中
    • 2、搜索功能
    • 3、不用点中间的两个箭头,而是勾选后,就会自动穿梭到右边去。

    这样的需求极为常见,所以你有必要在平时的学习中,把这些东西都自己整理出来,或者把常用的功能模块封装成通用组件,这个对于提高工作效率是非常有用的。花个两三天把它封装成一个常用的组件,以后开发起来,只要遇到这种的基本都可以搬过来用,顶多改改样式,所以也有必要给组件添加必要的属性为定制提供可能。又或者更过分点的,追加一些功能。

  • 相关阅读:
    Convert to a source folder or rename it.
    git revert 后悔了 还原修改前的版本 + git 常用命令
    android switch语句报错:case expressions must be constant expressions
    解读ContentResolver和ContentProvider
    sdk命令
    向Android模拟器中批量导入通讯录联系人
    Rational Rose2007下载安装教程以及问题处理
    java代码打包成jar以及转换为exe
    Timusoj 1982. Electrification Plan
    poj 3254 Corn Fields
  • 原文地址:https://www.cnblogs.com/Yanss/p/10133606.html
Copyright © 2020-2023  润新知