jjzjj

vue3+vant创建移动端项目,实战项目常见采坑记录

qwrBk 2023-07-20 原文

前言:

  产品背景介绍

  我所做的这个项目,刚开始是没有移动端需求的,等PC端做完了上线使用了几个月后,突然有一天产品经理找到我说是要做一个在PC端添加一个快速注册入口,用手机微信扫二位码进入移动端注册页面,用户注册。

所以本次需求就是在PC端添加一个tool-tip气泡型弹出二维码,再开发一个移动端注册页面。

  起初我是在PC项目中引入vant新加了一个模块来存放移动注册页面和注册成功页面的,然后想使用postcss-px-to-viewport的exclude和include属性配置来区分PC和移动页面,避免样式干扰。

然而,是我天真了,看网上各种postcss-px-to-viewport的exclude和include的配置,更换各个版本以及相似的更新版本,都不能完美做到兼容移动端和PC端,我就放弃了移动pc放在一个项目中了,最终只能单独的把移动页面单独摘出来成立一个单独项目跑,坑爹啊。

  1. 表单密码可见切换以及不让输入汉字空格

代码实现:

<van-field
              :required="true"
              v-model="registerForm.password"
              :type="switchPassType ? 'text' : 'password'"
              name="password"
              label="登录密码"
              placeholder="请输入登录密码"
              :right-icon="switchPassType ? 'eye' : 'closed-eye'"
              @click-right-icon="switchPassType = !switchPassType"
              :rules="rules.password"
              :update:model-value="registerForm.password=registerForm.password.replace(/[\u4e00-\u9fa5/\s+/]/ig,'')"
            />
 
备注:密码这块虽然有些网上搜到的让用vant 自带的digit属性让只能输入数字,但这个不符合产品需求,密码应为数字、字母、特殊符号都可输入。
使用van-field自带的update:model-value方法进行汉字、空格校验,亲测有效。
 

  2. 移动端页面出现X轴滚动条问题

1) 在index.html文件中添加
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,minimum-scale=1,viewport-fit=cover"/>
2) 在公共样式中修改html、body设置的样式
html {
    overflow-y: scroll;
}

:root {
    overflow-y: auto;
    overflow-x: hidden;
}

:root body {
    position: absolute;
}

body {
    width: 100%;
    margin: 0;
    padding: 0;
    overflow: hidden;
}

  3.使用postcss-px-to-viewport做适配出现的问题

使用教程我就不赘述了,网上一大片,说点有用的
1)兼容vant的375设置
在你的vue.config.js文件中添加如下代码:
css: {
    loaderOptions: {
      postcss: {
        postcssOptions: (loaderContext) => {
          return {
            plugins: [
              ["autoprefixer"],
              // vant px转vw。参坑:单独写在postcss.config.js中无法解析vant内部样式
              {
                "postcss-px-to-viewport": {
                  unitToConvert: "px",
                  viewportWidth: loaderContext.resourcePath.includes("vant") ? 375 : 750,
                  // viewportWidth: 750,  // 视窗的宽度,对应的是我们设计稿的宽度,一般是750
                  // viewportHeight: 1334, // 视窗的高度,根据750设备的宽度来指定,一般指定1334,也可以不配置
                  unitPrecision: 6, // 指定`px`转换为视窗单位值的小数位数
                  propList: ["*"],
                  viewportUnit: "vw", //指定需要转换成的视窗单位,建议使用vw
                  fontViewportUnit: "vw",
                  selectorBlackList: [], // 如['.ignore'], 可以指定不转换为视窗单位的类,可以自定义,可以无限添加,建议定义一至两个通用的类名
                  minPixelValue: 1, // 小于或等于`1px`不转换为视窗单位,你也可以设置为你想要的值
                  mediaQuery: true, // 允许在媒体查询中转换`px`
                  exclude: [],
                  landscape: false
                },
              },
            ],
          };
        },
      },
    },
  }
代码目录:

 

备注:其中的exclude属性不知道树我本人写的有问题还是怎么的,想用它处理views目录下的特定目录文件总是不生效,include就更别说了,各种版本、各种写法都换过了没啥nuan用。

  4.检测是否是移动端打开跳转不同路由

1)路由处理

export const ISMOBILE = function () {

    let flag = navigator.userAgent.match(
        /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i
    );
    return flag;
};

  5. DatePicker日期选择器默认选中当前日期

在这块有2个坑:

1)它的年份默认最小2013,不能像elementui的日期选择器一样自由选择,所以,使用时你可以使用min-date属性设置最小年月日。

2)默认选中当前年月日,

currentDate使用计算属性获取,
备注:月日不足2位要用0补齐,不然获取到的当前年月日不对

/**获取当前日期回填 */
const currentDate = computed(() => {
  const nowDate = myDate.toLocaleDateString().split("/");
  if (nowDate[1].length < 2) {
    nowDate[1] = "0" + nowDate[1];
  }
  if (nowDate[2].length < 2) {
    nowDate[1] = "0" + nowDate[2];
  }
  return nowDate;
});

   6. 表单校验添加

1)一定要给van-form中添加ref属性,在van-field中使用name作为校验标识,使用rules属性添加校验规则。

备注:想要对一个字段进行不同校验以及不同提示,只能使用多条校验规则。此处不能像使用elementUi中的callback返回提示语,只能使用message属性写死,操蛋啊

   7.文件上传预览删除

直接上代码,很明了:

