uniapp归结

8 篇文章 0 订阅

image

        *Uniapp 的 <image> 与传统 web 开发中的 <img> 相比多了一个 mode 属性,用来设置图片的裁剪、缩放模式。
        一般只需要使用 widthFix、aspectFill 这两个属性即可应对绝大多数情况。
        即只需设置宽度自动撑起高度的图片用 widthFix ;需要固定尺寸设置宽高,并保持图片不被拉伸的图片用 aspectFill。
        例如:所有 icon、文章详情里、产品详情里的详情图一般会用 widthFix,用户头像、缩略图一般会用 aspectFill。*

滚动穿透

    弹窗遮罩显示时,底层页面仍可滚动。给遮罩最外层 view 增加事件 @touchmove.stop.prevent
<view class="pop-box" @touchmove.stop.prevent></view> 

分享

     小程序可以通过右上角胶囊按钮或者页面中 <button open-type='share'> 按钮来触发 分享功能
 <template>
  <!-- 假如这是一个社区列表页面 -->
  <view v-for="(item, index) in list">
    <button open-type="share" :data-item="item">分享</button>
  </view>
</template>
<script>
export default{
  data(){
    return{
      //列表数据
      list:[
        {
          id:1,
          title:"标题"img:'***.jpg'
        }
      ]
    }
  },
  onShareAppMessage(){
    // 点击页面中分享按钮,这样可以分别设置分享内容
    if (res.from === 'button') {
      let item=res.target.dataset.item
      return {
        title: item.title,
        path: `/pages/detail?id=${item.id}`,
        imageUrl:item.img
      }
    }
    //点击右上角胶囊按钮分享的设置
    return {
      title: '**社区',
      path: '/pages/community/'
    }
  }
}
</script>

return 的 Object 中 imageUrl 必须为宽高比例 5:4 的图片,并且图片大小尽量小于 20K。imageUrl 可不填,会自动截取当前页面画面。
另外 button 有默认样式,需要清除一下

 <template>
  <button class="btn-share" open-type="share"></button>
</template>
<style lang="scss">
.btn-share {
  padding: 0;
  margin: 0;
  border: 0;
  &::after {
    padding: 0;
    margin: 0;
    border: 0;
  }
  /*以上代码完成了样式清除,接下来写新的css样式*/
}
</style>

底部安全区

      OS 全面屏设备的屏幕底部有黑色横条显示,会对 UI 造成遮挡,影响事件点击和视觉效果。Android 没有横条,不受影响
      使用 css 样式 constant(safe-area-inset-bottom) env(safe-area-inset-bottom) 来处理,兼容 iOS11.2+
      需注意该方法小程序模拟器不支持,真机正常。

          <template>
            <view class="bottomBar"></view>
            </template>
            <style>
            .bottomBar {
                关于使用constant(safe-area-inset-bottom)、env(safe-area-inset-bottom)
                会返回底部安全区的高度
                两个方法都写,会自动选择能够生效的来使用
                可以使用calc方法来计算,根据实际情况灵活使用
                padding-bottom: calc(0rpx + constant(safe-area-inset-bottom));
                padding-bottom: calc(0rpx + env(safe-area-inset-bottom));
                }

