基于uniapp开发的微信小程序问题集锦

113 阅读4分钟

上一次写小程序还是五年前,最近心血来潮用uniapp开发了一款微信小程序应用,发现坑是真多啊,有些在我看来比较基础的东西,竟然是微信小程序官方底层的BUG,甚至BUG存在好几年了都不修复,离谱,最后只能曲线救国。用这篇文章记录一下以免后续遇到再浪费时间找解决方案。(持续更新)

注意:我只有ios机器,以下问题均在ios机型上复现,安卓机型不一定有这些问题

小程序问题汇总

1️⃣ textarea组件设置了maxlength时,拼音输入阶段会因为超过字数限制而被打断,无法正常输入中文,且光标位置错乱

1、将 maxlength 设置为 -1

2、在 @input 方法中

handleInput(e){
    //...
    return {
        cursor: e.detail.cursor,
        value: e.detail.value
    };
}

2️⃣ textarea组件,聚焦键盘弹出会遮挡文本域下面的内容

添加属性 :cursor-spacing="100"

3️⃣ input、textarea重新聚焦时光标始终在最前面,且用focus聚焦时仅第一次会聚焦失败

pages.json 文件中 globalStyle 属性中增加 "renderingMode": "seperated" 关闭同层渲染

注意:这个设置会关闭所有组件的同层渲染,会导致一些问题,如canvas组件在弹窗中时会有残影,关闭弹窗canvas的图形还在,所以要单独给canvas开启同层渲染:在globalStyle中增加属性 "mixedRenderComponents": ["canvas"]

4️⃣ 首次加载页面时,页面中的图片会全屏闪一下

image 标签 mode 属性使用 scaleToFill,再用css设置固定的长高

5️⃣ pre标签失效

设置css属性 white-space: pre-wrap;

6️⃣ 想实现计算器功能,但是eval函数不支持

使用自定义js函数代替:

...
try {
    console.log(expr)
    const result = this.safeEval(expr);
    return isNaN(result) ? "错误" : result.toString();
} catch (e) {
    console.log(e)
    return "错误";
}
...
/**
 * 安全计算表达式值(支持负数)
 * @param {string} expr 输入的数学表达式字符串
 * @returns {number} 计算结果
 * 
 * 支持功能:
 * - 四则运算:+、-、*、/
 * - 负数支持:包括一元运算符和负数操作数
 * - 括号支持:允许任意嵌套的括号
 * - 错误处理:无效表达式返回 NaN
 */
safeEval(expr) {
        // 1. 预处理:移除空格并验证表达式
        expr = expr.replace(/\s+/g, '');
        if (!expr) return NaN;

        // 2. 标记化处理(支持负数)
        const tokens = [];
        let current = '';

        for (let i = 0; i < expr.length; i++) {
                const char = expr[i];
                const isDigitOrDecimal = /[\d\.]/.test(char);
                const isOperator = /[\+\-\*\/\(\)]/.test(char);

                // 处理负数的特殊情况
                const isUnaryMinus = (
                        (char === '-') &&
                        (i === 0 || /[\+\-\*\/\(]/.test(expr[i - 1]))
                );

                if (isUnaryMinus) {
                        // 一元负号处理
                        if (current) tokens.push(current);
                        current = '-';
                } else if (isDigitOrDecimal) {
                        current += char;
                } else if (isOperator) {
                        if (current) {
                                tokens.push(current);
                                current = '';
                        }
                        tokens.push(char);
                }
        }

        if (current) tokens.push(current);

        // 3. 将一元负号转换为特殊标识
        const processedTokens = [];
        for (let i = 0; i < tokens.length; i++) {
                const token = tokens[i];
                if (token === '-' && (i === 0 || /[\+\-\*\/\(]/.test(tokens[i - 1]))) {
                        // 一元负号后面跟着左括号的处理
                        if (tokens[i + 1] === '(') {
                                processedTokens.push('~');
                        }
                        // 一元负号后面是数字的处理
                        else if (/^-?\d/.test(tokens[i + 1])) {
                                processedTokens.push('' + (-parseFloat(tokens[i + 1])));
                                i++;
                        }
                        // 其他情况
                        else {
                                processedTokens.push('~');
                        }
                } else {
                        processedTokens.push(token);
                }
        }

        // 4. 运算符优先级定义
        const precedence = {
                '~': 5, // 一元负号(最高优先级)
                '*': 4,
                '/': 4,
                '+': 3,
                '-': 3,
                '(': 0,
                ')': 0
        };

        // 5. 转换中缀表达式为后缀表达式(逆波兰表示法)
        const output = [];
        const operators = [];

        for (let token of processedTokens) {
                // 数字直接输出
                if (!isNaN(token)) {
                        output.push(parseFloat(token));
                }
                // 左括号压栈
                else if (token === '(') {
                        operators.push(token);
                }
                // 右括号处理
                else if (token === ')') {
                        while (operators.length > 0 && operators[operators.length - 1] !== '(') {
                                output.push(operators.pop());
                        }
                        if (operators[operators.length - 1] === '(') operators.pop();
                }
                // 运算符处理
                else {
                        while (
                                operators.length > 0 &&
                                precedence[operators[operators.length - 1]] >= precedence[token] &&
                                operators[operators.length - 1] !== '('
                        ) {
                                output.push(operators.pop());
                        }
                        operators.push(token);
                }
        }

        // 输出剩余运算符
        while (operators.length > 0) {
                output.push(operators.pop());
        }

        // 6. 计算后缀表达式
        const stack = [];

        for (let token of output) {
                if (typeof token === 'number') {
                        stack.push(token);
                }
                // 处理一元负号
                else if (token === '~') {
                        if (stack.length < 1) return NaN;
                        const a = stack.pop();
                        stack.push(-a);
                }
                // 二元运算符处理
                else {
                        if (stack.length < 2) return NaN;
                        const b = stack.pop();
                        const a = stack.pop();

                        switch (token) {
                                case '+':
                                        stack.push(a + b);
                                        break;
                                case '-':
                                        stack.push(a - b);
                                        break;
                                case '*':
                                        stack.push(a * b);
                                        break;
                                case '/':
                                        if (b === 0) return NaN; // 除零错误
                                        stack.push(a / b);
                                        break;
                                default:
                                        return NaN;
                        }
                }
        }

        // 7. 返回计算结果
        if (stack.length !== 1 || isNaN(stack[0])) {
                return NaN; // 无效表达式
        }

        return stack[0];
}

7️⃣ scroll-view组件将scroll-top设置为 0,置顶无效

需要动态设置scroll-top 属性的值,如:

this.contentScrollTop = this.contentScrollTop === 0 ? -1 : 0;

8️⃣ 页面滚动时,textarea不跟随滚动

textarea只能跟随Page滚动,如果是采用overflow滚动的就会出现这个问题

解决方法:要么去掉父层级的overflow 只让最外层的Page滚动;要么换种交互,新开一页去编辑内容(很多app,如微信小红书等,编辑姓名描述都是点击后跳转到新页面编辑)

写在最后

时间比较赶,所以只简单记录下最终的解决方法。想看具体效果的可以访问小程序查看:搜索【公途领航】查看