普通视图

发现新文章,点击刷新页面。
今天 — 2025年6月29日首页

前端技术大放送,SSE 流式传输全攻略

2025年6月28日 23:49

探索前端新境界:SSE 流式传输的魅力

在前端开发的浩瀚宇宙中,总有一些技术如璀璨星辰,吸引着我们不断探索。今天,就让我们一同走进 SSE 流式传输的世界,感受它的独特魅力。

一、初遇 SSE

你还记得在使用某些智能应用,如 DeepSeek 时,输入问题后,答案仿佛具有魔法,能一点点地呈现在页面上吗?起初,我猜测这可能是 WebSocket 的神奇推送,但经过仔细检查网络请求,我发现并非如此,而是一种基于 HTTP 的特殊技术 —— SSE(Server-Sent Events)。

与 WebSocket 不同,SSE 并非基于 TCP 协议,而是依附于 HTTP 协议。它是一种单工通信模式,专为服务端向浏览器端实时推送消息而生。虽然功能相对有限,但却以其简洁轻便、易于实现而备受青睐。

二、SSE 与 WebSocket 的对比

为了更清晰地理解 SSE 的特点,让我们把它和 WebSocket 放在一起比较一番:

特性 SSE WebSocket
基础协议 HTTP 协议 TCP 协议
通信模式 单工(服务端到浏览器) 全双工(可双向通信)
复杂程度 轻量级,简单易用 相对复杂
断线重连 内置断线重连功能 需手动实现
消息类型 文本或经 Base64、gzip 处理的二进制消息 支持多种类型消息
自定义事件 支持自定义事件类型 不支持自定义事件类型
连接数量 HTTP/1.1 最多 6 个,HTTP/2 默认 100 个 无限制

从表中可见,若项目需求仅为服务端向浏览器端推送消息,且希望快速实现,SSE 当然是更优之选。

三、浏览器中的 SSE API

在浏览器端,我们主要借助 EventSource API 来与 SSE 服务器进行交互。

  1. 1. 建立连接 :通过 new EventSource(url) 创建实例,其中 url 为服务器端提供的接口地址。还可以传入可选的 options 参数,如 {withCredentials: true} ,用于处理跨域凭据问题。
  2. 2. 监听事件 :EventSource 实例提供了多种事件供我们监听,包括 onopen (连接建立)、onmessage (接收到消息)、onerror (出现错误)。除了系统预设事件,还能自定义事件类型,只需在服务器端指定事件名称即可。

四、实战封装 SSEService 类

为了方便在项目中使用 SSE,我们可以对其进行封装,创建一个 SSEService 类。

class SSEService {
    constructor() {
        this.eventSource = null;
        this.isClosing = false;
    }
    connect(url, options = {}) {
        if (this.eventSource) {
            this.disconnect();
        }
        this.eventSource = new EventSource(url);
        // 连接打开时的处理
        this.eventSource.onopen = () => {
            console.log('SSE 连接已建立');
            this.isClosing = false;
            if (options.onOpen) {
                options.onOpen();
            }
        };
        // 接收到消息时的处理
        this.eventSource.onmessage = event => {
            try {
                const data = JSON.parse(event.data);
                if (options.onMessage) {
                    options.onMessage(data);
                }
                // 假设 status 为 1 表示最后一条消息
                if (data.status === 1) {
                    this.isClosing = true;
                    this.disconnect();
                }
            } catch (error) {
                console.error('解析 SSE 消息失败:', error);
            }
        };
        // 出现错误时的处理
        this.eventSource.onerror = error => {
            if (this.isClosing) {
                return;
            }
            console.error('SSE 连接错误:', error, new Date().toLocaleString());
            if (options.onError) {
                options.onError(error);
            }
            this.disconnect();
        };
    }
    // 断开连接
    disconnect() {
        if (this.eventSource) {
            this.eventSource.close();
            this.eventSource = null;
            console.log('SSE 连接已关闭', new Date().toLocaleString());
        }
    }
}
export default SSEService;

在实际使用时,只需创建该类的实例,调用 connect 方法传入相应的 url 和回调函数即可。

