IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 【荣耀开发者服务平台—百亿曝光扶持等你来】智慧服务快应用卡片接入指南(下) -> 正文阅读

[移动开发]【荣耀开发者服务平台—百亿曝光扶持等你来】智慧服务快应用卡片接入指南(下)

一、卡片网络加载优化指导

1. 卡片显示效果优化

1.1 优化说明

(1)首次加载:一般指用户手机上第一次使用卡片,手机本地还没有卡片的相关资源和用户数据,手机会下载卡片 rpk 包并进行安装,安装完成后进行展示。会执行卡片生命周期 onInit->onReady->onShow;

(2)卡片曝光:指卡片对用户可见,手机从息屏再到卡片展示页面,算是一次曝光;会执行卡片生命周期 onShow;

(3)重新加载:首次加载完成以后,手机系统的一些动作会导致负一屏卡片重新进行创建加载,如:用户切换手机字体、主题、重启手机或者手机的一些其他机制,会使卡片重新加载并显示。此时会执行卡片生命周期 onInit->onReady->onShow(卡片对用户可见时执行,不可见不会执行此生命周期);

(4)占位图提示页面:卡片首次加载或者重新加载时,有可能 fetch 请求返回数据较慢,卡片需要先显示文本宫格占位、图标占位或者沉浸式占位的 UI 文案提示页面作为过渡页,样式参见:《快应用卡片设计指南》1.10 空内容卡片样式

(5)无网络失败页面:卡片在首次加载时,如果手机无网络情况下,需要显示“数据加载失败,点击重试”文案提示页面;点击该文案页面时判断:1. 仍然无网络则跳转至卡片落地页处理无网络场景;2. 网络恢复时进行请求数据操作,恢复卡片正常显示。

(6)业务加载失败页面:卡片在首次加载时,如果网络存在,接口失败或者访问网络超时等失败情况时,请自行处理失败页面展示;

(7)缓存方案(可选):如果处在手机无网络或者 fetch 失败,需要获取上次存储的数据(每次 fetch 的数据都使用 storage 存储到本地)进行展示。开发者不必担心使用上次存储的数据显示时图片会无法加载,因为每次图片加载成功后,引擎框架会默认缓存卡片中的图片资源,只要 Image 组件的静态地址不变,图片在无网的情况下也可以正常显示;

注意:卡片的 fetch 不支持直接设置超时参数,所以开发者使用 Promise 自己封装超时处理函数,超时时间固定为 5s(不可以使用其他值),fetch 5s 后返回的数据需要废弃。

(8)卡片刷新场景(可选):为防止卡片影响客户端的流畅度和手机流量、功耗。

需要限制卡片访问网络或者刷新卡片刷新界面(onShow生命周期)的频率,在刷新管控机制下,卡片在一个时间周期内仅能获取到一次onShow生命周期的钩子函数回调,达到限制刷新的目的。onShow生命周期刷新时间周期建议大于等于3S。

1.2 卡片首次加载处理

1.3 卡片二次刷新

1.4 示例demo

(1)HTML部分

<template>
  <!-- 卡片最外层容器 -->
  <div class="card" @click="toH5">
    <!-- 加载初始占位布局 -->
    <div class="layer-box" if="{{showLoadView}}">
      <div class="title-box">
        <div class="title-logo"></div>
        <div class="title-txt-box"></div>
      </div>
      <div class="content-box"></div>
      <div class="footer-box">
        <div class="footer-txt-box"></div>
        <div class="footer-img-box"></div>
      </div>
    </div>
    <!-- 数据加载异常布局 -->
    <div class="network-box" if="{{showLoadFailedView}}" onclick="clickRetry">
      <image class="network-img" src="./image/位图备份.png"></image>
      <text class="network-txt">数据加载失败,点击重试</text>
    </div>
    <!-- stack标签用于有需要插入背景图的卡片需求,若无背景图需求无需用stack标签 -->
    <stack class="stack" if="{{showCardContent}}">
      <!-- 卡片stack标签第一个元素,设置百分百宽高,做成背景图效果  -->
      <div class="bg-img">
        <!-- 此处背景图标要用image标签 -->
        <image
          src="../Common/res/img_pic.png"
          forcedark="false"
          class="icon"
        ></image>
      </div>
      <!-- 卡片stack标签第二个元素,卡片布局容器,设置百分百宽高铺满父元素,若无背景图需求,直接来到此处布局容器  -->
      <div class="layer">
        <!-- 标题区域 -->
        <div class="title">
          <div class="title-logo">
            <image
              forcedark="false"
              class="logo"
              src="../Common/res/icon_icon.png"
            ></image>
          </div>
          <text class="title-text">{{ title }}</text>
        </div>
        <!-- 内容区域 -->
        <div class="content">
          <text class="content-title">内容区</text>
          <text class="content-text">{{ cardInfo.content }}</text>
        </div>
        <!-- 底部区域 -->
        <div class="footer">
          <div class="footer-box">
            <text class="footer-text">{{ cardInfo.fooderName }}</text>
          </div>
        </div>
      </div>
    </stack>
  </div>
