Weex开发技巧Weex专栏weex社区

Weex内置组件的使用——Weex的学习之路(四)

2019-05-15  本文已影响3人  安卓搬砖小曾

上一篇文章我们学习了<list>、<cell>、<loading>和<refresh>组件,这都都是在项目中常用的。那这篇文章我们一起来学习<recycle-list>、<scroller>、<slider>、<indicator>、<textarea>和<input>,大家可能会问为什么Weex的组件为什么要一个一个学下来呢?其实这是一个很普遍的问题,任何技术不打好基础,以后实际运用的时候是要买单的,还是那句话,基础不牢,地动山摇。

那么我们首先来看一下<recycle-list>组件,这个组件是不是和我们Android中的RecycleView很像,其实他的功能就是一样的。

1.<recycle-list>的简介和使用

<recycle-list> 是一个新的列表容器,具有回收和复用的能力,可以大幅优化内存占用和渲染性能。它只能使用 <cell-slot> 作为其直接子节点,使用其他节点无效。

<cell-slot> 代表的是列表每一项的模板,它只用来描述模板的结构,并不对应实际的节点。<cell-slot> 的个数只表示模板的种类数,真实列表项的个数是由数据决定的。

属性 说明
case 声明了当前模板的类型,只有和数据中的类型与当前类型匹配时才会渲染,语义和编程语言里的 case 一致。
所有模板中最多只会匹配到一项,按照模板的顺序从上到下匹配,一旦匹配成功就不在继续匹配下一个。
default 表示当前模板为默认模板类型,不需要指定值。如果数据项没有匹配到任何 case 类型,则渲染带有 default 模板。如果存在多个 default,则只会使用第一个默认模板。
key 可选属性,用于指定列表数据中可以作为唯一标识的键值,可以优化渲染性能。

<recycle-list>的属性如下:

简单的使用示例如下:

<recycle-list for="(item, i) in longList" switch="type">
  <cell-slot case="A">
    <text>- A {{i}} -</text>
  </cell-slot>
  <cell-slot case="B">
    <text>- B {{i}} -</text>
  </cell-slot>
</recycle-list>

<recycle-list> 中使用的子组件也将被视为模板,在开发组件时给 <template> 标签添加 recyclable 属性,才可以用在 <recycle-list> 中。

<template recyclable>
  <div>
    <text>...</text>
  </div>
</template>
<script>
  // ...
</script>

特别说明的是:添加了 recyclable 属性并不会影响组件本身的功能,它仍然可以用在其他正常的组件里。

使用<recycle-list>需要注意以下几点:

1. 属性和文本的绑定

绑定属性或者文本时,仅支持表达式,不支持函数调用,也不支持使用 filter,可以参考 Implementation.md#支持的表达式,例如,下列写法不可用:

<div :prop="capitalize(card.title)">
  <text>{{ card.title | capitalize }}</text>
</div>

针对这种场景,推荐使用 computed属性来实现。因为模板的取值是由客户端实现的,而函数的定义在前端(filter 可以认为是在模板里调用函数的语法糖),如果每次取值都走一次通信的话,会大幅降低渲染性能

<slot>不可用<cell-slot> 的功能和 <slot> 有部分重叠,而且更为激进,在概念上有冲突,存在很多边界情况无法完全支持。不要在 <cell-slot> 及其子组件里使用 <slot>

  1. v-once 不会优化渲染性能

和前端框架中的理解不同,客户端里要实现复用的逻辑,会标记模板节点的状态,添加了 v-once 能保证节点只渲染一次,但是并不一定能优化渲染性能,反而可能会拖慢客户端复用节点时的比对效率。

3. 样式功能的限制

目前版本里还不支持绑定样式类名(v-bind:class),后续会支持的

4. 子组件的限制

使用示例如下:

<recycle-list for="(item, i) in longList" switch="type">
  <cell-slot case="A">
    <text>- A {{i}} -</text>
  </cell-slot>
  <cell-slot case="B">
    <text>- B {{i}} -</text>
  </cell-slot>
