草庐IT

Vant 2 - 移动端 Vue 组件库 _ 问题记录

雨季mo浅忆 2023-05-14 原文

目录

基础组件

Popup 弹出层

表单组件

DatetimePicker 时间选择

Field 输入框

Form 表单

Picker 选择器

Radio 单选框

展示组件

List 列表

导航组件

Tab 标签页


发布初衷 :

记录在移动端项目中使用 Vant  2 组件库时遇到的各种问题 ,

方便以后再次遇到类似问题 , 能够快时查阅解决 ,

大家要是觉得有帮助的话 , 可以收藏一下 , 博主会不定时更新文章的


基础组件

Popup 弹出层

介绍

弹出层容器,用于展示弹窗、信息提示等内容,支持多个弹出层叠加展示。

问题记录 : Field 输入框 和 Popup 弹出层  两个 结合 使用 时 ,

在 iPhone 真机上测试的时候 出现的一个小 bug :

点击 Field 输入框 的时候 , 第一次会 弹出 一个 手机的键盘输入框

点击第二次的时候 才出来  Popup 弹出层 里面的内容 ( 比如 日期选择器 )

解决方案 : 

    给 Field 输入框 设置 readonly ,通过 readonly 将输入框设置为只读状态

输入框 van-field 必须得加入 readonly 这个 只读属性 ,

不然会导致 用户手机 触发 默认键盘 遮挡 你的弹窗和选择器内容 影响体验

也不要用 disabled 来禁用输入框 , 样式会变成禁用状态下的样式很难改动

只需要设置为只读即可 , 也不会触发手机键盘


表单组件

DatetimePicker 时间选择

介绍

时间选择器,支持日期、年月、时分等维度,通常与弹出层组件配合使用。

确认选择的时间数据是需要自己处理的,详见 confirmPicker 方法 

<template>
  <div class="seller">
    <van-cell
      title="开始时间"
      is-link
      :value-class="className"
      :value="timeValue"
      @click="showPopup" />
    <van-popup v-model="show" position="bottom">
      <van-datetime-picker
        v-model="currentDate"
        type="datetime"
        title="选择时间"
        :loading="isLoadingShow"
        :min-date="minDate"
        :max-date="maxDate"
        :formatter="formatter"
        @cancel="show = false"
        @confirm="confirmPicker"
      />
    </van-popup>
  </div>
</template>

<script>
export default {
  name: 'Seller',
  data () {
    return {
      msg: '商家页面',
      timeValue: '请选择时间',
      show: false,
      isLoadingShow: true,
      currentDate: new Date(),
      minDate: new Date(),
      maxDate: new Date(2020, 12, 31),
      className: ''
    }
  },
  methods: {
    // 显示弹窗
    showPopup () {
      this.show = true
      this.isLoadingShow = true
      setTimeout(() => {
        this.isLoadingShow = false
      }, 500)
    },
    // 确认选择的时间
    confirmPicker (val) {
      let year = val.getFullYear()
      let month = val.getMonth() + 1
      let day = val.getDate()
      let hour = val.getHours()
      let minute = val.getMinutes()
      if (month >= 1 && month <= 9) { month = `0${month}` }
      if (day >= 1 && day <= 9) { day = `0${day}` }
      if (hour >= 0 && hour <= 9) { hour = `0${hour}` }
      if (minute >= 0 && minute <= 9) { minute = `0${minute}` }
      this.className = 'timeClass'
      this.timeValue = `${year}-${month}-${day} ${hour}:${minute}`
      this.show = false
    },
    // 选项格式化函数
    formatter (type, value) {
      if (type === 'year') {
        return `${value}年`
      } else if (type === 'month') {
        return `${value}月`
      } else if (type === 'day') {
        return `${value}日`
      } else if (type === 'hour') {
        return `${value}时`
      } else if (type === 'minute') {
        return `${value}分`
      } else if (type === 'second') {
        return `${value}秒`
      }
      return value
    }
  }
}
</script>

<style lang="stylus" rel="stylesheet/stylus" scoped>
.seller
  .timeClass {
    color: #333;
  }
</style>


Field 输入框

介绍

表单中的输入框组件。

问题记录 : Field 输入框 和 Popup 弹出层  两个 结合 使用 时 ,

iPhone 真机 上测试的时候 出现的一个小 bug :

点击 Field 输入框 的时候 , 第一次会 弹出 一个 手机的键盘输入框

点击第二次的时候 才出来  Popup 弹出层 里面的内容 ( 比如 日期选择器 )