// 上传图片、上传文件校验大小和格式
const beforeRead = (file) => {
  const correctFormat = ["jpg", "jpeg", "png", "bmp"];
  const isArray = Object.prototype.toString.call(file) === "[object Array]";
  const isLimit50M = 1024 * 1024 * 6; // 是否大于50M
  if (isArray) {
    const sizes = file.map((item) => item.size);
    if (sizes.some((item) => item > isLimit50M)) {
      showNotify({ type: "warning", message: "大小不能超过6M" });
      return false;
    }
    const types = file.map(
      ({ name }) => name.slice(name.lastIndexOf(".") + 1) // 后缀
    );
    if (!types.every((item) => correctFormat.includes(item))) {
      showNotify({ type: "warning", message: "请上传jpg/jpeg/png/bmp" });
      return false;
    }
  } else {
    if (file.size > isLimit50M) {
      showNotify({ type: "warning", message: "大小不能超过6M" });
      return false;
    }
    const type = file.name.slice(file.name.lastIndexOf(".") + 1);
    if (!correctFormat.includes(type)) {
      showNotify({ type: "warning", message: "请上传jpg/jpeg/png/bmp" });
      return false;
    }
  }
  return true;
};

// 文件上传
const fileUpload = (data, key, id, file) => {
  fileUploadApi(data)
    .then((res) => {
      if (res.status === 1) {
        res.data.key = new Date().getTime();
        res.data.url = res.data.attachPreviewUrl;
        res.data.percent = 100;
        res.data.status = "success";
        res.data.name = res.data.attachSrcName;
        res.data.uid = id;
        registerForm[key] = [];
        registerForm[key].push(res.data);
        file.status = "success";
        showNotify({ type: "success", message: "上传成功" });
        return true;
      } else {
        file.status = "failed";
        showNotify({ type: "danger", message: "上传失败,请重新上传" });
        return false;
      }
    })
    .catch((err) => {
      showNotify({ type: "danger", message: err.message });
      return false;
    });
};
/**文件上傳动作 */
const myBeforeRead = (file, field) => {
  if (beforeRead(file)) {
    file.status = "uploading";
    file.message = "上传中...";
    uploadData.file = file;
    uploadData.field = field;
    const form = new FormData();
    const keys = Object.keys(uploadData);
    keys.forEach((key) => {
      form.append(key, uploadData[key]);
    });
    // 后台接口
    if (fileUpload(form, uploadData.field, file.lastModified, file)) {
      return true;
    } else {
      return false;
    }
  } else {
    return false;
  }
};
/**文件删除动作 */
const delImg = (file, field) => {
  registerForm[field] = [];
  proxy.$refs.registerFormRef.validate(field);
};

 

有关vue3+vant创建移动端项目,实战项目常见采坑记录的更多相关文章

  1. ruby - 如何在 Ruby 中顺序创建 PI - 2

    出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

  2. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  3. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  4. ruby - 多次弹出/移动 ruby​​ 数组 - 2

    我的代码目前看起来像这样numbers=[1,2,3,4,5]defpop_threepop=[]3.times{pop有没有办法在一行中完成pop_three方法中的内容?我基本上想做类似numbers.slice(0,3)的事情,但要删除切片中的数组项。嗯...嗯,我想我刚刚意识到我可以试试slice! 最佳答案 是numbers.pop(3)或者numbers.shift(3)如果你想要另一边。 关于ruby-多次弹出/移动ruby​​数组,我们在StackOverflow上找到一

  5. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  6. ruby-on-rails - 无法使用 Rails 3.2 创建插件? - 2

    我对最新版本的Rails有疑问。我创建了一个新应用程序(railsnewMyProject),但我没有脚本/生成,只有脚本/rails,当我输入ruby./script/railsgeneratepluginmy_plugin"Couldnotfindgeneratorplugin.".你知道如何生成插件模板吗?没有这个命令可以创建插件吗?PS:我正在使用Rails3.2.1和ruby​​1.8.7[universal-darwin11.0] 最佳答案 随着Rails3.2.0的发布,插件生成器已经被移除。查看变更日志here.现在

  7. ruby - 如何使用 RSpec::Core::RakeTask 创建 RSpec Rake 任务? - 2

    如何使用RSpec::Core::RakeTask初始化RSpecRake任务?require'rspec/core/rake_task'RSpec::Core::RakeTask.newdo|t|#whatdoIputinhere?endInitialize函数记录在http://rubydoc.info/github/rspec/rspec-core/RSpec/Core/RakeTask#initialize-instance_method没有很好的记录;它只是说:-(RakeTask)initialize(*args,&task_block)AnewinstanceofRake

  8. ruby-on-rails - 项目升级后 Pow 不会更改 ruby​​ 版本 - 2

    我在我的Rails项目中使用Pow和powifygem。现在我尝试升级我的ruby​​版本(从1.9.3到2.0.0,我使用RVM)当我切换ruby​​版本、安装所有gem依赖项时,我通过运行railss并访问localhost:3000确保该应用程序正常运行以前,我通过使用pow访问http://my_app.dev来浏览我的应用程序。升级后,由于错误Bundler::RubyVersionMismatch:YourRubyversionis1.9.3,butyourGemfilespecified2.0.0,此url不起作用我尝试过的:重新创建pow应用程序重启pow服务器更新战俘

  9. ruby - 为什么 SecureRandom.uuid 创建一个唯一的字符串? - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?

  10. ruby-on-rails - 新 Rails 项目 : 'bundle install' can't install rails in gemfile - 2

    我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="

随机推荐