</template>

(2)CSS部分

<style lang="less">
/* 卡片最外层 最外层容器无需给宽高,由负一屏或桌面设定宽高 */
.card {
  padding: 12dp;
  /* 此处给宽高是为了让调试器devtools显示内容方便测试效果,实际开发需要去掉宽高 */
  height: 152dp;
  width: 100%;
  /* 按照最新深色模式规范需要给卡片设置背景色,映衬规范需要#ffffff作为背景色;
  若自定义背景色,要满足深色模式则需要通过媒体查询来实现,详见深色模式开发文档 */
  background-color: #ffffff;
}
/* stack标签用于有需要插入背景图的卡片需求,若无背景图需求无需用stack标签*/
.stack {
  width: 100%;
}

/*卡片布局容器,设置百分百宽高铺满父元素,若无背景图需求,不需要stack标签结构直接来到此处布局容器*/
.layer {
  width: 100%;
  height: 100%;
  justify-content: space-between;
  flex-direction: column;
}

/* 卡片标题区域 */
.title {
  display: flex;
  height: 16dp;
  flex-direction: row;
  .title-logo {
    width: 16dp;
    height: 16dp;
    justify-content: center;
    align-items: center;
    flex-shrink: 0;
    .logo {
      width: 100%;
      height: 100%;
      object-fit: contain;
      border-radius: 50%;
    }
  }
  .title-text {
    font-size: 12dp;
    color: rgba(0, 0, 0, 0.9);
    padding-left: 8dp;
  }
}

/* 占位图 */
.layer-box {
  width: 100%;
  height: 100%;
  flex-direction: column;
  justify-content: space-between;
  .title-box {
    display: flex;
    height: 16dp;
    flex-direction: row;
    align-items: center;
    /* 占位图 */
    .title-logo {
      width: 16dp;
      height: 16dp;
      border-radius: 50%;
      margin-right: 8dp;
      background-color: #87ceeb;
    }
    .title-txt-box {
      width: 60%;
      height: 8dp;
      background-color: #ccc;
      border-radius: 8dp;
    }
  }
  .content-box {
    height: 60dp;
    background-color: #ccc;
  }
  .footer-box {
    height: 40dp;
    justify-content: space-between;
    align-items: flex-end;
    .footer-txt-box {
      height: 8dp;
      width: 50%;
      background-color: #ccc;
    }
    .footer-img-box {
      height: 40dp;
      width: 40dp;
      border-radius: 50%;
      background-color: #87ceeb;
    }
  }
}

/* 无网络布局 */
.network-box {
  width: 100%;
  height: 100%;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  .network-img {
    width: 80dp;
    height: 60dp;
    object-fit: contain;
  }
  .network-txt {
    font-size: 10dp;
    color: rgba(0, 0, 0, 0.9);
    padding-top: 4dp;
  }
}

/*/卡片内容区域 */
.content {
  height: 60dp;
  flex-direction: column;
  justify-content: center;
}
.content-title {
  font-size: 16dp;
  color: rgba(0, 0, 0, 0.9);
  font-weight: 500;
}
.content-text {
  font-size: 14dp;
  color: rgba(0, 0, 0, 0.6);
  font-weight: 400;
  /* 注意:卡片内容区域给定高度,内容展示要注意字数限制内容过长采用省略方式,避免导致内容缺失问题 */
  lines: 2;
  text-overflow: ellipsis;
}
/* 卡片底部区域 */
.footer {
  height: 40dp;
  flex-direction: row;
  justify-content: space-between;
  align-items: flex-end;
  .footer-box {
    height: 16dp;
    flex-direction: row;
    .footer-text {
      font-size: 10dp;
      color: rgba(0, 0, 0, 0.6);
    }
  }
}

/* 背景图标 */
.bg-img {
  width: 100%;
  height: 100%;
  flex-direction: column-reverse;
  align-items: flex-end;
}
.icon {
  width: 40dp;
  height: 40dp;
  object-fit: contain;
}
</style>

