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

    xiaoxiao2022-07-06  207

    这几天忙着做组件化了,博客晚了些更新,说到组件化,我近期也会用博客来介绍的。上一篇博客我们讲的是weex的内置组件,那么这篇博客我们学习最后四个组件,下篇博客我们就会讲到世界weex页面的编写了。这篇博客我们来学习<waterfall>、<video>、<web>和<richtext>。weex的组件真的是要好好学牢固的,很多人可能会觉得定义太多记不住,没关系,在后续实际页面的编写上我们还是会温习的。

    1.<waterfall>的简介和使用

    <waterfall> 组件是提供瀑布流布局的核心组件。瀑布流,又称瀑布流式布局是比较流行的一种页面布局,视觉表现为参差不齐的多栏布局。随着页面滚动条向下滚动,这种布局还可以不断加载数据块并附加至当前尾部。

    <template> <waterfall column-count="2" column-width="auto"> <cell v-for="num in lists" > <text>{{num}}</text> </cell> </waterfall> </template> <script> export default { data () { return { lists: ['A', 'B', 'C', 'D', 'E'] } } } </script> <style></style>

    <waterfall>的子组件

    和 <list>组件一样, <waterfall> 组件的子组件只能包括以下四种组件或是 fix 定位的组件,其他形式的组件将不能被正确渲染。

    <cell>:用于定义列表中的子列表项,类似于 HTML 中的 ul 之于 li。Weex 会对 <cell> 进行高效的内存回收以达到更好的性能。<header>:当 <header> 到达屏幕顶部时,吸附在屏幕顶部。<refresh>:用于给列表添加下拉刷新的功能。<loading>:<loading> 用法与特性和 <refresh> 类似,用于给列表添加上拉加载更多的功能。

    <waterfall>的属性

    show-scrollbar : [可选] 可选值为 true/ false,默认值为 true。控制是否出现滚动条。 [H5无效]column-count: [可选]描述瀑布流的列数 auto: 意味着列数是被其他属性所决定的(比如 column-width)<integer>: 最佳列数,column-width 和 column-count 都指定非0值, 则 column-count 代表最大列数。column-width : [可选]描述瀑布流每一列的列宽 auto: 意味着列宽是被其他属性所决定的(比如 column-count)<length>: 最佳列宽,实际的列宽可能会更宽(需要填充剩余的空间), 或者更窄(如果剩余空间比列宽还要小)。 该值必须大于0column-gap: [可选]列与列的间隙. 如果指定了 normal 。left-gap: [可选]左边cell和列表的间隙. 如果未指定 。right-gap: [可选]右边cell和列表的间隙. 如果未指定。

     

    <waterfall>的事件

    支持所有通用事件:

    click:用于监听点击事件。(例如:一般绑定于子组件之上触发跳转)。longpress:用于监听长按事件(一般绑定于子组件之上例如:手机淘宝猜你喜欢瀑布流,长按可删除您不感兴趣的商品)。appear:用于监听子组件出现事件(一般绑定于子组件之上例如:监听最后一个元素出现,加载新的数据)disappear:用于监听子组件滑出屏幕事件(一般绑定于子组件之上)

    <waterfall>使用示例如下:

    <template> <waterfall class="page" ref="waterfall" v-bind:style="{padding:padding}" :column-width="columnWidth" :column-count="columnCount" :column-gap="columnGap" :show-scrollbar="showScrollbar" :scrollable="scrollable" @scroll="recylerScroll" @loadmore="loadmore" loadmoreoffset=3000 > <refresh class="refresh" @refresh="onrefresh" @pullingdown="onpullingdown" :display="refreshing ? 'show' : 'hide'"> <loading-indicator class="indicator"></loading-indicator> <text class="refreshText">{{refreshText}}</text> </refresh> <header class="stickyHeader" > <div v-if="stickyHeaderType === 'none'" class="stickyWrapper"> <text class="stickyText">Header</text> </div> <div v-if="stickyHeaderType === 'appear'" class="stickyWrapper"> <div class="stickyTextImageWrapper"> <text class="stickyText">Last Appear:</text> <image class="stickyImage" :src="appearImage"></image> </div> <div class="stickyTextImageWrapper"> <text class="stickyText">Last Disappear:</text> <image class="stickyImage" :src="disappearImage"></image> </div> </div> <div v-if="stickyHeaderType === 'scroll'" class="stickyWrapper"> <text class="stickyText">Content Offset:{{contentOffset}}</text> </div> </header> <cell v-for="(item, index) in items" :key="item.src" class="cell" ref="index"> <div class="item" @click="onItemclick(item.behaviour, index)" @appear="itemAppear(item.src)" @disappear="itemDisappear(item.src)"> <text v-if="item.name" class="itemName">{{item.name}}</text> <image class="itemPhoto" :src="item.src"></image> <text v-if="item.desc" class="itemDesc">{{item.desc}}</text> <text v-if="item.behaviourName" class="itemClickBehaviour"> {{item.behaviourName}}</text> </div> </cell> <header class="footer" ref="footer"> <text class="stickyText">Footer</text> </header> <div ref="fixed" class="fixedItem" @click="scrollToNext"> <text class="fixedText">bot</text> </div> </waterfall> </template> <style> .page { background-color: #EFEFEF; } .refresh { height: 128px; width: 750px; flex-direction: row; align-items: center; justify-content: center; } .refreshText { color: #888888; font-weight: bold; } .indicator { color: #888888; height: 40px; width: 40px; margin-right: 30px; } .absolute { position: absolute; top: 0px; width: 750px; height: 377px; } .avatar { width: 148px; height: 108px; border-radius: 54px; border-width: 4px; border-color: #FFFFFF; margin-bottom: 14px; } .name { font-weight: bold; font-size:32px; color:#ffffff; line-height:32px; text-align:center; margin-bottom: 16px; } .titleWrap { width: 100px; height: 24px; margin-bottom: 10px; background-color: rgba(255,255,255,0.80); border-radius: 12px; justify-content: center; align-items: center; } .title { font-size: 20px; color: #000000; } .stickyHeader { position: sticky; height: 94px; flex-direction: row; padding-bottom:6px; } .stickyWrapper { flex-direction: row; background-color:#00cc99; justify-content: center; align-items: center; flex:1; } .stickyTextImageWrapper { flex:1; justify-content: center; align-items: center; flex-direction: row; } .stickyText { color: #FFFFFF; font-weight: bold; font-size:32px; margin-right: 12px; } .stickyImage { width: 64px; height: 64px; border-radius: 32px; } .cell { padding-top: 10px; padding-bottom: 10px; } .item { padding: 10px; background-color: #FFFFFF; align-items: center; } .itemName { font-size:28px; color:#333333; line-height:42px; text-align:left; margin-top: 24px; } .itemPhoto { margin-top: 18; width: 220px; height: 220px; margin-bottom: 18px; } .itemDesc { font-size:24px; margin:12px; color:#999999; line-height:36px; text-align:left; } .itemClickBehaviour { font-size:36px; color:#00cc99; line-height:36px; text-align:center; margin-top: 6px; margin-left: 24px; margin-right: 24px; margin-bottom: 30px; } .footer { height: 94px; justify-content: center; align-items: center; background-color: #00cc99; } .fixedItem { position: fixed; width:78px; height:78px; background-color:#00cc99; right: 32px; bottom: 32px; border-radius: 39px; align-items: center; justify-content: center; } .fixedText { font-size: 32px; color: white; line-height: 32px; } </style> <script> export default { data: function() { const items = [ { src:'https://gw.alicdn.com/tps/TB1Jl1CPFXXXXcJXXXXXXXXXXXX-370-370.jpg', name: 'Thomas Carlyle', desc:'Genius only means hard-working all one\'s life', behaviourName: 'Change width', behaviour: 'changeColumnWidth', }, { src:'https://gw.alicdn.com/tps/TB1Hv1JPFXXXXa3XXXXXXXXXXXX-370-370.jpg', desc:'The man who has made up his mind to win will never say "impossible "', behaviourName: 'Change gap', behaviour: 'changeColumnGap' }, { src:'https://gw.alicdn.com/tps/TB1eNKuPFXXXXc_XpXXXXXXXXXX-370-370.jpg', desc:'There is no such thing as a great talent without great will - power', behaviourName: 'Change count', behaviour: 'changeColumnCount' }, { src:'https://gw.alicdn.com/tps/TB1DCh8PFXXXXX7aXXXXXXXXXXX-370-370.jpg', name:'Addison', desc:'Cease to struggle and you cease to live', behaviourName: 'Show scrollbar', behaviour: 'showScrollbar', }, { src:'https://gw.alicdn.com/tps/TB1ACygPFXXXXXwXVXXXXXXXXXX-370-370.jpg', desc:'A strong man will struggle with the storms of fate', behaviourName: 'Listen appear', behaviour: 'listenAppear', }, { src:'https://gw.alicdn.com/tps/TB1IGShPFXXXXaqXVXXXXXXXXXX-370-370.jpg', name:'Ruskin', desc:'Living without an aim is like sailing without a compass', behaviourName: 'Set scrollable', behaviour: 'setScrollable', }, { src:'https://gw.alicdn.com/tps/TB1xU93PFXXXXXHaXXXXXXXXXXX-240-240.jpg', behaviourName: 'waterfall padding', behaviour: 'setPadding', }, { src:'https://gw.alicdn.com/tps/TB19hu0PFXXXXaXaXXXXXXXXXXX-240-240.jpg', name:'Balzac', desc:'There is no such thing as a great talent without great will - power', behaviourName: 'listen scroll', behaviour: 'listenScroll', }, { src:'https://gw.alicdn.com/tps/TB1ux2vPFXXXXbkXXXXXXXXXXXX-240-240.jpg', behaviourName: 'Remove cell', behaviour: 'removeCell', }, { src:'https://gw.alicdn.com/tps/TB1tCCWPFXXXXa7aXXXXXXXXXXX-240-240.jpg', behaviourName: 'Move cell', behaviour: 'moveCell', } ] let repeatItems = []; for (let i = 0; i < 3; i++) { repeatItems.push(...items) } return { padding: 0, refreshing: false, refreshText: '↓ pull to refresh...', columnCount: 2, columnGap: 12, columnWidth: 'auto', contentOffset: '0', showHeader: true, showScrollbar: true, scrollable: true, showStickyHeader: false, appearImage: null, disappearImage: null, stickyHeaderType: 'none', // fixedRect:'', items: repeatItems } }, created() { // let self = this // setTimeout(()=>{ // weex.requireModule('dom').getComponentRect(this.$refs.fixed, result=>{ // const x = result.size.left // const y = result.size.top // const width = result.size.width // const height = result.size.height // self.fixedRect = `${x}|${y}|${width}|${height}` // }) // }, 3000) }, methods: { recylerScroll: function(e) { this.contentOffset = e.contentOffset.y }, loadmore: function(e) { console.log('receive loadmore event') // this.$refs.waterfall.resetLoadmore() }, showOrRemoveHeader: function() { this.showHeader = !this.showHeader }, onItemclick: function (behaviour, index) { console.log(`click...${behaviour} at index ${index}`) switch (behaviour) { case 'changeColumnCount': this.changeColumnCount() break case 'changeColumnGap': this.changeColumnGap() break case 'changeColumnWidth': this.changeColumnWidth() break case 'showScrollbar': this.showOrHideScrollbar() break case 'listenAppear': this.listenAppearAndDisappear() break case 'setScrollable': this.setScrollable() break case 'setPadding': this.setRecyclerPadding() break case 'listenScroll': this.listenScrollEvent() break case 'removeCell': this.removeCell(index) break case 'moveCell': this.moveCell(index) break } }, itemAppear: function(src) { this.appearImage = src; }, itemDisappear: function(src) { this.disappearImage = src; }, changeColumnCount: function() { if (this.columnCount === 2) { this.columnCount = 3 } else { this.columnCount = 2 } }, changeColumnGap: function() { if (this.columnGap === 12) { this.columnGap = 'normal' } else { this.columnGap = 12 } }, changeColumnWidth: function() { if (this.columnWidth === 'auto') { this.columnWidth = 600 } else { this.columnWidth = 'auto' } }, showOrHideScrollbar: function() { this.showScrollbar = !this.showScrollbar }, setScrollable: function() { this.scrollable = !this.scrollable }, listenAppearAndDisappear: function() { this.stickyHeaderType = (this.stickyHeaderType === 'appear' ? 'none' : 'appear') }, listenScrollEvent: function() { this.stickyHeaderType = (this.stickyHeaderType === 'scroll' ? 'none' : 'scroll') }, scrollToNext: function() { weex.requireModule('dom').scrollToElement(this.$refs.footer) }, setRecyclerPadding: function() { this.padding = (this.padding == 0 ? 12 : 0); }, removeCell: function(index) { this.items.splice(index, 1) }, moveCell: function(index) { if (index == 0) { this.items.splice(this.items.length - 1, 0, this.items.splice(index, 1)[0]); } else { this.items.splice(0, 0, this.items.splice(index, 1)[0]); } }, onrefresh (event) { this.refreshing = true this.refreshText = "loading..." setTimeout(() => { this.refreshing = false this.refreshText = '↓ pull to refresh...' }, 2000) }, onpullingdown (event) { if (event.pullingDistance < -64) { this.refreshText = '↑ release to refresh...' } else { this.refreshText = '↓ pull to refresh...' } } } } </script>

    2.<video>的简介和使用

    <video>的简介

    Video 组件用于在页面中嵌入视频内容。

    <video>的子组件

    text 是唯一合法的子组件。

    <video>的属性

    src, string. 内嵌的视频指向的URL。play-status, string. 可选值为 play | pause,用来控制视频的播放状态,play 或者 pause,默认值是 pause。auto-play, boolean. 当页面加载初始化完成后,用来控制视频是否立即播放,默认值是 false。poster, string, v0.18+ & iOS. 指定视频首图的图片链接。controls, string, v0.19+. 可选值为 controls | nocontrols,控制视频播放组件是否显示回放控制面板,默认会显示,当指定为 nocontrols 时不显示回放控制面板。

     

    <video>的事件

    start 当 playback 的状态是 Playing 时触发。pause 当 playback 的状态是 Paused 时触发。finish 当 playback 的状态是 Finished 时触发。fail 当 playback 状态是 Failed 时触发。

    <video>的示例:

    <template> <div> <video class="video" :src="src" autoplay controls @start="onstart" @pause="onpause" @finish="onfinish" @fail="onfail"></video> <text class="info">state: {{state}}</text> </div> </template> <style scoped> .video { width: 630px; height: 350px; margin-top: 60px; margin-left: 60px; } .info { margin-top: 40px; font-size: 40px; text-align: center; } </style> <script> export default { data () { return { state: '----', src:'http://flv2.bn.netease.com/videolib3/1611/01/XGqSL5981/SD/XGqSL5981-mobile.mp4' } }, methods:{ onstart (event) { this.state = 'onstart' }, onpause (event) { this.state = 'onpause' }, onfinish (event) { this.state = 'onfinish' }, onfail (event) { this.state = 'onfinish' } } } </script>

     3.<web>的简介和使用

    <web>的简介

    <web> 用于在 WEEX 页面中显示由 src 属性指定的网页内容。

    <web> 可以使 H5 与 Native 元素相结合。

    您可以整个页面铺满 Web 页面(快速兼容您之前的 H5 页面)可以使用 Web 和其他 Weex 组件合成复杂页面使用 Web 组合出多种效果(设置透明背景的 H5 页面,灵活配置各类 H5 活动资讯) <template> <web src="https://www.taobao.com/"></web> </template> <script></script> <style></style>

    特别注意事项

    <web> 不支持任何嵌套的子组件。<web> 必须指定 width 和 height 的样式属性,否则将不起作用。您可以使用 webview module来控制 <web>。

    <web>的属性

    src是要加载的网页内容的 URL。建议指定线上真实存在的 URL 地址。

    <web>的事件

    支持 appear 和 disappear 事件同时支持:

    pagestart 会在 Web 页面开始加载时调用。

    事件对象:

    url: {String} 当前 Web 页面的 URL。

    pagefinish 会在 Web 页面完成加载时调用。

    事件对象:

    url: {String} 当前 Web 页面的 URL。canGoBack: {Boolean} 当前 Web 页面是否可以回退。canGoForward: {Boolean} 当前 Web 页面是否可以前进。title: {String} 当前 Web 页面的标题(仅限 iOS 平台)。

    error 会在 Web 页面加载失败时调用。

    receivedtitle 会在 Web 页面的标题发生改变时调用(仅限 Android 平台)。

    <template> <div class="wrapper"> <web @pagestart="onPageStart" @pagefinish="onPageFinish" @error="onError" src="https://www.taobao.com/"></web> </div> </template> <script> module.exports = { methods: { onPageStart: function(e) { // page start load }, onPageFinish: function(e) { // page finish load }, onError: function(e) { // page load error } } } </script> <style></style>

     4.<richtext>的简介和使用

    <richtext>的简介

    富文本组件可以内嵌 <span><a><image>。同时它也支持 <span><a><image> 的嵌套。

    只有 <span>, <a> and <image> 可以包含在 <richtext> 标签里。<span> and <a> 会被显示为 display:inline,而 <image> 会被显示为 display:inline-block。

    <richtext> 的子节点分两种类型。

    <span> and <a> 可以再包含孩子节点。<image> 不能再包含孩子节点。

    富文本组件内部树形结构不能超过255层,超过的层会被忽略。

    注意事项

    <a> 标签在 iOS 上恒定为 color:blue 蓝色样式,它孩子节点也会被应用为该样式,见下面样例。Android 上无此限制。<image> 标签必须指定 width 和 height.在图片下载完成前,<image> 会保持空白状态,目前不支持显示占位图。富文本组件自身不能嵌套。<span>, <a> 和 <richtext> 可以被继承 colorfont-familyfont-sizefont-stylefont-weightline-height不可被继承 background-color<span> 可以被继承 text-decoration: none | underline | line-through, 默认值是 none<richtext> 不可被继承 lines: 最大行数,必须为正数。<image> 不可被继承 widthheight通用事件 支持所有通用事件。itemclick. 只有img和span标签可能触发,触发时机是: img标签: img被点击时没有任何父节点是 a如果第一个条件不满足,Weex 会尝试打开 a 标签指定的链接。img 的 pseudo-ref 会作为参数传回来。

    span标签:

    a标签中的span被点击并且所在的a标签的href被指定为"click://"(这个条件iOS端强要求,Android端并不要求)a标签设置了pseudo-ref。此时itemclick事件会被触发,并且携带pseudo-ref的值。 

    <richtext>的使用示例:

    <template> <div> <richtext @itemclick="listener" style="color:red;text-overflow:ellipsis"> <span>link</span> <a href="http://t.cn?_wx_tpl=http://g.tbcdn.cn/ali-wireless-h5/res/0.0.16/hello.js"> <image style="width:150; height:150" src="https://img.alicdn.com/tps/i2/TB1hRb1IXXXXXX3XVXXXQaP.pXX-87-87.jpeg" pseudo-ref="22"></image> <span style="font-size:42;color:#FF5400;">TAOBAO</span> </a> <image style="width:300; height:300" src="http://www.fresher.ru/manager_content/images2/kadry-veka/big/2-1.jpg" pseudo-ref="23"></image> <span>继承Transition继承Transition继承Transition继承Transition继承Transition继承Transition继承Transition继承Transition继承Transition</span> </richtext> </div> </template> <script> module.exports = { methods: { listener: function (foo) { var modal = weex.requireModule('modal'); modal.toast({ 'message': 'My pseudoRef is'+foo.pseudoRef, 'duration': 3 }); } } } </script> <style> .logo{width: 50;height: 50;} .title{font-size:42; color: #FF5400;} </style>

    到此我们的weex组件就学习完了,下一篇博客我们来一起看看weex实际页面的编写。一套代码在Android和Ios上都是生效!

    最新回复(0)