如果使用 nvue,则不支持以上方案。可使用 HTML5+规范 的方法来处理

 <template>
            <view :style="{ paddingBottom: `${holderHeight}px` }"></view>
            </template>
            <script>
            export default{
            data(){
                return{
                      * 先判断是否iOS,再判断是否刘海屏即全面屏。34即为底部安全高度
                      * plus.os.name返回系统平台名称,plus.navigator.hasNotchInScreen()返回是否是刘海屏。
                     * 一定要先判断是否iOS,因为该问题仅iOS需处理,而且Android返回是否刘海屏标准不一,会有显示问题。
                holderHeight:plus.os.name == 'iOS' ? (plus.navigator.hasNotchInScreen() ? 34 : 0) : 0)
                }

对于老机型不支持用于设定安全区域与边界的距离的constant(safe-area-inset-bottom) env(safe-area-inset-bottom) 可用以下兼容
not 表示不支持括号内的属性

 @supports not(constant(safe-area-inset-bottom)){
        page{
            padding-bottom: 150rpx;
        }
    }

摇树优化

H5 打包时去除未引用的组件、API。
摇树优化(treeShaking)

//manifest.json
"h5" : {
    "optimization":{
        "treeShaking":{
            "enable":true //启用摇树优化
        }
    }
}

H5 唤起 App

两种实现方式:

  • URL Sheme
    优点:配置简单
    缺点:会弹窗询问“是否打开***”,未安装时网页没有回调,而且会弹窗“打不开网页,因为网址无效”;微信微博 QQ 等应用中被禁用,用户体验一般。

  • Universal Link
    优点:没有额外弹窗,体验更优。
    缺点:配置门槛更高,需要一个不同于 H5 域名的 https 域名(跨域才出发 UL);iOS9 以上有效,iOS9 一下还是要用 URL Sheme 来解决;未安装 App 时会跳转到 404 需要单独处理。

分包

主包大小不能超过2m 除页面可以分包配置,静态文件、js 也可以配置分包。可以进一步优化落地页加载速度。
在 manifest.json 中对应平台下配置 “optimization”:{“subPackages”:true} 来开启分包优化。开启后分包目录下可以放置 static 内容。
manifest.json源码

 {
            ...,
            "mp-weixin" : {//这里以微信为例,如有其他平台需要分别添加
                ...,
                "optimization" : {
                    "subPackages" : true
                }
            }
        }
        *分包预加载 (https://uniapp.dcloud.net.cn/collocation/pages.html#subpackages)*

多行文字需要限制行数溢出隐藏时,Nvue 和非 Nvue 写法不同

 Nvue 写法
        .text {
        lines: 2; //行数
        text-overflow: ellipsis;
        word-wrap: break-word;
        }

        非 Nvue 写法
        .text {
        display: -webkit-box;
        -webkit-line-clamp: 2; //行数
        -webkit-box-orient: vertical;
        overflow: hidden;
        text-overflow: ellipsis;
        }

uniapp 的自定义导航栏插件

**uni-nav-bar 自定义导航栏 **

 
          	<uni-nav-bar v-if="navBarShowTag">
			<view class="tabs-box">
				<view class="one-nav" :class="currentSwiperIndex === 0 ? 'nav-actived' : '' " @tap="swiperChange(0)">推					荐</view>
				<view class="one-nav" :class="currentSwiperIndex === 1 ? 'nav-actived' : '' " @tap="swiperChange(1)">资讯</view>
			</view>
		</uni-nav-bar>
uni加载loadding状态控制
uni.showLoading({
        title: '加载中',
      })

uni.hideLoading();

navigator 页面跳转

类似于a标签 但只能跳转本地页面

  
     <navigator open-type="navigate" :url=" '/pages/webview/webview?url='+item.link">
						<image class="banner-swiper-img" :src="item.image" mode="aspectFill" />
	  </navigator>
路由跳转
uni.navigateTo({
   url: '/fpage/pages/login/login'
  })
获取当前设备的宽度
let device = uni.getSystemInfoSync()
let widths = device.windowWidth
uni.navigateBack返回到上一个页面,页面没有刷新,

可这样设置

uni.navigateBack({
                    delta:1,
                    success: function() {
                    let page = getCurrentPages().pop(); //跳转页面成功之后
                    if (!page) return;
                      page.onLoad(); //如果页面存在,则重新刷新页面
                    }
                  })
当前页面向返回的页面传值

当前页面设置

let pages = getCurrentPages();
             let prevPage = pages[pages.length - 2];
             prevPage.$vm.currentIndex = this.currentIndex;
            uni.navigateBack({})

返回页面接收

onShow() {
            let pages = getCurrentPages();
            let index = pages[pages.length - 1].$vm.currentIndex
            if (index) {
              console.log('getFilterGoods',this.getFilterGoods);
              this.outboundGoodsAppointmentList.splice(index,1,this.getFilterGoods)
            }
        },
上拉加载,下拉刷新
   // 上拉加载
        onReachBottom() {
         if(this.goodList.length>=this.total)return false;
         this.initData({customerId:this.customerId,projectId:this.projectId,current:this.pageNum,pageSize:this.pageSize})
        },
        // 下拉刷新
        onPullDownRefresh(){
          this.goodList = []
          this.pageNum = 1
          this.initData({customerId:this.customerId,projectId:this.projectId,current:this.pageNum,pageSize:this.pageSize})
        },

 initData(param){
            if(this.loadingType !==0) return false;
            this.loadingType = 1
            uni.showNavigationBarLoading()
            getStockGroupByBatchNumberPage({...param}).then(res=>{
            this.goodList = this.goodList.concat(res.arr)
            this.total = res.total
            this.loadingType = 0
            this.pageNum ++
            uni.hideNavigationBarLoading()
          })
          },

获取用户手机号

    *小程序通过点击 button 获取 code 来跟后端换取手机号。在开发者工具中无法获取到 code。真机预览中可以获取到。*
     <template>
  <button open-type="getPhoneNumber" @getphonenumber="getphonenumber">
    获取用户手机号
  </button>
</template>
    getphonenumber(e) {
      let code = e.detail.code; //开发工具中无法获取到该code,用真机预览进行测试

      //开发阶段可以设置剪贴板将code复制。便于跟后端对接调试。调试完成后记得删除。
      uni.setClipboardData({
        data: e.detail.code
      });
    }
input 设置输入类型

uniapp自带的input自身是不带输入类型设置的,除非使用uni-easyinput,但是因为uni-forms的样式与原本页面需求相差太大,只能手写

 <view class="form_item">
          <text class="label beforeIcon"> 件重 </text>
          <input
            class="inputStyle"
            name="packageUnit"
            type="number"
            @input="getWeight(item, index, 'packageUnit', $event)"
            v-model="item.packageUnit"
            placeholder="请输入"
          />
          <text class="weightWord">kg</text>
        </view>


   getWeight(item,index,objType,e){
             let value = e.target.value.replace(/^0|[^\d]|[.]/g, '')
             this.$nextTick(() => {
                this.$set(this.inboundGoodsAppointmentList[index],objType,value)
              })
             if(value){
                if(+item.packageUnit&&+item.quantity){
          this.$set(this.inboundGoodsAppointmentList[index],'weight',Math.round(item.packageUnit*item.quantity))
               }
             }
           },

//小红点的样式
.beforeIcon{
      &::before {
            content: "*";
            color: #ff4949;
          }
}

出来的效果一部分是这样的
在这里插入图片描述

picker 从底部弹出的选择框
 <picker
          :range="goodsOptions" //选择数据的数组
          @change="changeGoods($event, index)"
          range-key="label" //渲染当前对象数据的什么属性
        >
          <view class="form_item">
            <text class="label beforeIcon"> 商品 </text>
            <view
              class="inputStyle"
              :class="{ placeholderStyle: item.goodsName === '' }"
            >
              {{ item.goodsName || "请选择" }}
            </view>
            <uni-icons type="forward" size="16"></uni-icons>
          </view>
        </picker>
动态设置类名
 :class="{ placeholderStyle: contractTypeName === '' }"
当uniapp需要设置多个底部tab栏

当我在别的页面需要设置另外的tab栏时,可和在配置文件的区分开来。
单个修改的时候,uniapp,支持单个设置,
然后多个的时候需要自己设置底部tab,代码

<template>
  <view   :style="{ 'padding-bottom': paddingBottomHeight + 'rpx' }">
    <view>
      <Order v-show="current == 0" />
      <Record v-show="current == 1" />
      <Search v-show="current == 2" />
      <Bill v-show="current == 3" />
    </view>
    <cover-view
      class="tabbar"
    >
      <cover-view
        class="tabbar-item"
        v-for="(item, index) in tabNav"
        :key="index"
        @click="tabbarChange(item)"
      >
        <uni-icons
          :type="item.iconPath"
          size="16"
          v-if="current == index"
          color="#0099fe"
        ></uni-icons>
        <uni-icons :type="item.iconPath" size="16" v-else></uni-icons>
        <cover-view
          class="item-text"
          :class="{ tabbarActive: current == index }"
          style="color: #a3a3a3; font-size: 20rpx"
          v-if="item.text"
          >{{ item.text }}</cover-view
        >
      </cover-view>
    </cover-view>
  </view>
</template>
<script>
import Bill from "../bill/index"
import Order from "../order/index"
import Record from "../stock/record"
import Search from "../stock/search"
export default {
    components: {
        Bill,
        Order,
        Record,
        Search
    },
        data() {
            return {
                current:0,
                tabNav: [
                    {
                    pagePath: "/pages/order/index",
                    iconPath: "settings-filled",
                    text: "预约管理",
                    index:0,
                },
                    {
                    pagePath: "/pages/stock/record/index",
                    iconPath: "wallet",
                    text: "出入库记录",
                    index:1,
                },
                  {
                    pagePath: "/pages/stock/search/index",
                    iconPath: "home",
                    text: "库存查询",
                    index:2,
                },
                {
                    pagePath: "/pages/bill/index",
                    iconPath: "list",
                    text: "对账单",
                    index:3
                },
                ],
                paddingBottomHeight: 0, //iPhonex以上手机底部适配高度
            }
        },
        created () {
              uni.setNavigationBarTitle({
                    title: this.tabNav[this.current].text
                });
                uni.getSystemInfo({
                success: (res) => {
                    let model = ['X', 'XR', 'XS', '11', '12', '13', '14', '15'];
                    for (let i=0;i<=model.length;i++) {
                        if(res.model.indexOf(model[i]) != -1 && res.model.indexOf('iPhone') != -1) {
                            this.paddingBottomHeight = 70
                            return false
                        }else {
                             this.paddingBottomHeight = 100
                            // this.$emit('tabbarHeight',100)
                        }
                    }
                }
            })
        },
        methods: {
            //跳转切换tab
            tabbarChange(item) {
               this.current = item.index
               uni.setNavigationBarTitle({
                    title: item.text
                });
            }
        } 
    }
</script>

<style lang="scss" scoped>
.tabbarActive{
	    color: #0099fe !important;
	}
	.tabbar{
	    position: fixed;
	    bottom: 0;
	    left: 0;
	    display: flex;
	    justify-content: space-around;
	    align-items: center;
	    width: 100%;
	    height: 100rpx;
	    background-color: #ffffff;
		border-top: 1px solid #e5eaea;
	}
	.tabbar-item{
		flex: 1;
	    display: flex;
	    flex-direction: column;
	    align-items: center;
	    justify-content: center;
	    // height: 100rpx;
	}
	.item-img{
	    margin-bottom: 4rpx;
	    width: 46rpx;
	    height: 46rpx;
	}
	.item-name{
	    font-size: 26rpx !important;
	    color: #A3A3A3 !important;
	}
.wmsContent{
    padding-bottom:100rpx;
}
</style>

列表页面

       *下拉刷新,上滑加载,没有更多内容的提示,关键字搜索,标签栏匹配,空白页面,列表项组件*
           <!-- 页面代码 -->
<scroll-view
  :scroll-y="true"
  style="height: 100vh"
  :refresher-enabled="true"
  :refresher-triggered="list.flag"
  @refresherrefresh="refresh"
  @scrolltolower="getAnswer"
  :enable-back-to-top="true"
  :scroll-into-view="list.scrollId"
  :scroll-with-animation="true"
>
  <view style="position: relative" class="bg-white">
    <view v-for="(item,index) in list.data" :key="index" >
      <answer-item
        :data="item"
      ></answer-item>
    </view>
  </view>
  <view
    class="cu-load bg-gray text-main loading"
    style="height: 40px"
    v-if="!list.nomore"
  ></view>
</scroll-view>

// js代码
export default {
components: {
        AnswerItem,
},
data() {
        return {
                list: {
                        data: [],
                        flag: false, //是否展示刷新
                        limit: 10,
                        total: 0,
                        nomore: false, //是否显示到底
                        empty: false, //是否显示为空,
                        error: false, //是否请求错误,
                }

        };
},
async onLoad(e) {
        this.getQuestion()
        await this.getAnswer()
        async getAnswer() {
				
},
methods: {
    async getAnswer() {
        const listHandle = require("../../utils/js/listHandle")
        const id = this.list.data.length ? this.list.data[this.list.data.length - 1].id : ''
        const res = await this.http.get('/applet/answerList', {
                qId: this.question.id,
                limit: this.list.limit,
                userId: this.store.user ? this.store.user.id : '',
                id
        })
        if (res.code === 200) {
                const list = listHandle.add(res.data, this.list.data, this.list.limit)
                Object.assign(this.list, list)
                return res.data
        } else {
                this.list.error = true
                this.message.toast('请求失败')
                return false
        }
},
async refresh() {
        // 刷新方法
        const listHandle = require("../../utils/js/listHandle")
        this.list.flag = true
        this.list.nomore = false
        this.list.empty = false
        this.list.error = false
        this.list.loadNum = 0
        const res = await this.http.get('/applet/answerList', {
                qId: this.question.id,
                limit: this.list.limit,
                userId: this.store.user ? this.store.user.id : '',
                id: ''
        })
        this.list.flag = false
        if (res.code === 200) {
                const list = listHandle.update(res.data, this.list.limit)
                Object.assign(this.list, list)
        } else {
                this.list.err = true
                this.message.toast('请求失败')
        }
},
}
}

listHandle.js 列表项处理的方法

const listHandle = {
  add(resData, listData, limit) {
    var ret = {
      nomore: false,
      empty: false,
      data: []
    }
    if (resData) {
      if (resData.length < limit) {
        // 获取数据条数小于页码数,显示已到底
        ret.nomore = true
      }
      ret.data = listData.concat(resData)
    } else {
      ret.data = listData
      ret.nomore = true
      if (!listData.length) {
        // 请求已无返回数据且当前列表无数据,显示为空
        ret.empty = true
      }
    }
    return ret
  },
  update(resData, limit) {
    var ret = {
      nomore: false,
      empty: false,
      data: []
    }
    if (resData) {
      if (resData.length < limit) {
        // 获取数据条数小于页码数,显示已到底
        ret.nomore = true
      }
      ret.data = resData
    } else {
      ret.nomore = true
      // 请求已无返回数据且,显示为空
      ret.empty = true
    }
    return ret
  }
}

module.exports = listHandle

在手机端上滑加载的时候,如果你是按照时间的倒序来排序,传统web底部分页器那样传一个页码数和单页条数给后端查询的话。如果在你上滑的过程中有用户发布新的内容,那么你的列表中就会有 重复的项。
举个例子:你最初取了十条数据,当你上滑到底部加载时传了一个 page=2 和 limit=10给后端,意思是将所有数据十条作为一页,我要拿第二页的内容。但是这时候有用户添加了一条新的数据,你第一页的最后一条就被挤到第二页去了,此时你拿到的数据第一条会和上一次拿到的最后一条一模一样!
想要解决这个问题也很简单,我们在向后端传递数据的时候不要按页码数去传值。我们将当前数据的最后一条的id传给后端,让后端取 id比这个值更小的十条,此时不论有多少用户插入新的数据都不会对你的结果产生影响。当然要实现这种功能的前提是你的数据表id是递增的,如果不是你也可以用数据的创建时间的那个字段来传递。
对应这个功能的是下面这行代码。

const id = this.list.data.length ? this.list.data[this.list.data.length - 1].id : ''

登录页面

在小程序中,登录往往不像web端需要输入账号密码或者手机验证码登录,而是使用各个平台的快速鉴权功能,例如微信小程序就是可以通过向微信官方的api发送请求来获取用户信息
一个按钮来获取用户信息

     <template>
	<button class="cu-btn bg-blue shadow-blur round lg" @click="login">
            立即登录
	</button>
</template>
<script>
export default {
    methods: {
	async login() {
            uni.showLoading({
		mask: true,
		title: '登录中'
		})
            const res = await uni.getUserProfile({
		desc: '用于存储用户数据'
		})
	uni.hideLoading()
	if (res[0]) {
		this.message.toast('获取失败', 'text')
		return
	}
        this.getUser(res[1].userInfo)
        },
        async getUser(userInfo) {
            uni.showLoading({
                    mask: true,
                    title: '登录中'
            })
            const loginRes = await uni.login()
            if (loginRes[0]) {
                    uni.hideLoading()
                    this.message.toast('获取失败')
                    return
            }
            const res = await this.http.post('/applet/weChatLogin', {
                    code: loginRes[1].code
            }, 'form')
            uni.hideLoading()
            if (!res.data) {
                    this.router.push('/pages/form/userForm', {
                            userInfo,
                            handle: 'add'
                    })
                    return
            }
            this.store.setData('user', res.data)
    },}

跨页面方法调用

*我要实现一个搜索功能,当我点进搜索详情输入关键词后,我要返回列表页面并触发一次搜索方法*
            searchFunc(){
  let pages = getCurrentPages()
  let page = pages[pages.length - 2]
  page.$vm.searchText = this.search.text
  page.$vm.refresh()
  this.router.back()
}

getCurrentPages() 是一个全局函数,用于获取当前页面栈的实例,以数组形式按栈的顺序给出。我们当前页面就是数组最后一项,那么上一个页面就是pages[pages.length - 2]。当然我们还要记得加上$vm属性,因为在uniapp中我们的数据和方法是挂载这个实例上的。我们可以通过这个示例访问到对应页面的所有数据和方法

证书文件

准备苹果开发账号
ios 证书、描述文件 申请方法(https://ask.dcloud.net.cn/article/152)
证书和描述文件分为开发(Development)和发布(Distribution)两种,Distribution 用来打正式包,Development 用来打自定义基座包。
ios 测试手机需要在苹果开发后台添加手机登录的 Apple 账号,且仅限邮箱方式注册的账号,否则无法添加。

苹果登录

APP
苹果登录需要使用自定义基座打包才能获得 Apple 的登录信息进行测试
iOS 自定义基座打包需要用开发(Development)版的证书和描述文件
iOS自定义基座包,如果开发者重新续费要生成一个本地证书,再打包

踩坑

scroll-view无法下拉刷新

    *scroll-view标签上有一个scroll-into-view属性,这个属性值可以传入一个id,当我们更改这个值时我们就会滚动到指定id的容器位置。
    但是如果我们的scroll-view被封装在组件中使用时,scroll-view无法下拉刷新
    应该是scroll-view元素的下拉位置在元素渲染时就确定了,而我们赋予scroll-view的高度更改了下拉位置,导致下拉的时候没法拉到位
    在scroll-view的高度变量确定后再渲染scroll-view元素,具体的做法如下代码*
     <scroll-view 
	scroll-y="true" 
	:style="'height:'+height" 
	v-if="height"  
	:refresher-enabled='true'
	:refresher-triggered='list.flag' 
	@refresherrefresh='refresh' 
	@scrolltolower='loadMore'>
</scroll-view>

scroll-view sticky样式问题

     scroll-view 是小程序常常会用到的一个标签,在滚动窗口内我们可能会有一个顶部标签栏,如果我们不想通过计算高度去固定在顶部的话我们可以使用 position:sticky  加一个边界条件例如top:0 属性实现一个粘性布局,在容器滚动的时候,如果我们的顶部标签栏触碰到了顶部就不会再滚动了,而是固定在顶部。
但是在小程序中如果你在scroll-view元素中直接为子元素使用sticky属性,你给予sticky的元素在到达父元素的底部时会失效,
解决方法
在scroll-view元素中,再增加一层view元素,然后在再将使用了sticky属性的子元素放入view中,就可以实现粘贴在某个位置的效果了

ios固定输入框字体移动bug

在一个固定于页面中间的滚动容器内放了一个表单,在安卓端测试功能完好,在IOS端有一个bug。当输入框在输入后没有点击其他位置使输入框失焦的话,如果滚动窗口内部的字体也会跟着滚动下面使解决方法
使用这个方法更改后,不仅布局的样式不会改变,而且字体随着固定的滚动窗口一起滚动的bug也会解决
更改后的输入框

<textarea fixed="true" auto-height="true" ></textarea>

真机时间错误BUG

在小程序中使用new Date().toLocaleDateString() api获取时间的时候,在开发工具中显示为当前时间,而在真机中显示为其他地区的时间
toLocaleDateString()方法依赖于底层操作系统在格式化日期上。 例如,在美国,月份出现在日期(06/22/2018)之前,而在印度,日期出现在月份(22/06/2018)之前

解决方案
使用new Date()构造函数来获取年月日后拼接
如果没有输入任何参数,则Date的构造器会依据系统设置的当前时间来创建一个Date对象。
Date和toLocaleDateString()的区别在于一个是获取系统当前设置的时间,一个则是底层操作系统来格式化时间

//具体代码如下
let date = new Date()
date = date.getFullYear() + '/' + (date.getMonth() + 1) + '/' + date.getDate()
date = date.split('/')
if (date[1] < 10) {
		date[1] = '0' + date[1]
	}
if (date[2] < 10) {
	date[2] = '0' + date[2]
	}
date = date.join('-')

textarea回显异常

问题描述

textarea回显在popup弹框内,在小程序状态,会渲染少字的情况

问题分析

小程序和App的vue页面,主体是webview渲染的,这个环境下,部分的UI元素,使用的是原生控件,此种混合渲染,虽然提升性能了,但是会带来问题

  • 前端组件无法覆盖原生控件的层级问题
  • 原生控件无法嵌套特殊前端组件(如scroll-view)
  • 原生控件UI无法灵活自定义

原生组件是:

  1. map
  2. video
  3. camera
  4. canvas
  5. input
  6. textarea
  7. live-player
  8. live-pusher
  9. cover-view
  10. cover-image
  11. ad
    uniapp原生组件说明
    H5或者App的nvue页面就不存在混合渲染,因为都是前端渲染或原生渲染,不存在层级关系
    解决方案:以text替换textarea
  <u-popup
        v-model="show"
        mode="center"
        width="500"
        :closeable="true"
        :mask-close-able="true"
      >
        <view class="titles-wrap">
          <view class="titles">使用规则</view>
        </view>
        <scroll-view scroll-y="true" style="height: 540rpx;">
          <view class="titlesw-wrap" v-if="showText">
            <!-- <u-input v-model="item.useInstructions" type="textarea"  :maxlength="-1" :height="100" :auto-height="true" /> -->
            <text class="cardTips">{{ forMatStr(item.useInstructions) }}</text>
            <!-- <textarea class="titlesw" v-model="item.useInstructions" :maxlength="-1" autoHeight></textarea> -->
          </view>
        </scroll-view>
      </u-popup>


 forMatStr (str) {
      if (!str) return ''
      let a = str.replace(/\↵/g, '\n')
      return a
    },
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值