解决方案 : 

    给 Field 输入框 设置 readonly ,通过 readonly 将输入框设置为只读状态

输入框 van-field 必须得加入 readonly 这个 只读属性 ,

不然会导致 用户手机 触发 默认键盘 遮挡 你的弹窗和选择器内容 影响体验

也不要用 disabled 来禁用输入框 , 样式会变成禁用状态下的样式很难改动

只需要设置为只读即可 , 也不会触发手机键盘


Form 表单

介绍

用于数据录入、校验,支持输入框、单选框、复选框、文件上传等类型,需要与 Field 输入框 组件搭配使用。2.5 版本开始支持此组件。

需求背景 :

类似于表单提交页面或者“答题”页面( 表单项需要根据后端返回的数据动态循环生成 )

且回答页面需要增加用户校验是否已答并给出未答提示。

代码实现 :( 答题页面拆分成两部分:头尾组件 和 主体内容 组件 )

src / views / revise / index.vue

<!--
  作者:小灰狼
  时间:2023-04
  描述:答题页
-->
<template>
  <div>
    <HeadFooter>
      <div slot="main-content">
        <MainContent></MainContent>
      </div>
    </HeadFooter>
  </div>
</template>

<script>
import HeadFooter from "./components/HeadFooter.vue";
import MainContent from "./components/MainContent.vue";

export default {
  name: "Revise",
  components: {
    HeadFooter,
    MainContent,
  },
};
</script>

<style lang="scss" scoped></style>

src / views / revise / components / HeadFooter.vue


Picker 选择器

介绍

提供多个选项集合供用户选择,支持单列选择和多列级联,通常与弹出层组件配合使用。

业务场景 :

一开始以为只能渲染纯数组

但后来用的时候 , 后端返回来的数据结构是 数组嵌套对象的模式 ,

因此还特意将数组对象里面的数据专门筛选出来一个新数组用于渲染。。

但后来传参的时候需要数据结构里面的其他数据用于传参

所以又找了找这个Picker选择器可不可以渲染数组对象结构的案例 :

发现 [ {  } ]  , 是可以渲染的 ,只不过还要做一下处理 :


使用案例 :

<van-popup
  v-model="showTitle"
  position="bottom"
>
  <van-picker
    title="标题"
    show-toolbar

    value-key="name"

    :columns="columns"
    @confirm="onConfirm"
    @cancel="onCancel"
  />
</van-popup>
export default {
  data() {
    return {
      showTitle: false,
      columns: [], // 后端请求的数据
      queryFrom: {
        id: null,
        name: '',
      }
    };
  },
  methods: {
    onConfirm(value, index) {
      this.queryFrom.id = value.id // 需要传给后端的id值
      this.queryFrom.name = value.name // 用于渲染选择器列表数据
      this.showTitle = false // 关闭弹出层
    },
    onCancel() {
      this.showTitle = false
    },
  },
};

补充知识 :

vant-ui 之 Field 输入框 和 Picker 结合使用时 ,如何绑定正确的 id 类型的值的问题 。

很常见的需求 :

表单中的一项 ,需要从 picker 控件中选择正确的值后 ,展示的是字符串 ,

然后提交到后台服务器的则是字符串对应的 value 类型的值的问题。

点击表单的档案组,弹出 Picker 选择组件 ,选择正确的值 ,填充到表单项 ,但是 ,

提交到服务器去,需要提交对应的 id ,而不是看到的字符串。

如何实现 ?

定义两个属性,id 和 name , 两个是一 一对应的关系 。

在 van-picker 中 ,绑定的 confirm 函数 ,参数获取到的是一个对象 

在这个函数内,同时更新 id 和 name ,保证他俩一 一对应 。

  onConfirm(value, index) {
    this.queryFrom.id = value.id // 需要传给后端的id值
    this.queryFrom.name = value.name // 用于渲染选择器列表数据
    this.showTitle = false // 关闭弹出层
  },

如何展示 默认选中项

项目使用背景 :

用户填写表单时 , 需要根据上面填写的 乘车人数 来自动让下面的 Picker 选择器

下拉时 默认值 展示 与 人数相匹配 的 车辆类型

而又由于车辆类型是后端返回的数据 , 并不是固定不变的 , 所以前端没办法写死匹配方法

1、用户输入完 乘车人数 后 , 自动发起请求 , 由后端来匹配相对应的车辆类型