</recycle-list>

如果有如下数据:

const longList = [
  { type: 'A' },
  { type: 'B' },
  { type: 'B' },
  { type: 'A' },
  { type: 'B' }
]

则会生成如下等价节点:

<text>- A 0 -</text>
<text>- B 1 -</text>
<text>- B 2 -</text>
<text>- A 3 -</text>
<text>- B 4 -</text>

如果将模板合并成一个,也可以省略 switchcase,将例子进一步简化:

<recycle-list for="(item, i) in longList">
  <cell-slot>
    <text>- {{item.type}} {{i}} -</text>
  </cell-slot>
</recycle-list>

2.<scroller>的简介和使用

<scroller> 是一个容纳子组件进行横向或竖向滚动的容器组件。如果你的组件需要进行滚动,可以将 <scroller> 当作根元素或者父元素使用,否则页面无法滚动( <list> 组件除外, <list> 默认可以滚动)。

有几点需要开发者特别的注意:

<template>
  <scroller class="scroller">
    <div class="row" v-for="row in rows" :key="row.id">
      <text class="text">{{row.name}}</text>
    </div>
  </scroller>
</template>

<script>
  const dom = weex.requireModule('dom')

  export default {
    data () {
      return {
        rows: []
      }
    },
    created () {
      for (let i = 0; i < 80; i++) {
        this.rows.push({id: i, name: 'row ' + i})
      }
    },
  }
</script>

<scroller> 支持任意类型的 Weex 组件作为其子组件。 其中,还支持以下两个特殊组件作为子组件:

<scroller>的属性

参数 说明 类型 默认值
show-scrollbar 控制是否出现滚动条 boolean true
scroll-direction 控制滚动的方向 string(horizontal 或者 vertical) vertical
loadmoreoffset 触发 loadmore 事件所需要的垂直偏移距离(设备屏幕底部与页面底部之间的距离)。当页面的滚动条滚动到足够接近页面底部时将会触发 loadmore 这个事件 number 0
offset-accuracy 控制 scroll 事件触发的频率,默认值为 10,表示两次 scroll 事件之间列表至少滚动了 10px。注意,将该值设置为较小的数值会提高滚动事件采样的精度,但同时也会降低页面的性能 number 10
scrollToBegin 控制 scroll 内容(layout)改变后,是否自动滚到初时位置。默认是true string true

特别提醒:

scroll-direction 定义了 scroller 的滚动方向,样式表属性 flex-direction 定义了 scroller 的布局方向,两个方向必须一致。例如:

<scroller>有如下四个属性:

3.<slider>的简介和使用

Slider 组件用于在一个页面中展示多个图片,在前端这种效果被称为轮播图。默认的轮播间隔为3秒。它支持任意类型的 Weex 组件作为其子组件。你也可以放置一个 indicator 组件用于显示轮播指示器。indicator 也只能作为 Slider 的子组件使用。indicator 不能再包含其它子组件了。

<slider>的属性有如下几种:

简单的使用示例如下所示:

<template>
  <div>
    <slider class="slider" interval="3000" auto-play="true">
      <div class="frame" v-for="img in imageList">
        <image class="image" resize="cover" :src="img.src"></image>
      </div>
    </slider>
  </div>
</template>

<style scoped>
  .image {
    width: 700px;
    height: 700px;
  }
  .slider {
    margin-top: 25px;
    margin-left: 25px;
    width: 700px;
    height: 700px;
    border-width: 2px;
    border-style: solid;
    border-color: #41B883;
  }
  .frame {
    width: 700px;
    height: 700px;
    position: relative;
  }
</style>

<script>
  export default {
    data () {
      return {
        imageList: [
          { src: 'https://gd2.alicdn.com/bao/uploaded/i2/T14H1LFwBcXXXXXXXX_!!0-item_pic.jpg'},
          { src: 'https://gd1.alicdn.com/bao/uploaded/i1/TB1PXJCJFXXXXciXFXXXXXXXXXX_!!0-item_pic.jpg'},
          { src: 'https://gd3.alicdn.com/bao/uploaded/i3/TB1x6hYLXXXXXazXVXXXXXXXXXX_!!0-item_pic.jpg'}
        ]
      }
    }
  }
