npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

looplan-touch

v1.1.9

Published

触控操作组件

Downloads

11

Readme

Looplan Touch 触控库

Looplan Touch 是一个以 Vue3 + TypeScript 为基础的触控交互库,提供组件与方法用来实现拖拽、排序与跨组转移等交互能力。核心设计通过统一事件绑定和插件机制扩展触摸事件行为,适配表格、列表与栅格等多种布局场景。

安装

npm i looplan-touch

引入

import { LpDraggable, useSortable } from 'looplan-touch'

组件与方法

  • LpDraggable:拖拽组件,支持同组排序与跨组转移,内置过渡适配与预览态占位
  • useSortable(target, list, option):对现有 DOM 列表开启排序能力(例如表格 tr 行),适配过渡与方向

示例一:跨组拖动(组件)

模板:

<template>
  <div class="group-container">
    <div class="group">
      <h4>列表 A1</h4>
      <lp-draggable v-model="listA1" group="group-a" :allow-groups="['group-b']">
        <template #item="{ item, index }">
          <div class="custom-item group-a-item">
            <span class="item-icon">📋</span>
            <span class="item-text">{{ item.name }}</span>
            <span class="item-badge">A1-{{ index }}</span>
          </div>
        </template>
      </lp-draggable>
    </div>
    <div class="group">
      <h4>列表 A2</h4>
      <lp-draggable v-model="listA2" group="group-a" :allow-groups="['group-b']">
        <template #item="{ item, index }">
          <div class="custom-item group-a-item">
            <span class="item-icon">📊</span>
            <span class="item-text">{{ item.name }}</span>
            <span class="item-badge">A2-{{ index }}</span>
          </div>
        </template>
      </lp-draggable>
    </div>
  </div>
</template>

脚本:

import { ref } from 'vue'
import { LpDraggable } from 'looplan-touch'

const listA1 = ref([
  { name: '任务 A1-1' },
  { name: '任务 A1-2' },
  { name: '任务 A1-3' }
])

const listA2 = ref([
  { name: '任务 A2-1' },
  { name: '任务 A2-2' },
  { name: '任务 A2-3' },
  { name: '任务 A2-4' }
])

样式(简要):

.group-container { display: grid; gap: 20px }
.group { border: 2px solid #e9ecef; border-radius: 8px; padding: 16px }
.custom-item { display:flex; align-items:center; gap:12px; padding:12px; margin:8px 0; user-select:none }

LpDraggable Props

  • v-model: 列表数据(数组)
  • group: 分组名称,用于跨组识别
  • allow-groups: 允许接收的分组名数组
  • direction: 元素分布方向(x | y | xy | auto,默认 auto

LpDraggable 插槽

  • #item="{ item, index }":自定义子项渲染

示例二:表格排序(useSortable)

模板:

<template>
  <div ref="tableRef" class="test-table1">
    <lp-table :data="tableData" :columns="columns" row-key="id" row-transition-name="lp-drag-transition">
      <template #column.sort="{ item }">
        <div class="sort-field"><lp-icon is="sorting"></lp-icon></div>
      </template>
      <!-- 其它列略 -->
    </lp-table>
  </div>
</template>

脚本:

import { ref, onMounted, useTemplateRef, onUnmounted } from 'vue'
import { useSortable } from 'looplan-touch'

const tableRef = useTemplateRef('tableRef')
const tableData = ref([
  { id: 1, name: '张三', age: 18 },
  { id: 2, name: '李四', age: 19 },
  { id: 3, name: '王五', age: 20 }
])

let touchBox
onMounted(() => {
  ({ touchBox } = useSortable(tableRef, tableData, {
    targetClass: 'lp-table__tr',
    dragClass: 'sort-field',
    transitionName: 'lp-drag-transition',
    direction: 'auto'
  }))
})
onUnmounted(() => { touchBox.unbindEvent() })

useSortable Option

  • targetClass: 被排序的行元素类名(如 lp-table__tr
  • dragClass: 触发拖动的类名(如排序列里的图标容器)
  • transitionName: 过渡动画前缀(如 lp-drag-transition),用于检测过渡期间的碰撞过滤
  • idKey: 元素 id 键名(可选)
  • direction: 布局方向(x | y | xy | auto
  • onMove(params): 移动回调(可选)

示例三:同组排序(useSortable,跨两列)

模板:

<div ref="list1Ref" class="list drag-list">
  <transition-group name="lp-list-transition">
    <div class="custom-item lp-sortable__item" v-for="item in listA1" :key="item.id">{{ item.name }}</div>
  </transition-group>
  </div>
<div ref="list2Ref" class="list drag-list">
  <transition-group name="lp-list-transition">
    <div class="custom-item lp-sortable__item" v-for="item in listA2" :key="item.id">{{ item.name }}</div>
  </transition-group>
</div>

脚本:

import { ref, useTemplateRef, onUnmounted } from 'vue'
import { useSortable } from 'looplan-touch'

const listA1 = ref([{ id:'A1-1', name:'任务 A1-1' }, { id:'A1-2', name:'任务 A1-2' }])
const listA2 = ref([{ id:'A2-1', name:'任务 A2-1' }, { id:'A2-2', name:'任务 A2-2' }])

const listRef1 = useTemplateRef('list1Ref')
const listRef2 = useTemplateRef('list2Ref')

const { touchBox: tb1 } = useSortable(listRef1, listA1, {
  targetClass: 'lp-sortable__item',
  transitionName: 'lp-list-transition'
})
const { touchBox: tb2 } = useSortable(listRef2, listA2, {
  targetClass: 'lp-sortable__item',
  transitionName: 'lp-list-transition'
})

onUnmounted(() => { tb1.unbindEvent(); tb2.unbindEvent() })

行为与适配

  • 过渡适配:transition-grouptr 行过渡时不添加类名,库通过检测 transform 来过滤过渡元素命中
  • 命中解析:表格中拖动命中 td/th 时向上寻找对应 tr 行作为目标
  • 方向适配:direction: auto 会根据容器 flex-directionflex-wrap 推断为 x/y/xy
  • 尾部插入:computeIndexByPoint 会在指针位于最后一项之后(y 轴底部 / x 轴右侧 / xy 右下)返回 index + 1

许可

MIT