跳转至

1. 样式

1.1. fixed弹窗滑动时,下层页面也跟着滑动(穿透问题)

这里有篇文章介绍的比较好。

对于uni-app来说,最简单的方法应该是第一种,在弹窗外层元素加上事件@touchmove.stop="preventTouchMove"

1
2
3
preventTouchMove() {
  return;
},

如果弹窗内部有滚动元素,则在滚动元素外层用scroll-view包裹。

这个 scroll-view 的子孙元素不能添加 overflow: auto,否则无法滚动。

另外,试了下在page-meta上加上 page-style="height: 100%; overflow: 'hidden'" 是不生效的。

1.2. 安全区

h5的时候有下面的样式,就是处理ios的刘海屏。

body {
  padding-top: constant(safe-area-inset-top);
  padding-top: env(safe-area-inset-top);
  padding-left: constant(safe-area-inset-left);
  padding-left: env(safe-area-inset-left);
  padding-right: constant(safe-area-inset-right);
  padding-right: env(safe-area-inset-right);
  /* padding-bottom: constant(safe-area-inset-bottom);
  padding-bottom: env(safe-area-inset-bottom); */
}

在小程序中,这段样式需要去掉,否则会在自定义导航栏下面出现一条白框。

在uni-app项目中,只要把上面代码移动到index.html中就可以了,因为只有h5项目才会使用这个index.html文件。

1.3. page-meta

<page-meta :root-font-size="fontsize+'px'"></page-meta>

page-meta只能是页面内的第一个节点,可以实现rem

1.4. slot问题

uni-app是支持具名插槽的,有一点需要注意,对于写在slot标签上的类名,h5会下发到slot内部的外层元素上,而小程序则会创建view元素,在这个元素上添加类名。

如果遇到slot的样式异常,可以先排查下这里。

举个例子:

1
2
3
4
5
<SomeComp class="extra">
  <template #middle>
      title
  </template>
</SomeComp>

SomeComp组件内容如下:

1
2
3
4
5
<div class="inner">
  <div class="middle">
    <slot name="middle" />
  </div>
</div>

在h5中会被渲染成:

1
2
3
4
5
<div class="extra inner">
  <div class="middle">
    title
  </div>
</div>

在小程序会被渲染成:

1
2
3
4
5
6
7
<view class="extra">
  <view class="inner">
    <view class="middle">
      title
    </view>
  </view>
</view>

子组件加上下面代码可以解决:

1
2
3
options: {
  virtualHost: true,
},

1.5. 样式隔离

主要涉及 styleIsolation 属性。文档地址在这里

styleIsolation 选项支持以下取值:

  • isolated 表示启用样式隔离,在自定义组件内外,使用 class 指定的样式将不会相互影响(一般情况下的默认值);
  • apply-shared 表示页面 wxss 样式将影响到自定义组件,但自定义组件 wxss 中指定的样式不会影响页面;
  • shared 表示页面 wxss 样式将影响到自定义组件,自定义组件 wxss 中指定的样式也会影响页面和其他设置了 apply-shared 或 shared 的自定义组件。(这个选项在插件中不可用)

1.6. uni-app在h5端默认开启scoped

H5端为了隔离页面间的样式默认启用了 scoped,且无法取消

  1. 官方文档
  2. 相关文章

1.7. 不要在 class、style 中使用复杂对象

不能在 class、style 中直接使用 函数、data、计算属性 的对象,比如:

1
2
3
<div
  :style="scheItemStyle[index]"
>

但是可以这样:

1
2
3
<div
 :style="{ height: scheItemStyle[index].height }"
>

也就是使用某个具体的属性(字符串、数字等非引用类型类型),但不能是对象、数组等。

这种也不可以:

1
2
3
4
5
<div
  :class="[
    {'hidden-van-tabs': stageCfgList.length === 1},
  ]"
/>

这种可以:

1
2
3
4
5
<div
  :class="[
    {'hidden-van-tabs': isOnlyOneStage},
  ]"
/>

后面发现用字符串就可以了。

这样会报错

:style="getString(item,index)"

这样就不会

1
2
3
<div
  :style="type === 'card'? getString(item,index): getString(item,index)"
/>
可以变通一下,这样也不会报错

1
2
3
<div
 :style="true ? getString(item,index) : ''"
/>

1.8. v-if vs v-show

都知道v-show比v-if性能高,但是uni-app不支持v-show,对于dom节点特别大的页面来说,切换tab只能用v-show,v-if太卡。

这时可以用修改动态元素样式来实现,示例如下:

<div
  :class="['double-fail-wrap', `double-fail-wrap-${curTab}`]"
>

<style lang="scss">
.double-fail-wrap-1 {
  .loser-sche-map {
    display: none;
  }
}
.double-fail-wrap-2 {
  .winner-sche-map {
    display: none;
  }
}
</style>

1.9. CSS变量

uni-app 中css变量可以用 page,在h5模式下会自动转成uni-page-body,不能用:root,小程序中不生效,如:

1
2
3
4
5
page {
  // 修改switch的一些变量
  --switch-width: 0.88rem;
  --switch-height: 0.48rem;
}

1.10. 小程序中的:empty问题

uni-app 小程序 :empty,可能会存在问题,slot 即使父组件不传的情况下,还是会生成 <scoped-slots-label />,导致永远不为空,无法命中 empty

1.11. 样式层级问题

有些组件不要加scoped,加了以后,外面的样式很难覆盖里面的。

