Swipeout (可滑动列表)

Swipeout 是列表视图的扩展,允许您通过滑动列表元素来显示隐藏的菜单,其中包含可用的操作,如滑动删除。

Swipeout 布局

让我们看一下列表视图中 swipeout 元素的布局结构:

<div class="list">
  <ul>
    <!-- Additional "swipeout" class on li -->
    <li class="swipeout">
      <!-- Usual list element wrapped with "swipeout-content" -->
      <div class="swipeout-content">
        <!-- Your list element here -->
        <div class="item-content">
          <div class="item-media">...</div>
          <div class="item-inner">...</div>
        </div>
      </div>
      <!-- Swipeout actions left -->
      <div class="swipeout-actions-left">
        <!-- Swipeout actions links/buttons -->
        <a href="#">Action 1</a>
        <a href="#">Action 2</a>
      </div>
      <!-- Swipeout actions right -->
      <div class="swipeout-actions-right">
        <!-- Swipeout actions links/buttons -->
        <a href="#" class="swipeout-close">Action 1</a>
        <a href="#" class="swipeout-delete">Delete</a>
      </div>
    </li>
    ...
  </ul>
</div>

Where:

注意swipeout-contentswipeout-actions-left/right应该是<li>

如果您只有 "item-content",可以通过将 "item-content" 类添加到 "swipeout-content" 来简化布局:

<li class="swipeout">
  <div class="swipeout-content item-content">
    <div class="item-media">...</div>
    <div class="item-inner">...</div>
  </div>
  <div class="swipeout-actions-right">
    <a href="#">Action 1</a>
    <a href="#">Action 2</a>
  </div>
</li>

如果您使用链接项布局将是以下样子:

<li class="swipeout">
  <div class="swipeout-content">
    <a href="#" class="item-content item-link">
      <div class="item-media">...</div>
      <div class="item-inner">...</div>
    </a>
  </div>
  <div class="swipeout-actions-right">
    <a href="#">Action 1</a>
    <a href="#">Action 2</a>
  </div>
</li>

滑动删除

Framework7 支持开箱即用的此常用功能,无需一行 JavaScript。您需要做的就是向 swipeout 操作按钮添加swipeout-delete类:

<li class="swipeout">
  <div class="swipeout-content item-content">
    <div class="item-media">...</div>
    <div class="item-inner">...</div>
  </div>
  <div class="swipeout-actions-right">
    <!-- Add this button and item will be deleted automatically -->
    <a href="#" class="swipeout-delete">Delete</a>
  </div>
</li>

还可以调用确认模态框,当用户点击 "删除" 按钮时,元素只有在确认后才会被删除。要实现确认删除,您需要向删除链接添加额外的data-confirmdata-confirm-title(可选) 属性:

<li class="swipeout">
  <div class="swipeout-content item-content">
    <div class="item-media">...</div>
    <div class="item-inner">...</div>
  </div>
  <div class="swipeout-actions-right">
    <!-- We add data-confirm and data-confirm-title attributes -->
    <a href="#" class="swipeout-delete" data-confirm="Are you sure want to delete this item?" data-confirm-title="Delete?">Delete</a>
  </div>
</li>

超滑

Swipeouts 还支持 "超滑" 操作,如果您滑动操作过多,将自动触发这些操作。在这种情况下,我们需要向所需的操作按钮添加swipeout-overswipe类:

<li class="swipeout">
  <div class="swipeout-content item-content">
    <div class="item-media">...</div>
    <div class="item-inner">...</div>
  </div>
  <div class="swipeout-actions-right">
    <a href="#">More</a>
    <a href="#" class="swipeout-delete swipeout-overswipe">Delete</a>
    </div>
  </div>
</li>
  • 溢出仅可用于右侧 swipeout 操作中的最后一个按钮,以及左侧 swipeout 操作中的第一个按钮。

  • 通过超滑,脚本将自动在超滑按钮上触发 "点击" 事件,因此您需要为此按钮添加适当的事件监听器

  • 超滑按钮在超滑期间将具有额外的swipeout-overswipe-active类,您可以使用它来对此状态进行额外样式设置

<li class="swipeout">
  <div class="swipeout-content">
    <a href="#" class="item-content item-link">
      ...
    </a>
  </div>
  <div class="swipeout-actions-left">
    <a href="#" class="swipeout-overswipe bg-green reply">Reply</a>
    <a href="#" class="bg-blue forward">Forward</a>
  </div>
  <div class="swipeout-actions-right">
    <a href="#" class="mark bg-orange">Mark</a>
    <a href="#" class="swipeout-delete swipeout-overswipe">Delete</a>
  </div>