</script>

4.<indicator>的属性和使用

indicator 只能在 slider 中使用,说白了就是轮播图底部的小点,不可添加任何子元素,其中它的样式也很简单:

5.<input>的属性和使用

Weex 内置的 <input> 组件用来创建接收用户输入字符的输入组件。 <input> 组件的工作方式因 type 属性的值而异,比如 textpasswordurlemailtel 等。值得注意的是,此组件不支持 click 事件。请监听 inputchange 来代替 click 事件,同时也不支持任何子组件。

其属性可见表格:

key 类型 描述 默认值 备注
type string 控件的类型 text type 值可以是 text,date,datetime,email, password,tel,time,url,number 。每个 type 值都符合 W3C 标准。
其中,date 和 time 会使用系统默认组件(Android + IOS)查看示例

value | string | 组件的默认内容 |
placeholder | string | 提示用户可以输入什么。 提示文本不能有回车或换行
autofocus | boolean | 布尔类型的数据,表示是否在页面加载时控件自动获得输入焦点
maxlength | nubmer | 一个数值类型的值,表示输入的最大长度
return-key-type | string | 键盘返回键的类型(即手机输入法右下角回车按钮的地方)

image
支持 defalut;go;next;search;send,done
查看示例
singleline | boolean | 控制内容是否只允许单行 | true |
max-length | number | 控制输入内容的最大长度
字符串长度,即中英文字符长度都为 1
max | string | 控制当 type 属性为 date 时选择日期的最大时间,格式为 yyyy-MM-dd
min | string | 控制当 type 属性为 date 时选择日期的最小时间,格式为 yyyy-MM-dd
upriseOffsetv0.21+ & iOS | number | 当键盘弹起可能盖住输入框时,页面整体会上移。这个属性指定键盘上边缘与输入框下边缘的间隙。使用 iOS 系统坐标,默认是 20。
hideDoneButtoniOS | number | 隐藏键盘上面的完成栏 | false |

其中 placeholder-color {color},placeholder 字符颜色。默认值是 #999999

<input>组件方法:

focus()input 组件聚焦。

blur()input 组件中移除焦点并关闭软键盘(如果它具有焦点)。

setSelectionRange(selectionStart, selectionEnd) ,设置文本选区

key 类型 描述
selectionStart number 设置文本选区的起始点
selectionEnd number 设置文本选区的起终点

getSelectionRange(function(params){}) ,获取文本选区

key 类型 描述
params.selectionStart number 文本选区的起始点
params.selectionEnd number 文本选区的起终点

setTextFormatter(params) ,这是一个非常有用的特性,可以对 input 设置一组对输入的内容进行实时格式化的规则

input标签使用及事件处理demo:

<template>
  <div>
    <div class="title">
      <text style="text-align: center;font-size: 50px;">&lt;input&gt; Component Demo</text>
    </div>
    <div class="output">
      <scroller>
        <text>
          {{state}}  {{keyboard_state}}
        </text>
      </scroller>
    </div>
    <div>
      <input test-id="input-obj" ref="range" class="input" type="text" placeholder="input placeholder" @input="eventInput" @change="onChange" @focus="onFocus" @blur="onBlur" @keyboard="onKeyBoard"></input>
    </div>
    <div class="group">
      <div class="panel"><text class="text" @click="setRange">setSelectionRange</text></div>
      <div class="panel"><text class="text" @click="getRange">getSelectionRange</text></div>
    </div>
  </div>
