2

UNI-APP 实践问题记录

最近需要将一个原来vuejs 技术栈的 移动端业务改造小程序,基于成本和时间的考虑,选择了 uni-app ,一开始直接将旧代码迁入到新的工程里。在逐步开发过程中,遇到了一些问题,整理记录一下,当然这些问题可能只是在我们项目特定场景、特定情况下出现的,仅供参考,提供一个思路。

语法问题

  • 编译后,WXML提示 bad attrs

    在于template中写了个短路运算,v-if="false && item.count > 1" (之前主要是为了防止产品又要改回来,加了短路运算)。

    解决方案:删除短路运算相关代码

  • v-show 判断问题

    v-show 在数据表达式条件成立后,表现结果错误。 v-show="count > 0", 当count > 0的时候,v-show对应的el 仍旧没有显示出来。

    解决方案: v-show 改为 v-if

自定义配置

  • 自定义构建配置

    我们需要将小程序中用到的图片、字体构建到cdn 服务中,而不是打包在小程序代码中,所以需要修改构建工作流。

    在官方文档中,支持 vue.config.js来配置一些 webpack 工作流。

    对于图片、字体等默认是会对小于40KB进行base64。

    由于vue-cli 中,字体、图片等用的是 url-loader,所以为了将图片、字体构建到cdn种,需要在 vue.config.js 中配置 url-loaderurl-loader fallback 到 file-loader

    先看下完整配置

// vue.config.js

'use strict'
const path = require('path')

const isWin = /^win/.test(process.platform)
const isProd = process.env.NODE_ENV === 'production'

const normalizePath = (path) => (isWin ? path.replace(/\\/g, '/') : path)
const extConfig = require('./src/ext.json')
function resolve(dir) {
  return path.join(__dirname, dir)
}
// 配置H5 跨域
const devServer = {
  target: 'your.domain.com',
  // 重要
  changeOrigin: true,
  pathRewrite: { '^/': '' },
  // 重要
  secure: false,
  prependPath: true,
  onProxyReq: function (proxyReq, req, res) {
  },
}
module.exports = {
  // 路径别名
  chainWebpack: (config) => {
    /* .resolve.alias
      .set('@', resolve('src'))
      .set('@p', resolve('src/pages'))
      .set('@c', resolve('src/components'))
      .set('@a', resolve('src/assets'))
      .set('@utils', resolve('src/utils'))
      .end()
      .extensions.add('.js')
      .add('.vue')
      .add('.scss')
      .end()
      .end() */
    config.module
      .rule('vue')
      .test([/\.vue$/, /\.nvue$/])
      .use('vue-loader')
      .tap((options) =>
        Object.assign({}, options, {
              // 配置 小程序image标签的src 也进行资源路径转换
          transformAssetUrls: {
            image: 'src',
          },
        }),
      )
      .end()
    if (isProd) {
      config.module
        .rule('images') //.test(/\.(png|jpe?g|gif|svg)(\?.*)?$/)
        .use('url-loader')
        .tap((args) => {
          const newArgs = Object.assign({}, args, {
            // 配置转换规则,-1 表示任何大小的资源都不进行base64转换
            limit: -1,
            // 这里重要,publicPath 配置给url-loader 会不生效,必须配置到fallback里传递给file-loader
            fallback: {
              loader: 'file-loader',
              options: {
                publicPath(url, resourcePath, context) {
                  return (
                    extConfig.ext.publicPath +
                    normalizePath(path.relative(process.env.UNI_INPUT_DIR, resourcePath))
                  )
                },
                emitFile: false,
              },
            },
          })
          return newArgs
        })
        .end()
        .end()
        .rule('fonts')
        .use('url-loader')
        .tap((args) => {
          const newArgs = Object.assign({}, args, {
            limit: -1,
            fallback: {
              loader: 'file-loader',
              options: {
                publicPath(url, resourcePath, context) {
                  return (
                    extConfig.ext.publicPath +
                    normalizePath(path.relative(process.env.UNI_INPUT_DIR, resourcePath))
                  )
                },
                emitFile: false,
              },
            },
          })
          return newArgs
        })
    }
  },
  devServer: {
    disableHostCheck: true,
    proxy: {
      '/api': devServer,
    },
  },
}

另外,uni-app 中 路径别名默认 @ 指向 src目录,如果配置了其他自定义别名,比如上面配置中的 @c会导致编译的时候无法正确识别 @c 引用的资源。

性能优化相关

uni-app 会将 componentdata 属性转化为小程序的 data, vue中任何修改 data的操作都会最终触发小程序的 setData,众所周知, setData 是小程序性能优化一个重点。

  1. 与template 无关的数据尽量不要放到 data里,否则任何修改的操作都会导致 setData,从而影响性能。
  2. 尽量不要频繁的触发setData

    <script>
     
      data() {
        return {
          name: ['YoRoling']
        }
      },
      methods: {
        getName() {
          if (a) {
            // 触发setData
            this.name.push('a')
          }
          if (b) {
            // 触发setData
                 this.name.push('b')
          }
        }
      }
    </script>
    

    上面的代码,a和b 都会导致最终触发 setData,而且是触发两次,对于这种简单的数据可能还好,如果是一个复杂的JSON 对象,setData 可能就会引起性能问题。

    使用临时变量存储数据,最后再一次性修改 data


Yorolling
239 声望7 粉丝

我亦飘零久!十年来,深恩负尽,死生师友。