</li>

Swipeout App 方法

Swipeouts 还具有丰富的 JavaScript API,允许您控制 swipeout 元素。让我们看一下适当 App 的方法:

app.swipeout.open(el, , 回调)- 在指定的元素上显示 swipeout 操作

  • el - HTMLElement字符串(使用 CSS 选择器) 列表 (<li>) 元素,带有 "swipeout" 类。必需
  • - 字符串(可以是 "left" 或 "right") 要打开的 swipeout 操作。如果项目具有左右 swipeout 操作,则应指定。可选
  • 回调 - 函数- 在 swipeout 元素完成打开动画后执行回调函数

app.swipeout.close(el, 回调)- 在指定的元素上关闭 swipeout 操作

  • el - HTMLElement字符串(使用 CSS 选择器) 列表 (<li>) 元素,带有 "swipeout" 类。必需
  • 回调 - 函数- 在 swipeout 元素完成关闭动画后执行回调函数

app.swipeout.delete(el, 回调)- 删除指定的 swipeout 元素

  • el - HTMLElement字符串(使用 CSS 选择器) 列表 (<li>) 元素,带有 "swipeout" 类。必需
  • 回调 - 函数- 在 swipeout 元素完成删除动画之前,在它从 DOM 中移除之前执行回调函数

app.swipeout.el- 属性。当前打开的 swipeout HTMLElement。或undefined如果没有打开的 swipeout 元素

Swipeout App 参数

可以通过在swipeout属性下传递 swipeout 相关参数来在应用初始化时配置全局 swipeout 行为。

参数类型默认描述
noFollow布尔值false用于在旧/慢设备上潜在更好性能的回退选项。如果您启用它,则 swipeout 项在触摸时不会跟随您的手指,它将在滑动左右时自动打开/关闭。
removeElements布尔值true当禁用时,框架不会在 "swipeout-delete" 点击时从 DOM 中移除 swipeout 元素。如果您使用其他库(如 Vue 或 React)来管理(删除)swipeout 项,则启用它很有用
removeElementsWithTimeout布尔值false当启用时,框架将在 "swipeout-delete" 点击后在指定延迟后从 DOM 中移除 swipeout 元素
removeElementsTimeout数字0如果removeElementsWithTimeoutis enabled.
overswipeRatio数字1.2定义了滑动多少/多硬以触发超滑(默认为 1.2)

要更改这些参数,我们需要在应用初始化时在swipeout属性下传递它们,例如:

var app = new Framework7({
  swipeout: {
    noFollow: true,
    removeElements: false
  }
});

Swipeout 事件

Swipeout 将触发以下 DOM 事件和应用实例事件:

DOM 事件

事件Target描述
swipeoutSwipeout 元素<li class="swipeout">滑动 swipeout 元素时将触发事件。event.detail contains current opening progress percentage
swipeout:openSwipeout 元素<li class="swipeout">当滑动删除元素开始其打开动画时将触发事件
swipeout:openedSwipeout 元素<li class="swipeout">当滑动删除元素完成其打开动画后触发事件
swipeout:closeSwipeout 元素<li class="swipeout">当滑动删除元素开始其关闭动画时将触发事件
swipeout:closedSwipeout 元素<li class="swipeout">当滑动删除元素完成其删除动画后触发事件
swipeout:deleteSwipeout 元素<li class="swipeout">当滑动删除元素开始其删除动画后触发事件
swipeout:deletedSwipeout 元素<li class="swipeout">当滑动删除元素完成其删除动画后触发事件,就在它将被从 DOM 中移除之前
swipeout:overswipeenterSwipeout 元素<li class="swipeout">当启用溢出时将触发事件
swipeout:overswipeexitSwipeout 元素<li class="swipeout">当禁用溢出时将触发事件

应用实例事件

Swipeout 实例在应用实例上发出事件。

事件Target参数描述
swipeoutapp进度当您移动 swipeout 元素时将触发事件
swipeoutOpenappswipeoutEl当滑动删除元素开始其打开动画时将触发事件
swipeoutOpenedappswipeoutEl当滑动删除元素完成其打开动画后触发事件
swipeoutCloseappswipeoutEl当滑动删除元素开始其关闭动画时将触发事件
swipeoutClosedappswipeoutEl当滑动删除元素完成其删除动画后触发事件
swipeoutDeleteappswipeoutEl当滑动删除元素开始其删除动画后触发事件
swipeoutDeletedappswipeoutEl当滑动删除元素完成其删除动画后触发事件,就在它将被从 DOM 中移除之前
swipeoutOverswipeEnterappswipeoutEl当启用溢出时将触发事件
swipeoutOverswipeExitappswipeoutEl当禁用溢出时将触发事件