const sseService = new SSEService();
const url = `/api/stream?query=${encodeURIComponent(query)}`;
sseService.connect(url, {
    onMessagedata => {
        // 在此处处理接收到的数据,如更新页面显示
        console.log('收到数据:', data);
    },
    onError() => {
        // 处理连接错误情况
        console.error('连接出错');
    }
});

五、应对流式传输的“小插曲”

在开发过程中,有时会遇到使用 webpack 打包后,流式传输效果不理想的情况 —— 本应逐步显示的数据却等到全部接收完后才一次性呈现。不用担心,这通常是因为 webpack 的代理服务器配置中 compress 设置为 true 导致的。只需将其改为 false,即可恢复正常的流式传输效果。

总之,SSE 流式传输技术在特定场景下能为我们带来流畅、实时的用户体验,其简洁的实现方式也为前端开发增添了一份便利。希望本文能帮助你开启 SSE 的精彩之旅,让前端应用更具活力。

昨天以前首页

自定义指令

2025年6月24日 18:39

前言

自定义指令是 Vue.js 提供的强大功能之一,它允许开发者创建可重用的指令,以实现特定的功能。这使得代码更加模块化、可维护,并且可以轻松地在多个地方复用。本文将介绍自定义指令的一些常见应用场景,并提供相应的代码示例。

表单验证

表单验证是 Web 开发中非常常见的需求。通过自定义指令,可以简化表单验证的逻辑,使其更加易于管理和复用。

// 验证手机号的自定义指令
Vue.directive('validate-mobile', {
  bind(el, binding, vnode) {
    el.addEventListener('blur', () => {
      const value = el.value;
      const pattern = /^1[3-9]\d{9}$/;
      if (!pattern.test(value)) {
        el.style.borderColor = 'red';
        el.style.backgroundColor = '#ffebebeb';
        el.style.boxShadow = '0 0 5px red';
        el.setCustomValidity('请输入有效的手机号');
        el.reportValidity();
      } else {
        el.style.borderColor = 'green';
        el.style.backgroundColor = '#e8f5e9';
        el.style.boxShadow = '0 0 5px green';
        el.setCustomValidity('');
      }
    });
  }
});

在模板中使用:

<input type="text" v-validate-mobile placeholder="请输入手机号">

表单操作

自定义指令可以用于简化表单的操作,例如禁用和启用表单元素。

// 禁用表单元素的自定义指令
Vue.directive('disable-form', {
  bind(el, binding, vnode) {
    el.disabled = binding.value;
  },
  update(el, binding) {
    el.disabled = binding.value;
  }
});

在模板中使用:

<input type="submit" value="提交" v-disable-form="isFormDisabled">

用户体验优化

自定义指令可以用来提升用户体验,例如实现点击outside关闭面板的功能。

// 点击outside关闭面板的自定义指令
Vue.directive('click-outside', {
  bind(el, binding, vnode) {
    el.clickOutsideEvent = function(event) {
      if (!(el == event.target || el.contains(event.target))) {
        vnode.context[binding.expression](event);
      }
    };
    document.body.addEventListener('click', el.clickOutsideEvent);
  },
  unbind(el) {
    document.body.removeEventListener('click', el.clickOutsideEvent);
  }
});

在模板中使用:

<div class="panel" v-click-outside="closePanel">
  <div class="panel-header">面板标题</div>
  <div class="panel-body">面板内容</div>
</div>
methods: {
  closePanel() {
    // 关闭面板的逻辑
  }
}

与 Vue 状态管理结合

自定义指令可以与 Vue 的状态管理(如 Vuex)结合使用,以实现更复杂的功能。

// 使用 Vuex 的自定义指令
Vue.directive('theme', {
  bind(el, binding, vnode) {
    const { store } = vnode.context;
    const theme = store.state.settings.theme;
    el.style.backgroundColor = theme === 'dark' ? '#333' : '#fff';
    el.style.color = theme === 'dark' ? '#fff' : '#333';
  }
});

在模板中使用:

<div v-theme></div>

总结

自定义指令在 Vue.js 中有着广泛的应用场景,从表单验证到用户体验优化,再到复杂的业务逻辑处理。通过合理使用自定义指令,可以极大地提高代码的可维护性和复用性。希望本文的示例能够帮助你更好地理解和运用自定义指令。

