Building a Slider Captcha Component with Vue 3, Vite, and Canvas

This article guides developers through creating a customizable slider captcha component using Vue 3 and Vite, covering component design principles, Canvas drawing techniques, event handling, API configuration, and publishing the component to npm, with complete code examples.

Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Rare Earth Juejin Tech Community
Building a Slider Captcha Component with Vue 3, Vite, and Canvas

The article introduces a new graphics practice: implementing a sliding verification (captcha) component using Vue 3 and Vite. It begins with a brief overview of the component's purpose and the design principles such as readability, usability, reusability, maintainability, and performance.

Component Design and API

Key configurable props include visibility, size (width, height), slider dimensions (l, r), text tip, image source, and several callbacks (onSuccess, onFail, onCustomVertify, onDraw, onRefresh, etc.). These enable flexible integration into various projects.

Canvas Drawing Basics

The implementation relies on Canvas APIs like beginPath(), moveTo(), arc(), lineTo(), stroke(), fill(), and clip(). The globalCompositeOperation property is used to control how the cut‑out shape is composited over the background image.

const drawPath = (ctx, x, y, operation) => {
  ctx.beginPath();
  ctx.moveTo(x, y);
  ctx.arc(x + l / 2, y - r + 2, r, 0.72 * PI, 2.26 * PI);
  ctx.lineTo(x + l, y);
  ctx.arc(x + l + r - 2, y + l / 2, r, 1.21 * PI, 2.78 * PI);
  ctx.lineTo(x + l, y + l);
  ctx.lineTo(x, y + l);
  ctx.arc(x + r - 2, y + l / 2, r + 0.4, 2.76 * PI, 1.24 * PI, true);
  ctx.lineTo(x, y);
  ctx.lineWidth = 2;
  ctx.fillStyle = "rgba(255, 255, 255, 0.7)";
  ctx.strokeStyle = "rgba(255, 255, 255, 0.7)";
  ctx.stroke();
  ctx.globalCompositeOperation = "destination-over";
  operation === "fill" ? ctx.fill() : ctx.clip();
};

Component Skeleton (Vue 3 + TypeScript)

<script lang="ts" setup>
import { ref, watch, onMounted } from "vue";

interface VertifyType {
  spliced: boolean;
  verified: boolean;
  left: number;
  destX: number;
}

interface IProps {
  width?: number;
  visible?: boolean;
  height?: number;
  refreshIcon?: string;
  l?: number;
  r?: number;
  imgUrl?: string;
  text?: string;
  onDraw?: (l: number) => {};
  onCustomVertify?: (arg: VertifyType) => VertifyType;
  onBeforeRefresh?: () => void;
  onSuccess?: VoidFunction;
  onFail?: VoidFunction;
  onRefresh?: VoidFunction;
}

const props = withDefaults(defineProps<IProps>(), {
  width: 320,
  visible: true,
  height: 160,
  refreshIcon: "http://cdn.dooring.cn/dr/icon12.png",
  l: 42,
  r: 9,
  imgUrl: "",
  text: "",
});

// refs for DOM elements and state
const canvasRef = ref<any>(null);
const blockRef = ref<any>(null);
const isMouseDownRef = ref<boolean>(false);
const sliderLeft = ref(0);
const textTip = ref(props.text);
const PI = Math.PI;
const L = props.l + props.r * 2 + 3;
// ... other reactive variables
</script>

Event handling for dragging uses onMouseDown, onMouseMove, and onMouseUp (or touch equivalents) to update the slider position, calculate the trail, and trigger success/failure callbacks based on verification logic.

const handleDragMove = (e) => {
  if (!isMouseDownRef.value) return false;
  e.preventDefault();
  const eventX = e.clientX || e.touches[0].clientX;
  const eventY = e.clientY || e.touches[0].clientY;
  const moveX = eventX - originXRef.value;
  const moveY = eventY - originYRef.value;
  if (moveX < 0 || moveX + 36 >= width) return false;
  sliderLeft.value = moveX;
  const blockLeft = (width - props.l - 2 * props.r) / (width - props.l) * moveX;
  blockRef.value.style.left = blockLeft + 'px';
};

After the component is complete, the article shows how to package it with Vite, configure the library build, and publish the distribution to npm. Example Vite config and npm installation commands are provided.

export default defineConfig({
  ...baseConfig,
  build: {
    outDir: 'dist',
    lib: {
      entry: resolve(__dirname, '../packages/index.ts'),
      name: 'vue-slider-vertify',
      fileName: (format) => `vue-slider-vertify.${format}.js`,
    },
    rollupOptions: {
      external: ['vue'],
      output: {
        globals: { vue: 'Vue' },
      },
    },
  },
  plugins: [...baseConfig.plugins, dts()],
});

Finally, the article encourages readers to explore further graphics applications such as 3D visualization, editors, and charts, and invites contributions via the author's GitHub repositories.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

frontend developmentCanvasComponent LibraryVue3Slider Captcha
Rare Earth Juejin Tech Community
Written by

Rare Earth Juejin Tech Community

Juejin, a tech community that helps developers grow.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.