• Moegirl.ICU:萌娘百科流亡社群 581077156(QQ),欢迎对萌娘百科运营感到失望的编辑者加入
  • Moegirl.ICU:账号认领正在试运行,有意者请参照账号认领流程

Module:Slider

萌娘百科,万物皆可萌的百科全书!转载请标注来源页面的网页链接,并声明引自萌娘百科。内容不可商用。
跳转到导航 跳转到搜索
Template-info.svg 模块文档  [创建] [刷新]
local p = {}

function p.init(frame)
    local args = frame.args
    local sliderId = args.id or 'slider-' .. tostring(math.random(10000))
    
    return mw.html.create('div')
        :addClass('slider-container')
        :attr('id', sliderId)
        :node(mw.html.create('div'):addClass('slider-track'))
        :node(mw.html.create('div'):addClass('slider-thumb')
            :node(mw.html.create('div'):addClass('slider-icon')))
        :node(mw.html.create('div'):addClass('slider-value')
            :wikitext((args.value or 50) .. ((tonumber(args.max or 100) <= 100) and '%' or '')))
        :node(args['show-minmax'] ~= 'false' and 
            mw.html.create('div'):addClass('slider-minmax slider-min')
                :wikitext(args.min or '0') or nil)
        :node(args['show-minmax'] ~= 'false' and 
            mw.html.create('div'):addClass('slider-minmax slider-max')
                :wikitext(args.max or '100') or nil)
        :tag('script')
            :wikitext(string.format([[
                (function() {
                    var slider = document.getElementById('%s');
                    var thumb = slider.querySelector('.slider-thumb');
                    var track = slider.querySelector('.slider-track');
                    var valueDisplay = slider.querySelector('.slider-value');
                    
                    // 配置
                    var config = {
                        leftColor: '%s',
                        rightColor: '%s',
                        thumbColor: '%s',
                        thumbIconColor: '%s',
                        value: %d,
                        min: %d,
                        max: %d,
                        step: %d
                    };
                    
                    // 设置颜色
                    track.style.background = 'linear-gradient(to right, ' + config.leftColor + ', ' + config.rightColor + ')';
                    thumb.style.backgroundColor = config.thumbColor;
                    thumb.querySelector('.slider-icon').style.backgroundColor = config.thumbIconColor;
                    
                    // 计算实际值
                    function calculateValue(percent) {
                        return config.min + (percent / 100) * (config.max - config.min);
                    }
                    
                    // 计算百分比
                    function calculatePercent(value) {
                        return ((value - config.min) / (config.max - config.min)) * 100;
                    }
                    
                    // 更新滑块位置和显示
                    function updateSlider(value) {
                        value = Math.max(config.min, Math.min(config.max, value));
                        var percent = calculatePercent(value);
                        thumb.style.left = 'calc(' + percent + '% - 12px)';
                        
                        // 格式化显示值
                        var displayValue;
                        if (config.max <= 100) {
                            displayValue = Math.round(value) + '%%';
                        } else {
                            displayValue = Math.round(value);
                        }
                        valueDisplay.textContent = displayValue;
                    }
                    
                    // 初始化
                    updateSlider(config.value);
                    
                    // 事件处理
                    var isDragging = false;
                    
                    function startDrag(e) {
                        isDragging = true;
                        e.preventDefault();
                    }
                    
                    function drag(e) {
                        if (!isDragging) return;
                        
                        var rect = track.getBoundingClientRect();
                        var clientX = e.clientX || (e.touches && e.touches[0].clientX);
                        if (!clientX) return;
                        
                        var pos = (clientX - rect.left) / rect.width;
                        pos = Math.max(0, Math.min(1, pos));
                        var value = config.min + Math.floor(pos * (config.max - config.min) / config.step) * config.step;
                        updateSlider(value);
                        
                        // 触发自定义事件
                        var event = new CustomEvent('sliderChange', {
                            detail: {
                                id: '%s',
                                value: value,
                                percent: pos * 100
                            }
                        });
                        slider.dispatchEvent(event);
                    }
                    
                    function endDrag() {
                        isDragging = false;
                    }
                    
                    thumb.addEventListener('mousedown', startDrag);
                    thumb.addEventListener('touchstart', startDrag);
                    document.addEventListener('mousemove', drag);
                    document.addEventListener('touchmove', drag);
                    document.addEventListener('mouseup', endDrag);
                    document.addEventListener('touchend', endDrag);
                    
                    track.addEventListener('click', function(e) {
                        var rect = track.getBoundingClientRect();
                        var pos = (e.clientX - rect.left) / rect.width;
                        var value = config.min + Math.floor(pos * (config.max - config.min) / config.step) * config.step;
                        updateSlider(value);
                        
                        var event = new CustomEvent('sliderChange', {
                            detail: {
                                id: '%s',
                                value: value,
                                percent: pos * 100
                            }
                        });
                        slider.dispatchEvent(event);
                    });
                    
                    // 暴露API
                    slider.updateValue = function(value) {
                        updateSlider(value);
                    };
                    
                    slider.getValue = function() {
                        return calculateValue(parseInt(thumb.style.left) / (track.offsetWidth - thumb.offsetWidth) * 100);
                    };
                })();
            ]], 
            sliderId,
            args['left-color'] or '#24b44a',
            args['right-color'] or args['left-color'] or '#24b44a',
            args['thumb-color'] or '#ffffff',
            args['thumb-icon-color'] or '#333333',
            tonumber(args.value) or 50,
            tonumber(args.min) or 0,
            tonumber(args.max) or 100,
            tonumber(args.step) or 1,
            sliderId,
            sliderId))
end

return p