scss / less 转换成css 包含有scope设置 - 戴向天

33 篇文章 0 订阅
6 篇文章 0 订阅

大家好!我叫戴向天。

QQ群:602504799

可设置样式scoped作用域
scss/less转换的时候暂不支持 变量 以及 函数处理


/**
 * author: 戴向天
 * time: 2022-03-03
 * QQ: 809002582
 * desc:
 *      可设置样式scoped作用域
 *      scss to css / less to css
 *      scss/less转换的时候暂不支持 变量 以及 函数处理
 */

/**
 * scss to css / less to css
 * @param text string;
 * @param scopedId? string;
 */
function toCss(text: string, scopedId?: string) {
    let content = text.replace(/\/*(.+)\*\//g, '');
    content = toCss.removeNotes(content)    // 去掉注释
    const json = toCss.toJSON(content, scopedId)
    const perfectNameResult = toCss.perfectName(json)
    const mergeResult = toCss.mergeJSON(perfectNameResult)
    const textResult = toCss.toText(mergeResult)
    return toCss.format(textResult)
}

// css 样式格式化
toCss.format = function (text: string) {
    // 格式化代码
    let s = text.replace(/\s*([\{\}\:\;\,])\s*/g, '$1');
    s = s.replace(/;\s*;/g, ';'); // 清除连续分号
    s = s.replace(/\,[\s\.\#\d]*{/g, '{');
    s = s.replace(/([^\s])\{([^\s])/g, '$1 {\n\t$2');
    s = s.replace(/([^\s])\}([^\n]*)/g, '$1\n}\n$2');
    s = s.replace(/([^\s]);([^\s\}])/g, '$1;\n\t$2');
    return s;
}


/**
 * 将样式表内容转换成json数据
 * @param text string;
 */
toCss.toJSON = function (text: string, scopedId?: string) {
    let s = text.replace(/\s*([\{])\s*/g, '{\n')   // 左大括号换行
    s = s.replace(/\s*([\}])\s*/g, '\n}\n') // 右大括号换行
    s = s.replace(/\s*([;])\s*/g, ';\n')    // 分号换行
    s = s.replace(/;\s*;/g, ';')           // 清除连续分号
    s = s.replace(/,\s*\n\s*/g, ',')       // 逗号合并一行

    const sa = s.split(/\n/).filter(row => row.trim())  // 去掉空白行

    let res = sa.map((str: string) => {
        // 判断是不是样式名称行
        if (str.indexOf('{') > 0) {
            const result = str.split('{')
            // 设置作用域
            if (scopedId) {
                const names = result[0].split(',')
                const newName = names.map(name => {
                    if (name.indexOf(':') >= 0) {
                        const ns = name.split(':')
                        const n = ns.shift()
                        return `${n}[${scopedId}]:${ns.join(':')}`
                    }
                    return `${name}[${scopedId}]`
                }).join(',')
                return `${newName}:{`
            }
            return `"${result[0]}":{`
        }
        // 样式属性行
        if (str.indexOf(':') >= 0 && str.indexOf('{') < 0) {
            const result = str.split(':')
            return `"${result[0]}":"${result[1]}",`
        }
        // 结束符处理
        if (str.trim().indexOf('}') === 0) {
            return '},'
        }

        return str
    }).join('')

    res = res.substring(0, res.length - 1) // 去掉最后一个逗号

    return eval('({' + res + '})')  // 返回对象
}

/**
 * 去掉样式注释
 * @param text string;
 */
toCss.removeNotes = function (text: string) {
    // 去掉多行注释
    const s = text.replace(/\/\*.*\*\//g, '')
    // 换成行数数组
    const sa = s.split(/\n/)
    // 去掉单行数组
    const result = sa.reduce(function (total: string[], str: string) {
        if (str.indexOf('//') >= 0) {
            str = str.replace(/\/\/.*/, '')
        }
        total.push(str)
        return total
    }, []).join('\n')

    return result
}

/**
 * 完善名称
 * @param obj json;对象
 * @param parentKey  string;名称前缀
 * @returns 
 */
toCss.perfectName = function (obj: any, parentKey: string = '') {
    const keys = Object.keys(obj);
    return keys.reduce((total: any, key) => {
        const rightKey = key.replace(/\&/g, parentKey);
        total[rightKey] = typeof obj[key] === 'object' ? toCss.perfectName(obj[key], rightKey) : obj[key];
        return total;
    }, {});
}

/**
 * 合并成一个对象,没有曾经
 * @param obj cssJSON
 * @returns 
 */
toCss.mergeJSON = function (obj: { [key: string]: string }) {
    const res: any = {};
    function getSheet(params: any, parentKey?: string) {
        const objKeys = Object.keys(params).filter(key => typeof params[key] === 'object' && (parentKey || '').indexOf('@keyframes') < 0);
        objKeys.forEach((key: string) => {
            getSheet(params[key], key);
            delete params[key];
        }, {});
        if (parentKey && Object.keys(params).length > 0) {
            res[parentKey] = params;
        }
    }
    getSheet(obj);
    return res;
}

/**
 * json转样式表
 * @param obj json样式数据
 */
toCss.toText = function (obj: any) {
    return Object.keys(obj).reduce((content, key) => {
        const res: any = Object.keys(obj[key]).reduce((total, name) => {
            let value = obj[key][name]
            if (typeof obj[key][name] === 'object') {
                const child: any = {}
                child[name] = obj[key][name]
                value = toCss.toText(child)
                total += `${value}`;
            } else {
                total += `${name}: ${value}`;
            }


            return total;
        }, '');

        content += `
                ${key} {
                    ${res}
                }
            `;
        return content.replace(/\s\s+/g, ' ');
    }, '');
}

export default toCss;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值