CSS 打造手电筒光照效果,超简单

2025年6月24日 18:38

CSS 打造手电筒光照效果,超简单!

在网页设计的世界里,总有一些小创意能给我们的页面增添别样的趣味。今天,我要和大家分享一个超好玩的技巧 —— 用 CSS 实现手电筒光照效果!宝子们,是不是听起来就很酷?别急,接着往下看,手把手教你搞定。

image.png

一、核心原理: radial - gradient 的魅力

这个神奇效果的关键就在于 background: radial-gradient() 。它能创建一个径向渐变,简单来说,就是颜色从一个中心点向四周发散开来的渐变效果。它的基本语法长这样:

background: radial-gradient([shape] [size] at [position], color1 [stop1], color2 [stop2], ...);

乍一看有点复杂,别慌!我来给大家拆解一下。[shape] 就是渐变的形状,比如 circle 表示圆形,ellipse 表示椭圆形;[size] 用来定义渐变的大小范围;at [position] 指定渐变的中心位置;后面跟着的就是各种颜色及其对应的停止位置啦。

咱直接看个简单的例子,感受一下这个渐变的神奇。假设我们写成:

background: radial-gradient(circle at 100px 100px, red, blue 50%, green 100%);

意思就是,创建一个圆形的径向渐变,中心在距离左上角 100px、100px 的位置。颜色从中心开始是红色,然后在 50% 的位置变成蓝色,最后在 100% 的位置变成绿色。是不是很直观?

二、打造手电筒光照效果:代码实战

好啦,光说不练假把式。直接上我们实现手电筒光照效果的完整代码吧:

<html>
<body>
<div class="flashlight"></div>
</body>
<style>
  html,
  body {
    width: 100%;
    height: 100%;
    background-image: url(https://fastly.jsdelivr.net/gh/bucketio/img16@main/2025/06/24/1750735460479-c318c8e9-df17-469d-a930-459784710ac7.png);
    background-repeat: no-repeat;
    background-size: cover;
    overflow: hidden;
  }

  .flashlight {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: radial-gradient(circle 100px at var(--x) var(--y), transparent 0%, transparent 5%, rgba(0, 0, 0, .5) 80%, rgba(0, 0, 0, .7) 90%, rgba(0, 0, 0, .8) 100%);
  }
</style>
<script>
  document.addEventListener('mousemove', (e) => {
    document.documentElement.style.setProperty('--x', `${e.clientX}px`);
    document.documentElement.style.setProperty('--y', `${e.clientY}px`);
  });
</script>
</html>

先给大家捋一捋。在 htmlbody 的样式里,我设置了一个全屏的背景图,还把重复和平铺啥的都禁掉,防止图片显示乱七八糟的。然后重点看咱们的 .flashlight 类。这个 position: absolute 就是让这个元素脱离文档流,方便我们全屏定位。关键是这个 background: radial-gradient() ,我设置了一个圆形的渐变,中心位置用 var(--x)var(--y) 来动态表示,后面跟着的就是光照效果从透明到较暗的颜色过渡啦。

最精彩的部分在 script 标签里。我监听了鼠标的移动事件,只要鼠标一动,就把鼠标的横纵坐标分别赋值给 --x--y ,这样咱们的光照效果就能跟着鼠标跑啦。是不是很巧妙?

三、效果展示与小结

宝子们,是不是很神奇?鼠标一动,就像手电筒的光在黑暗背景上扫来扫去。这个效果是不是瞬间让页面生动了起来?而且呢,这个办法超级简单,只要掌握了 radial-gradient 的用法,再配合点小脚本,分分钟就能搞定。

其实呢,这个小技巧在生活中也能用上。比如咱们做个悬疑类的网页游戏,玩家只能在手电筒光照范围内探索,增加神秘感;或者做个氛围感十足的夜间主题网页,这种光照效果一加,瞬间代入感拉满。不过呢,大家在用的时候可以多试试不同的颜色、渐变范围和透明度,说不定能整出更炫酷的效果呢。

宝子们,快去试试吧!要是觉得这个教程有用,别忘了点赞关注哦,咱们下期再见,拜拜 ~

❌
❌