2、但是这里前端 Picker 组件需要用其索引值来展示下拉默认值 , 后端又无法返给我索引

3、前端这里只能先请求车辆类型数据列表后 , 再请求匹配车型数据值 , 循环去匹配后拿到当前匹配的索引值后再赋值给 Picker 组件


代码实现 :

根据乘车人数展示默认选中项
<van-picker
  show-toolbar
  title="车辆类型"
  value-key="dictLabel"
  :default-index="defaultMatch"
  :columns="applyType"
/>

data() {
  return {
    defaultMatch: 0, // 车辆类型下拉展示默认索引值
    applyType: [], // 车辆类型列表
  }
}

methods: {
  // 根据乘车人数自动匹配车辆类型
  async blurMatchType() {
  let arr = []
  // 先请求车辆类型列表数据用于匹配
  let res = await this.getDicts('car_apply_type')
  if (res.code == 200) arr = res.data
  // 根据乘车人数请求匹配的车辆类型值
  let ret = await getMatchType(this.userCarForm.riderNum)
  const { code, data } = ret
  if (code == 200) {
      // 循环匹配后赋值其索引值
      arr.forEach((item, index) => {
        if (item.dictValue == data) {
          this.defaultMatch = index
        }
      })
    }
  }
}

Radio 单选框

介绍

用于在多个选项中选择单个结果。

与 Cell 组件一起使用

Vant 展示效果如下 :

但 UI 设计图里面是 单选框 在左侧,文字在右侧

百度解决案例 :

项目实际所用 :

<van-radio-group v-model="radio">
  <van-cell-group>
    <van-cell
      v-for="(item, index) in [1, 2, 3]"
      :key="index"
      @click="radio = index"
      ><van-radio :name="index">{{ item }}</van-radio></van-cell
    >
  </van-cell-group>
</van-radio-group>

需求升级,页面需要判断用户是否回答此项,思路是借鉴 Form表单 里面的验证。

详情请 移步 上方 Form 表单 了解。


展示组件

List 列表

介绍

瀑布流滚动加载,用于展示长列表,当列表即将滚动到底部时,会触发事件并加载更多列表项。

List 组件通过 loading 和 finished 两个变量控制加载状态,当组件滚动到底部时,会触发 load 事件并将 loading 设置成 true

此时可以发起异步操作并更新数据,数据更新完毕后,将 loading 设置成 false 即可。

若数据已全部加载完毕,则直接将 finished 设置成 true 即可。

<van-list
  v-model="loading"
  :finished="finished"
  :finished-text="appList.length ? '没有更多了' : ''"
  @load="onLoad"
>
  <van-cell v-for="item in appList" :key="item" :title="item" />
</van-list>

export default {
  data() {
    return {
      loading: false,
      finished: false,
      appList: [], // 用车申请列表
      appQuery: {
        page: '1', // 要查询的页码
        rows: '10', // 每页记录数量
        userId: null, // 用户 Id
      }
    };
  },
  methods: {
    async onLoad() {
      // 异步更新数据
      let ret = await getAppList(this.appQuery)
      const { code, data } = ret
      if (code == 200) {
        this.appList = this.appList.concat(data.rows)
        // 加载状态结束
        this.loading = false;
        if (this.appList.length >= data.total) {
          // 没有更多数据了
          this.finished = true;
          Notify({
            message: '已加载完全部订单',
            background: '#ee0a24'
          })
        } else {
          this.appQuery.page++
        }
      }
    },
  },
};

以上是正常情况下 , onLoad 滚动到底部可以正常触发加载下一页数据

接下来就是说明一个不正常使用情况 , 此 bug 组件库还未修复

就是 和 Tab 标签页 组件 公用 :

我猜估计是包裹内容的高度它无法断定了吧 , 所以 onLoad 加载就有问题了


导航组件

Tab 标签页

<van-tabs v-model="active">
  <van-tab title="标签 1">
    <ApprovalItem type='1' />
  </van-tab>
  <van-tab title="标签 2">
    <ApprovalItem type='2' />
  </van-tab>
  <van-tab title="标签 3">
    <ApprovalItem type='3' />
  </van-tab>
  <van-tab title="标签 4">
    <ApprovalItem type='4' />
  </van-tab>
</van-tabs>

data() {
  return {
    active: 2,
  };
},

主要注意点就是子组件的高度需要设置一下 ,

一开始尝试的给 ApprovalItem 子组件一个高度  height:100% ,

但并没有解决一直触发 onLoad 加载的问题 ,