</template>
<script>
  module.exports = {
    data : {
      state:'',
      keyboard_state: ''
    },
    methods : {
      eventInput:function (e) {
        this.state='input: ' + JSON.stringify(e)
      },
      onChange:function(e){
        this.state='change: '+ JSON.stringify(e) 
      },  
      onFocus:function (e) {
        this.state='focus: '+ JSON.stringify(e) 
      }, 
      onBlur:function (e) {
        this.state='blur: '+ JSON.stringify(e)
      },
      onKeyBoard: function(e) {
        this.keyboard_state = "\n onkeyboard: " + JSON.stringify(e)
      },
      setRange() {
        this.$refs.range.setSelectionRange(1, 4);
      },
      getRange() {
        this.$refs.range.getSelectionRange(params => {
          this.state = `当前文本选区为 ${params.selectionStart} ~ ${params.selectionEnd}`;
          this.keyboard_state = "";
        });
      },
    }
  }
</script>

<style scoped>
  .mr-base{
    margin: 10px;
  }
  .title {
      height: 100px;
      margin-top: 30px;
      margin-bottom: 20px;
      flex-direction: column;
      justify-content: center;
  }
  .output {
    border-width: 2px;
    border-style: solid;
    border-color: rgb(162, 217, 192);
    width: 650px;
    height: 200px;
    margin-left: 50px;
    margin-top: 20px;
    margin-bottom: 30px;
  }
  .desc{
    color:#aa0000;
    font-size: 30px;
  }
  .input{
    width: 650px;
    height:100px;
    border-width: 1px;
    border-style: solid;
    border-color: rgb(162, 217, 192);
    placeholder-color: #41B883;
    margin-left: 50px;
    padding-left: 20px;
    font-size: 28px;
  }
  .panel {
    height: 100px;
    flex-direction: column;
    border-width: 2px;
    border-style: solid;
    border-color: rgb(162, 217, 192);
    background-color: rgba(162, 217, 192, 0.2);
    margin-left: 20px;
    display:inline-block;
    padding: 10px;
    padding-top: 20px;
  }
  .group {
    flex-direction: row;
    width:auto;
    margin-top: 30px;
    margin-left: 45px;
    margin-right: auto;
  }
</style>

6.<textarea>的属性和使用

<textarea><input> 组件类似,可用于接受用户输入数据。<textarea> 支持多行文本输入。 <textarea> 支持 <input> 支持的所有的属性、样式和事件,不支持子组件。

除了支持 input 支持的所有属性外,textarea 还支持 row 属性,用于指定输入的行数。

<textarea>的事件:

其示例:

<template>
  <div class="wrapper">
    <textarea class="textarea" @input="oninput" @change="onchange" @focus="onfocus" @blur="onblur"></textarea>
  </div>
</template>

<script>
  const modal = weex.requireModule('modal')

  export default {
    methods: {
      oninput (event) {
        console.log('oninput:', event.value)
        modal.toast({
          message: `oninput: ${event.value}`,
          duration: 0.8
        })
      },
      onchange (event) {
        console.log('onchange:', event.value)
        modal.toast({
          message: `onchange: ${event.value}`,
          duration: 0.8
        })
      },
      onfocus (event) {
        console.log('onfocus:', event.value)
        modal.toast({
          message: `onfocus: ${event.value}`,
          duration: 0.8
        })
      },
      onblur (event) {
        console.log('onblur:', event.value)
        modal.toast({
          message: `input blur: ${event.value}`,
          duration: 0.8
        })
      }
    }
  }
</script>

<style>
  .textarea {
    font-size: 50px;
    width: 650px;
    margin-top: 50px;
    margin-left: 50px;
    padding-top: 20px;
    padding-bottom: 20px;
    padding-left: 20px;
    padding-right: 20px;
    color: #666666;
    border-width: 2px;
    border-style: solid;
    border-color: #41B883;
  }
</style>

至此<recycle-list>、<scroller>、<slider>、<indicator>、<textarea>和<input>这六个组件就学习完了,学起来是不是觉得和Android的组件极度相似?所以在学起来是没有任何难度的。那么下篇博客我们将学习Weex剩下的四个常用组件,不积跬步无以至千里,新技术的路上,加油!

上一篇下一篇

猜你喜欢

热点阅读