(3)JS部分

<script>
import fetch from '@system.fetch'
import network from '@system.network'
import router from '@system.router'

// 封装节流函数 用于限制频繁点击或频繁触发事件的处理
function throttle(func, delay = 500) {
  let timer = null
  let that = this
  return function (...arg) {
    if (timer) return
    timer = setTimeout(() => {
      func.apply(that, arg)
      timer = null
    }, delay)
  }
}

//封装获取网络状态
function getNetwork() {
  return new Promise((resolve, reject) => {
    network.getType({
      success: function (data) {
        console.log(`handling success: ${data.type}`)
        resolve(data.type)
      },
      fail: function (error) {
        console.error("get network error:" + error);
        reject(error);
      }
    })
  })
}

export default {
  private: {
    title: '标题(2x4)',
    showLoadView: false, //初始占位
    showLoadFailedView: false, //数据加载失败
showCardContent: false, //成功渲染
hasInited: false,
    timeout: null,
    cardInfo: {
      content: '',
      fooderName: ''
    }
  },
  onInit() {
    this.initDate()
    // 构建点击无网络失败页面节流函数  防止频繁点击无网络失败页面
    this.filedFetchThottle = throttle(this.filedFetch.bind(this), 500)
    //构建频繁触发updateData数据更新的节流函数 防止频繁触发onShow里数据的更新
    this.updateDataThottle = throttle(this.updateData.bind(this), 3000)
  },

  onShow() {
if(!this.hasInited) return
    //防止频繁触发onShow里数据的更新
    this.updateDataThottle()
  },

  // 正常卡片状态下的跳转(以跳转百度为示例)
  toH5() {    router.push({ uri: 'hnquick://browser//parameter?url=http://www.baidu.com' })
  },

  /**
  * 初始化卡片数据
  */
  async initDate() {
    this.showLoadingPage() //初始化显示占位图
    const netWorkStatus = await getNetwork()
    if (netWorkStatus == 'none') {
      this.showLoadFailedPage()
      return
    }
    const res = await this.fetchData()
    const { code, data } = res
    if (code == 200) {
      this.cardInfo.content = '离开[深圳航站],下一站[广州处理中转站]'
      this.cardInfo.fooderName = '来自顺丰速运'
      this.showCard()
    } else {
      // 自行处理业务失败逻辑
}
this.hasInited = true
  },

  //数据更新
  async updateData() {
    const res = await this.fetchData()
    const { code, data } = res
    if (code == 200) {
      this.cardInfo.content = '离开[深圳航站],下一站[广州处理中转站]'
      this.cardInfo.fooderName = '来自顺丰速运'
      this.showCard()
    }
  },

  //接口调用失败或者无网络时跳转去无网络加载失败页面
  async filedFetch() {
    const netWorkStatus = await getNetwork()
    console.log('netWorkStatus',netWorkStatus)
    if (netWorkStatus == 'none') {
      router.push({ uri: 'hnquick://browser//parameter?url=http://www.baidu.com' })
    } else {
      this.updateData()
    }
  },

  showLoadingPage: function () {
    this.showLoadFailedView = false
    this.showCardContent = false
    this.showLoadView = true
  },

  showLoadFailedPage: function () {
    this.showCardContent = false
    this.showLoadView = false
    this.showLoadFailedView = true
  },
  showCard: function () {
    this.showLoadFailedView = false
    this.showLoadView = false
    this.showCardContent = true
  },

  //网络超时处理
  timeoutHandler(promiseInstance) {
    const timeout = new Promise((_, reject) => {
      setTimeout(() => {
        reject('网络超时')
      }, 5000)
    })
    return Promise.race([timeout, promiseInstance])
  },

  /**
     * 发起fetch请求数据
     */
  fetchData() {
    return this.timeoutHandler(
      new Promise((resolve, reject) => {
        fetch
          .fetch({
            url: 'https://xxx', // 接口链接
            method: 'GET',
          })
          .then((response) => {
            resolve(response.data)
          })
          .catch((error, code) => {
            console.log(`🐛 request fetchIconUrlData fail, error= ${error}, code = ${code}`)
            resolve({ code, data: error })
          })
      })
    )
  },
  // 数据加载失败
  clickRetry(evt) {
    // 阻止事件冒泡
    evt.stopPropagation()
    // 防止频繁点击无网络失败页面
    this.filedFetchThottle()
  },

}
</script>

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-09-15 02:07:57  更:2022-09-15 02:09:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 4:53:42-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码