CSS 变量

以下是相关CSS 变量(CSS 自定义属性) 的列表。

:root {
  --f7-swipeout-delete-button-bg-color: #ff3b30;
  --f7-swipeout-button-text-color: #fff;
  --f7-swipeout-button-padding-vertical: 0px;
  --f7-swipeout-button-bg-color: rgba(0, 0, 0, 0.22);
}
:root .dark,
:root.dark {
  --f7-swipeout-button-bg-color: rgba(255, 255, 255, 0.55);
}
.ios {
  --f7-swipeout-button-padding-horizontal: 30px;
  --f7-swipeout-button-font-size: inherit;
  --f7-swipeout-button-font-weight: inherit;
}
.md {
  --f7-swipeout-button-padding-horizontal: 24px;
  --f7-swipeout-button-font-size: 14px;
  --f7-swipeout-button-font-weight: 500;
}
.md .dark,
.md.dark {
  --f7-swipeout-button-text-color: #000;
}

示例

swipeout.html
<template>
  <div class="page">
    <div class="navbar">
      <div class="navbar-bg"></div>
      <div class="navbar-inner sliding">
        <div class="title">Swipeout</div>
      </div>
    </div>
    <div class="page-content">
      <div class="block">
        <p>
          Swipe out actions on list elements is one of the most awesome F7 features. It allows you to call hidden menu
          for each list element where you can put default ready-to use delete button or any other buttons for some
          required actions.
        </p>
      </div>
      <div class="block-title">Swipe to delete with confirm modal</div>
      <div class="list list-strong list-outline-ios list-dividers-ios inset-md">
        <ul>
          <li class="swipeout">
            <div class="item-content swipeout-content">
              <div class="item-media"><i class="icon icon-f7"></i>
              </div>
              <div class="item-inner">
                <div class="item-title">Swipe left on me please</div>
              </div>
            </div>
            <div class="swipeout-actions-right">
              <a data-confirm="Are you sure you want to delete this item?" class="swipeout-delete">Delete</a>
            </div>
          </li>
          <li class="swipeout">
            <div class="item-content swipeout-content">
              <div class="item-media"> <i class="icon icon-f7"></i>
              </div>
              <div class="item-inner">
                <div class="item-title">Swipe left on me too</div>
              </div>
            </div>
            <div class="swipeout-actions-right">
              <a data-confirm="Are you sure you want to delete this item?" class="swipeout-delete">Delete</a>
            </div>
          </li>
          <li>
            <div class="item-content">
              <div class="item-media">
                <i class="icon icon-f7"></i>
              </div>
              <div class="item-inner">
                <div class="item-title">I am not removable</div>
              </div>
            </div>
          </li>
        </ul>
      </div>
      <div class="block-title">Swipe to delete without confirm</div>
      <div class="list list-strong list-outline-ios list-dividers-ios inset-md">
        <ul>
          <li class="swipeout">
            <div class="item-content swipeout-content">
              <div class="item-inner">
                <div class="item-title">Swipe left on me please</div>
              </div>
            </div>
            <div class="swipeout-actions-right">
              <a class="swipeout-delete">Delete</a>
            </div>
          </li>
          <li class="swipeout">
            <div class="item-content swipeout-content">
              <div class="item-inner">
                <div class="item-title">Swipe left on me too</div>
              </div>
            </div>
            <div class="swipeout-actions-right">
              <a class="swipeout-delete">Delete</a>
            </div>
          </li>
          <li>
            <div class="item-content">
              <div class="item-inner">
                <div class="item-title">I am not removable</div>
              </div>
            </div>
          </li>
        </ul>
      </div>
      <div class="block-title">Swipe for actions</div>
      <div class="list list-strong list-outline-ios list-dividers-ios inset-md">
        <ul>
          <li class="swipeout">
            <div class="item-content swipeout-content">
              <div class="item-media">
                <i class="icon icon-f7"></i>
              </div>
              <div class="item-inner">
                <div class="item-title">Swipe left on me please</div>
              </div>
            </div>
            <div class="swipeout-actions-right">
              <a @click=${more}>More</a>
              <a class="swipeout-delete">Delete</a>
            </div>
          </li>
          <li class="swipeout">
            <div class="item-content swipeout-content">
              <div class="item-media">
                <i class="icon icon-f7"></i>
              </div>
              <div class="item-inner">
                <div class="item-title">Swipe left on me too</div>
              </div>
            </div>
            <div class="swipeout-actions-right">
              <a @click=${more}>More</a>
              <a class="swipeout-delete">Delete</a>
            </div>
          </li>
          <li class="swipeout">
            <div class="item-content swipeout-content">
              <div class="item-media">
                <i class="icon icon-f7"></i>
              </div>
              <div class="item-inner">
                <div class="item-title">You can't delete me</div>
              </div>
            </div>
            <div class="swipeout-actions-right">
              <a @click=${more}>More</a>
            </div>
          </li>
        </ul>
      </div>
      <div class="block-title">With callback on remove</div>
      <div class="list list-strong list-outline-ios list-dividers-ios inset-md">
        <ul>
          <li class="swipeout" @swipeout:deleted=${onDeleted}>
            <div class="item-content swipeout-content">
              <div class="item-inner">
                <div class="item-title">Swipe left on me please</div>
              </div>
            </div>
            <div class="swipeout-actions-right">
              <a class="swipeout-delete">Delete</a>
            </div>
          </li>
          <li class="swipeout" @swipeout:deleted=${onDeleted}>
            <div class="item-content swipeout-content">
              <div class="item-inner">
                <div class="item-title">Swipe left on me too</div>
              </div>
            </div>
            <div class="swipeout-actions-right">
              <a class="swipeout-delete">Delete</a>
            </div>
          </li>
          <li>
            <div class="item-content">
              <div class="item-inner">
                <div class="item-title">I am not removable</div>
              </div>
            </div>
          </li>
        </ul>
      </div>
      <div class="block-title">With actions on left side (swipe to right)</div>
      <div class="list list-strong list-outline-ios list-dividers-ios inset-md">
        <ul>
          <li class="swipeout">
            <div class="item-content swipeout-content">
              <div class="item-media">
                <i class="icon icon-f7"></i>
              </div>
              <div class="item-inner">
                <div class="item-title">Swipe right on me please</div>
              </div>
            </div>
            <div class="swipeout-actions-left">
              <a class="color-green" @click=${reply}>Reply</a>
              <a class="color-blue" @click=${forward}>Forward</a>
            </div>
          </li>
          <li class="swipeout">
            <div class="item-content swipeout-content">
              <div class="item-media">
                <i class="icon icon-f7"></i>
              </div>
              <div class="item-inner">
                <div class="item-title">Swipe right on me too</div>
              </div>
            </div>
            <div class="swipeout-actions-left">
              <a class="color-green" @click=${reply}>Reply</a>
              <a class="color-blue" @click=${forward}>Forward</a>
            </div>
          </li>
        </ul>
      </div>
      <div class="block-title">On both sides with overswipes</div>
      <div class="list media-list list-strong list-outline-ios list-dividers-ios inset-md">
        <ul>
          <li class="swipeout">
            <div class="swipeout-content">
              <a class="item-link item-content">
                <div class="item-inner">
                  <div class="item-title-row">
                    <div class="item-title">Facebook</div>
                    <div class="item-after">17:14</div>
                  </div>
                  <div class="item-subtitle">New messages from John Doe</div>
                  <div class="item-text">
                    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla sagittis tellus ut turpis
                    condimentum, ut dignissim lacus tincidunt. Cras dolor metus, ultrices condimentum sodales sit amet,
                    pharetra sodales eros. Phasellus vel felis tellus. Mauris rutrum ligula nec dapibus feugiat. In vel
                    dui laoreet, commodo augue id, pulvinar lacus.
                  </div>
                </div>
              </a>
            </div>
            <div class="swipeout-actions-left">
              <a class="color-green swipeout-overswipe" @click=${reply}>Reply</a>
              <a class="color-blue" @click=${forward}>Forward</a>
            </div>
            <div class="swipeout-actions-right">
              <a @click=${more}>More</a>
              <a class="color-orange" @click=${mark}>Mark</a>
              <a data-confirm="Are you sure you want to delete this item?"
                class="swipeout-delete swipeout-overswipe">Delete</a>
            </div>
          </li>
          <li class="swipeout">
            <div class="swipeout-content">
              <a class="item-link item-content">
                <div class="item-inner">
                  <div class="item-title-row">
                    <div class="item-title">John Doe (via Twitter)</div>
                    <div class="item-after">17:11</div>
                  </div>
                  <div class="item-subtitle">John Doe (@_johndoe) mentioned you on Twitter!</div>
                  <div class="item-text">
                    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla sagittis tellus ut turpis
                    condimentum, ut dignissim lacus tincidunt. Cras dolor metus, ultrices condimentum sodales sit amet,
                    pharetra sodales eros. Phasellus vel felis tellus. Mauris rutrum ligula nec dapibus feugiat. In vel
                    dui laoreet, commodo augue id, pulvinar lacus.
                  </div>
                </div>
              </a>
            </div>
            <div class="swipeout-actions-left">
              <a class="color-green swipeout-overswipe" @click=${reply}>Reply</a>
              <a class="color-blue" @click=${forward}>Forward</a>
            </div>
            <div class="swipeout-actions-right">
              <a @click=${more}>More</a>
              <a class="color-orange" @click=${mark}>Mark</a>
              <a data-confirm="Are you sure you want to delete this item?"
                class="swipeout-delete swipeout-overswipe">Delete</a>
            </div>
          </li>
          <li class="swipeout">
            <div class="swipeout-content">
              <a class="item-link item-content">
                <div class="item-inner">
                  <div class="item-title-row">
                    <div class="item-title">Facebook</div>
                    <div class="item-after">16:48</div>
                  </div>
                  <div class="item-subtitle">New messages from John Doe</div>
                  <div class="item-text">
                    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla sagittis tellus ut turpis
                    condimentum, ut dignissim lacus tincidunt. Cras dolor metus, ultrices condimentum sodales sit amet,
                    pharetra sodales eros. Phasellus vel felis tellus. Mauris rutrum ligula nec dapibus feugiat. In vel
                    dui laoreet, commodo augue id, pulvinar lacus.
                  </div>
                </div>
              </a>
            </div>
            <div class="swipeout-actions-left">
              <a class="color-green swipeout-overswipe" @click=${reply}>Reply</a>
              <a class="color-blue" @click=${forward}>Forward</a>
            </div>
            <div class="swipeout-actions-right">
              <a @click=${more}>More</a>
              <a class="color-orange" @click=${mark}>Mark</a>
              <a data-confirm="Are you sure you want to delete this item?"
                class="swipeout-delete swipeout-overswipe">Delete</a>
            </div>
          </li>
          <li class="swipeout">
            <div class="swipeout-content">
              <a class="item-link item-content">
                <div class="item-inner">
                  <div class="item-title-row">
                    <div class="item-title">John Doe (via Twitter)</div>
                    <div class="item-after">15:32</div>
                  </div>
                  <div class="item-subtitle">John Doe (@_johndoe) mentioned you on Twitter!</div>
                  <div class="item-text">
                    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla sagittis tellus ut turpis
                    condimentum, ut dignissim lacus tincidunt. Cras dolor metus, ultrices condimentum sodales sit amet,
                    pharetra sodales eros. Phasellus vel felis tellus. Mauris rutrum ligula nec dapibus feugiat. In vel
                    dui laoreet, commodo augue id, pulvinar lacus.
                  </div>
                </div>
              </a>
            </div>
            <div class="swipeout-actions-left">
              <a class="color-green swipeout-overswipe" @click=${reply}>Reply</a>
              <a class="color-blue" @click=${forward}>Forward</a>
            </div>
            <div class="swipeout-actions-right">
              <a @click=${more}>More</a>
              <a class="color-orange" @click=${mark}>Mark</a>
              <a data-confirm="Are you sure you want to delete this item?"
                class="swipeout-delete swipeout-overswipe">Delete</a>
            </div>
          </li>
        </ul>
      </div>
    </div>
  </div>
</template>
<script>
  export default (props, { $f7, $onMounted, $onBeforeUnmount }) => {
    let actions;
    const more = () => {
      actions.open();
    }
    const mark = () => {
      $f7.dialog.alert('Mark');
    }
    const reply = () => {
      $f7.dialog.alert('Reply');
    }
    const forward = () => {
      $f7.dialog.alert('Forward');
    }
    const onDeleted = () => {
      $f7.dialog.alert('Thanks, item removed!');
    }

    $onBeforeUnmount(() => {
      actions.destroy();
    })

    $onMounted(() => {
      actions = $f7.actions.create({
        buttons: [
          [
            {
              text: 'Here comes some optional description or warning for actions below',
              label: true,
            },
            {
              text: 'Action 1',
            },
            {
              text: 'Action 2',
            },
          ],
          [
            {
              text: 'Cancel',
              strong: true,
            }
          ]
        ],
      })
    })

    return $render;
  }
</script>