You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pixi JS实现Mute静音切换按钮 点击切换状态与对应图标

PixiJS 静音切换按钮实现修正方案

原代码核心问题

  • 逻辑混淆:误将按钮的可交互控制方法enable()/disable()和静音业务状态绑定,这两个方法的作用是控制按钮是否响应点击,不是用来切换静音/非静音状态
  • 纹理赋值错误:直接将图片路径字符串赋值给Sprite.texture是无效的,Pixi需要使用预加载后存在纹理缓存中的PIXI.Texture对象
  • 状态缺失:没有维护内部的静音状态标记,也没有绑定点击后切换状态、更新图标的逻辑
  • 语法错误:create()方法中设置back.pivot时引用了未定义的mute变量,会直接抛出运行时错误
  • 事件逻辑断层:父类绑定的点击事件直接执行传入的action回调,没有衔接按钮自身的状态切换流程,且事件回调未绑定this上下文,容易出现指向错误

前置要求

确保两个图标资源已经通过PIXI.Loader完成预加载,否则无法从缓存中读取到对应纹理。

修正后的代码

1. 基础ButtonView类微调

原父类不需要大改,只需要调整点击事件的触发逻辑,让子类可以在执行外部传入的action前先处理自身状态:

import { GlowFilter } from "pixi-filters";
import { Timeline } from "gsap/gsap-core";

export default class ButtonView extends PIXI.Container {
    constructor(options) {
        super()
        this.name = options.name || 'button'
        this.text = options.text || 'button'
        // 保存外部传入的回调
        this.externalAction = options.action || this.noAction
        // 点击事件统一绑定到内部的onClick方法,方便子类重写扩展
        this.on('click', this.onClick.bind(this))
        this.on('tap', this.onClick.bind(this))

        this.timeLine = new Timeline()
        this.outlineFilter = new GlowFilter({ outerStrength: 0, color: 0xffffff, distance: 20 })
        this.filters = [this.outlineFilter]

        this.setInteractive(true)
        this.on('pointerup', this.pointerUp.bind(this))
        this.on('pointerdown', this.pointerDown.bind(this))
        this.on('pointerover', this.pointerOver.bind(this))
        this.on('pointerout', this.pointerOut.bind(this))
    }

    // 内部点击处理方法,子类可重写扩展
    onClick() {
        this.externalAction()
    }

    setInteractive(bool) {
        this.interactive = bool
        this.buttonMode = bool
    }

    pointerUp() {
        this.scale.set(1)
    }

    pointerDown() {
        this.scale.set(0.95)
    }

    pointerOver() {
        this.timeLine.clear()
        this.timeLine.to(this.outlineFilter, .3, { outerStrength: 2 })
    }

    pointerOut() {
        this.timeLine.clear()
        this.timeLine.to(this.outlineFilter, .3, { outerStrength: 0 })
    }

    enable() {
        this.setInteractive(true)
    }

    disable() {
        this.setInteractive(false)
    }

    noAction() {
        console.log('ButtonView no action')
    }
}

2. 修正后的MuteView静音按钮类

import ButtonView from "./ButtonView"

export default class MuteView extends ButtonView {
    constructor(options) {
        super(options)
        // 初始化静音状态,默认非静音
        this.isMuted = options.isMuted || false
        // 预存两个状态对应的纹理资源
        this.textures = {
            mute: PIXI.Texture.from('./images/mute_icon.png'),
            unmute: PIXI.Texture.from('./images/unmute_icon.png')
        }

        this.header = new PIXI.Text('mute', { fill: 0xeeeeee, fontSize: 20 })
        this.addChild(this.header)
        this.create()
        // 初始化时根据默认状态更新图标
        this.updateIcon()
    }

    create() {
        const btnMute = PIXI.Sprite.from('./images/mute_box.png')
        btnMute.anchor.set(0.5)

        this.btnSprite = new PIXI.Sprite(this.textures.unmute)
        this.btnSprite.anchor.set(0.5)
        // 图标通过锚点居中放在按钮背景上,不需要手动计算坐标差
        this.btnSprite.position.set(0, 0)

        // 修复原代码中未定义mute变量的错误
        const back = new PIXI.Graphics()
        back.drawRect(-btnMute.width/2, -btnMute.height/2, btnMute.width, btnMute.height)

        this.btn = new PIXI.Container()
        this.btn.addChild(btnMute, this.btnSprite)
        this.addChild(back, this.btn)
    }

    // 重写父类点击方法,先切换自身状态再执行外部回调
    onClick() {
        this.toggleMute()
        // 执行外部传入的回调,把当前静音状态传出去
        this.externalAction(this.isMuted)
    }

    // 切换静音状态
    toggleMute() {
        this.isMuted = !this.isMuted
        this.updateIcon()
        // 在这里添加实际的静音逻辑即可,比如:
        // Howler.mute(this.isMuted) 或者 audioElement.muted = this.isMuted
    }

    // 根据当前状态更新图标
    updateIcon() {
        this.btnSprite.texture = this.isMuted ? this.textures.mute : this.textures.unmute
    }

    pointerUp() {
        this.btn.scale.set(1)
    }

    pointerDown() {
        this.btn.scale.set(0.95)
    }

    // 保留enable/disable原本控制交互的功能,和业务状态完全分离
    enable() {
        super.enable()
        this.alpha = 1
    }

    disable() {
        super.disable()
        this.alpha = 0.5
    }
}

使用方式

// 初始化静音按钮
const muteBtn = new MuteView({
    name: 'muteBtn',
    isMuted: false,
    action: (isMuted) => {
        console.log('当前静音状态:', isMuted)
        // 此处编写全局静音的业务逻辑
    }
})
// 将按钮添加到舞台
app.stage.addChild(muteBtn)

内容的提问来源于stack exchange,提问作者Deni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 03:45:38