比如组件内的这个样式

.press-popover--right.data-v-3fdac1da {}

比组件外的这个样式优先级高。

.popover-wrap .demo-nav-popover--right {}

这块总之很乱,要每个case去看。

1.12. rpx精度丢失

小程序 rpx 转 px 时会直接去掉小数点,导致赛程树错位,用原生 rem 解决

1.13. 自定义组件多节点带来的样式问题

自定义组件渲染差异

微信(可以使用virtualHost配置)/QQ/百度/字节跳动这四家小程序,自定义组件在渲染时会比App/H5端多一级节点,在写样式时需要注意:

  1. 使用flex布局时,直接给自定义组件的父元素设置为·不能影响到自定义组件内部的根节点,需要设置当前自定义组件为display:flex才可以。
  2. 在自定义组件内部设置根元素高度为100%,不能撑满自定义组件父元素。需要同时设置当前自定义组件高度为100%才可以。

支付宝小程序默认启用了 virtualHost 配置不会插入节点,一般不存在如上问题。

参考:uni-app官网

1.14. 条件编译

样式文件中的条件编译需要用/* */包裹,不能用/** */包裹。

下图左边不生效,右边才生效。

1.15. 样式转化

page设置的样式,在h5中会被转成uni-page-body

htmlbody设置的样式,在小程序中会被转成page

对于这些容易造成歧义、容易产生误解,理解成本较高的转化样式,建议使用条件编译,只在本平台写本台可识别的样式,减少这种转化。

1.16. 多行省略号兼容性

不是uni-app项目独有的问题,这里也记录下。

多行省略号只能支持 webkit 内核浏览器, IE系就不兼容,所以对于多行省略号是不能用stylelint的默认规则。

  • 溢出隐藏:overflow: hidden;
  • 省略号:text-overflow: ellipsis; display: -webkit-box;
  • 弹性盒模型: 设置弹性盒子的子元素的排列方式 :-webkit-box-orient: vertical; 设置显示文本的行数:-webkit-line-clamp: 3; (最多显示3行)

1.17. page大部分情况下都应该为overflow:hidden

1.17.1. page

移动端,不论是h5还是小程序,大部分页面应该设置为height: 100%;overflow: hidden;,这样整个页面才不会跟着滑动,才不会漏出最底层,用户体验才好点。

如果是渐变式导航,则相反,page需要设置为height: auto,这样才会触发onPageScroll事件。此外,想让page滚动,那么page下的第一层的高度要大于一屏才可以,也就是不能在demo-wrap上设置height: 100%,可以给height: auto,或具体的高度。

除了需要onPageScroll事件的,其他都建议page设置为overflow: hidden

设置pageoverflow:hidden还有个好处,不用再给page设置额外的背景色了,反正看不见,只关心页面就行了,没铺满的就铺满即可。

1.17.2. demo-wrap

既然page设置了overflow:hidden,那么page下的第一个元素如果超出了屏幕高度,则需要设置overflow: auto;height: 100%;,否则就会显示不全。

如果不加demo-wrap,则页面在h5下可以滚动,在小程序下不可以滚动。因为h5中uni-page-body设置了overflow:auto,而小程序没有这个中间层。

1.17.3. press-ui

对于press-ui示例项目:

  • H5中html/body设置了height: 100%;overflow:hiddenuni-page-body设置了height: 100%;overflow:auto
  • 小程序中,page设置了height: 100%;overflow:hidden;,页面顶层需要滚动的dom,加上类名demo-wrap,其样式为height: 100%;overflow: auto;

小程序下页面级别的vue文件中,对page的样式设置:

  • 小程序下,不能加scoped,否则无效。
  • H5下,加了scopedpage转化的uni-page-body样式是生效的。

1.18. 安全区

什么时候需要适配安全区呢,底部是tabbar、购买按钮、输入框等不随页面滚动的元素。

1.19. 页面样式

归类,页面一定要有统一的包裹层class。好处是方便维护。

1.20. 动态class

小程序不支持这个

  :class="`tip-match-schedule-tab-item--scroll-${col - scrollTime}`"

但是支持这个

  :class="[`tip-match-schedule-tab-item--scroll-${col - scrollTime}`]"

2. vant

2.1. van-tab

2.1.1. change事件参数

uni-app中 vant-tab 的change事件暴露参数为event,需适配

this.curTab = e.detail.name;

2.1.2. v-model无效

uni-app 中 van-tab 使用 v-model 无效,会被转为,所以必须要想拿到改变后的tab,要写change事件,因为 van-weapp 默认更新的是 active 属性。

1
2
3
<van-tabs active="{{ active }}" bind:change="onChange">

</van-tabs>
Page({
  data: {
    active: 1,
  },

  onChange(event) {
    wx.showToast({
      title: `切换到标签 ${event.detail.name}`,
      icon: 'none',
    });
  },
});

2.1.3. 性能问题

tabMap[curTab]不要写在 template 中,否则切换 tab 时会有延迟,也不要写在 computed 中,最好不依赖 curTab。

1
2
3
4
<!-- 存在问题 -->
<Comp
  :list="tabMap[curTab]"
/>
<!-- 不推荐 -->
<Comp
  :list="curList"
/>

computed: {
  curList() {
    const { tabMap, curTab } = this;
    return tabMap[curTab]
  }
}

更好的方式是不依赖curTab

:sche-list="stageScheMap[index]"