vue3开发虚拟瀑布流组件

989 阅读3分钟

引言

作者为了找款好用的瀑布流组件,看了很多的开源库,发现都不是特别满意,我需要的是一个支持动态列数和虚拟列表的,所以打算自己撸一个。

不想看废话的可以拉到底部看源码

环境和框架版本

  • vue: 3.3.4
  • vite: 4.4.7
  • typescript: 5.1.6
  • pnpm: 8.6.10
  • node: 20.5.0

预览

image.png

开发

只列出部分,想查看全部源码,可以拉至最底部

├── src
│   └── vue-virtual-waterfall      // 组件源码,单独放一个文件夹内
│       ├── index.ts               // 组件导出
│       └── virtual-waterfall.vue  // 实现,按正常实现组件就行了,没特别说明
  • index.ts 组件导出特别提一下
import type { App } from 'vue'
import VirtualWaterfall from './virtual-waterfall.vue'

// 这里导出单个,可以单独引用
export { VirtualWaterfall }

// 这里导出一个默认对象,包含一个install方法,支持全局导入
export default {
    install(app: App) {
        app.component(VirtualWaterfall.name, VirtualWaterfall)
    }
}

// 在这里进行全局声明,不然全局安装时没有提示
declare module 'vue' {
    export interface GlobalComponents {
        VirtualWaterfall: typeof VirtualWaterfall
    }
}
  • 下面是vite的打包配置 vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// 如果是jsx写的组件需要引入这个,我用的template所以不用
// import vueJsx from '@vitejs/plugin-vue-jsx'

// 生成ts的声明文件,方便提示
import dts from 'vite-plugin-dts'
// 这个是把css写入到js里就不用单独引入样式文件了
// 如果样式比较少可以用这种方式,多的话就单独引入样式文件吧
import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
    let base = '/'
    let plugins = [
        vue()
    ]
    let build: Record<string, any> = {
        target: 'es2015',
        cssTarget: 'chrome61'
    }
    // vite build时可以传 `--mode npm`
    // 只有mode等于npm时才打包组件,否则的就可以预览组件了
    if (mode === 'npm') {
        plugins = [
            vue(),
            cssInjectedByJsPlugin(),
            dts({
                // 我们只需要组件这里生成声明文件,所以要指明位置
                entryRoot: 'src/vue-virtual-waterfall'
            })
        ]
        build = {
            // 兼容js
            target: 'es2015',
            // 兼容css
            cssTarget: 'chrome61',
            // 我们组件不需要public里的玩意
            copyPublicDir: false,
            lib: {
                // 这是入口文件
                entry: 'src/vue-virtual-waterfall/index.ts',
                // 最终生成的js格式,这里写三种常见的
                formats: ['cjs', 'es', 'umd'],
                // 全局引入时的名字
                name: 'VueVirtualWaterfall',
                // build后的文件名
                fileName: 'index'
            },
            // 我们不需要把vue里的东西打包进来,这里将其排除在外
            rollupOptions: {
                external: ['vue'],
                output: {
                    globals: {
                        vue: 'Vue'
                    },
                    exports: 'named'
                }
            }
        }
    }

    return {
        base,
        plugins,
        build
    }
})

发布

当然是使用github action进行发布,我希望提交后,自动识别package.json里的version属性发布版本,所以将要完成下面三步:

  1. 需要写个github的ci脚本(支持创建release)
  2. 写个提取version的脚本
  3. 发布到npm,这步的代码也放在2
  • 前置,发布到npm,package.json也要配置好,下面列几个关键的属性
{
  "name": "组件的名字",
  "version": "版本号",
  "license": "MIT",
  "type": "module",
  "scripts": {
    "build:npm": "vue-tsc && vite build --mode npm",
    "pub": "bash scripts/publish.sh"
  },
  "main": "dist/index.cjs",
  "module": "dist/index.js",
  "types": "dist/index.d.ts",
  "keywords": [
    "vue3",
    "waterfall",
    "virtual-list"
  ],
  "files": [
    "dist",
    "README.md",
    "LICENSE",
    "package.json"
  ]
}
  • 先写github action的脚本
name: Publish Package

on:
  push:
    branches:
      - main

jobs:
  publish:
    runs-on: ubuntu-latest
    environment: Release
    steps:
        # 把代码拷贝下来
      - name: Checkout
        uses: actions/checkout@v3
        
        # 我们使用的是pnpm
      - name: Install pnpm
        uses: pnpm/action-setup@v2
        with:
          version: 8
        
        # 安装依赖
      - name: Install deps
        run: pnpm i --no-frozen-lockfile --shamefully-hoist

        # 使用的node
      - name: Use Node.js
        uses: actions/setup-node@v3
        with:
          node-version: 18
          registry-url: 'https://registry.npmjs.org/'
          cache: 'pnpm'
        
        # 打包
      - name: Build
        # 这里执行的是package.json里的一个命令,可以找下上面的
        run: pnpm build:npm
        
        # 这里也是调用package.json的命令,用于发布到npm
      - name: publish
        run: pnpm pub
        env:
          # 这里要设置npm的token
          NODE_AUTH_TOKEN: '${{secrets.NPM_AUTH_TOKEN}}'
        
        # 上面执行成功表示发布到了npm,然后我们要在github仓库里创建一个release
        # 这里的命令是为了把package.json里的version版本号提取出来,放在GITHUB_ENV里,供下面的使用
      - run: |
          echo "version=$(grep -o '"version": *"[^"]*"' package.json | awk -F'"' '{print $4}')" >> "$GITHUB_ENV"
        
        # 这里打印了一下提取的版本号,看下对不对
      - run: |
          echo "version: ${{ env.version }}"
        
        # 仓库创建一个release
      - uses: ncipollo/release-action@v1
        with:
          # 这里使用的版本号就是上面的提取的,可以按自己喜欢命名,我这里前面加了一个v
          tag: "v${{ env.version }}"
          # 我为了确认是否要发布release设置成草稿,ok我就发布release
          draft: true
          token: ${{ secrets.TOKEN }}
  • 发布到npm的脚本

上面有个pnpm pub,这是调用的是bash scripts/publish.sh脚本,我这里用的是shell,比较熟悉,也可以琢磨一下python、js

#!/bin/bash

# 发布版本
function pub(){
    # 获取项目package.json文件
    path="./package.json"
    # 获取项目版本号
    version=$(awk '/version/{gsub(/("|",)/,"",$2);print $2};' $path)

    if [ -z "$version" ]; then
         exit 1
    fi

    # 获取tag,npm支持多种tag,如果不指定,则会发布到latest
    # 我这里会根据版本号提取出tag,如
    # 0.0.1-beta 提取出beta
    # 0.1.1-next.0 提取出next
    # 1.0.0-alpha.11 提取出alpha
    # 2.0.0 提取出latest
    tag=${version#*-}
    tag=${tag%.*}
    case $tag in
        "alpha")  tag="alpha"
        ;;
        "beta")  tag="beta"
        ;;
        "next")  tag="next"
        ;;
        *)  tag="latest"
        ;;
    esac
    # 这里打印一下提取出的版本号和tag,如: 1.0.0 beta
    echo $version, $tag
    # 发布
    pnpm publish --no-git-checks --tag $tag --access=public
}

# 这里是调用上面的函数
pub

到此就发布好了

使用

不想写了,自己看源码吧

源码