后来改成  height:100vh  , 就 OK 了 。。

没别的了 , 就是记录一下 , 提醒避坑 。


有关Vant 2 - 移动端 Vue 组件库 _ 问题记录的更多相关文章

  1. ruby - 在 64 位 Snow Leopard 上使用 rvm、postgres 9.0、ruby 1.9.2-p136 安装 pg gem 时出现问题 - 2

    我想为Heroku构建一个Rails3应用程序。他们使用Postgres作为他们的数据库,所以我通过MacPorts安装了postgres9.0。现在我需要一个postgresgem并且共识是出于性能原因你想要pggem。但是我对我得到的错误感到非常困惑当我尝试在rvm下通过geminstall安装pg时。我已经非常明确地指定了所有postgres目录的位置可以找到但仍然无法完成安装:$envARCHFLAGS='-archx86_64'geminstallpg--\--with-pg-config=/opt/local/var/db/postgresql90/defaultdb/po

  2. 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上找到一

  3. ruby - 通过 rvm 升级 ruby​​gems 的问题 - 2

    尝试通过RVM将RubyGems升级到版本1.8.10并出现此错误:$rvmrubygemslatestRemovingoldRubygemsfiles...Installingrubygems-1.8.10forruby-1.9.2-p180...ERROR:Errorrunning'GEM_PATH="/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/ruby-1.9.2-p180@global:/Users/foo/.rvm/gems/ruby-1.9.2-p180:/Users/foo/.rvm/gems/rub

  4. ruby - 通过 RVM (OSX Mountain Lion) 安装 Ruby 2.0.0-p247 时遇到问题 - 2

    我的最终目标是安装当前版本的RubyonRails。我在OSXMountainLion上运行。到目前为止,这是我的过程:已安装的RVM$\curl-Lhttps://get.rvm.io|bash-sstable检查已知(我假设已批准)安装$rvmlistknown我看到当前的稳定版本可用[ruby-]2.0.0[-p247]输入命令安装$rvminstall2.0.0-p247注意:我也试过这些安装命令$rvminstallruby-2.0.0-p247$rvminstallruby=2.0.0-p247我很快就无处可去了。结果:$rvminstall2.0.0-p247Search

  5. ruby - Sinatra:运行 rspec 测试时记录噪音 - 2

    Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/

  6. ruby - Fast-stemmer 安装问题 - 2

    由于fast-stemmer的问题,我很难安装我想要的任何ruby​​gem。我把我得到的错误放在下面。Buildingnativeextensions.Thiscouldtakeawhile...ERROR:Errorinstallingfast-stemmer:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcreatingMakefilemake"DESTDIR="cleanmake"DESTDIR=

  7. ruby - 安装 Ruby 时遇到问题(无法下载资源 "readline--patch") - 2

    当我尝试安装Ruby时遇到此错误。我试过查看this和this但无济于事➜~brewinstallrubyWarning:YouareusingOSX10.12.Wedonotprovidesupportforthispre-releaseversion.Youmayencounterbuildfailuresorotherbreakages.Pleasecreatepull-requestsinsteadoffilingissues.==>Installingdependenciesforruby:readline,libyaml,makedepend==>Installingrub

  8. ruby-on-rails - Rails 5 Active Record 记录无效错误 - 2

    我有两个Rails模型,即Invoice和Invoice_details。一个Invoice_details属于Invoice,一个Invoice有多个Invoice_details。我无法使用accepts_nested_attributes_forinInvoice通过Invoice模型保存Invoice_details。我收到以下错误:(0.2ms)BEGIN(0.2ms)ROLLBACKCompleted422UnprocessableEntityin25ms(ActiveRecord:4.0ms)ActiveRecord::RecordInvalid(Validationfa

  9. ruby-on-rails - 如何重命名或移动 Rails 的 README_FOR_APP - 2

    当我在我的Rails应用程序根目录中运行rakedoc:app时,API文档是使用/doc/README_FOR_APP作为主页生成的。我想向该文件添加.rdoc扩展名,以便它在GitHub上正确呈现。更好的是,我想将它移动到应用程序根目录(/README.rdoc)。有没有办法通过修改包含的rake/rdoctask任务在我的Rakefile中执行此操作?是否有某个地方可以查找可以修改的主页文件的名称?还是我必须编写一个新的Rake任务?额外的问题:Rails应用程序的两个单独文件/README和/doc/README_FOR_APP背后的逻辑是什么?为什么不只有一个?

  10. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

随机推荐