[refactor] Noticebar:升级到自定义组件 (#165)

* [improvement] Tab:升级到自定义组件

* fix: 去除冗余example代码

* [refactor] 重构badge为自定义组件 (#160)

* fix: 去除tab组件使用对象入参方式,修改example用例

* refactor: 重构noticebar组件

* fix: 去除tab组件冗余属性字段
This commit is contained in:
kobeCristiano 2018-03-25 18:30:53 +08:00 committed by Yao
parent a1b70a8437
commit 86152d45ce
11 changed files with 377 additions and 146 deletions

View File

@ -1,23 +1,28 @@
var Zan = require('../../dist/index'); Page({
Page(Object.assign({}, Zan.NoticeBar, {
data: { data: {
movable: { bar1: {
text: '足协杯战线连续第2年上演广州德比战上赛季半决赛上恒大以两回合5-3的总比分淘汰富力。',
scrollable: true,
delay: 1000
},
bar2: {
text: '足协杯战线连续第2年上演广州德比战',
color: '#fff',
backgroundColor: '#000'
},
bar3: {
text: '足协杯战线连续第2年上演广州德比战上赛季半决赛上恒大以两回合5-3的总比分淘汰富力。' text: '足协杯战线连续第2年上演广州德比战上赛季半决赛上恒大以两回合5-3的总比分淘汰富力。'
}, },
static1: { bar4: {
text: '足协杯战线连续第2年上演广州德比战' text: '带icon的公告',
leftIcon: 'https://img.yzcdn.cn/public_files/2017/8/10/6af5b7168eed548100d9041f07b7c616.png'
}, },
static2: { bar5: {
text: '足协杯战线连续第2年上演广州德比战上赛季半决赛上恒大以两回合5-3的总比分淘汰富力。' text: '足协杯战线连续第2年上演广州德比战上赛季半决赛上恒大以两回合5-3的总比分淘汰富力。',
leftIcon: 'https://img.yzcdn.cn/public_files/2017/8/10/6af5b7168eed548100d9041f07b7c616.png',
mode: 'closeable',
scrollable: true,
speed: 10
} }
},
onShow() {
// 滚动通告栏需要initScroll
this.initZanNoticeBarScroll('movable');
// initScroll的通告栏如果宽度足够显示内容将保持静止
this.initZanNoticeBarScroll('static1');
// 不进行initScroll的通告栏也将保持静止
// this.initZanNoticeBarScroll('static2');
} }
})) })

View File

@ -1,3 +1,6 @@
{ {
"navigationBarTitleText": "Noticebar 通告栏" "navigationBarTitleText": "Noticebar 通告栏",
"usingComponents": {
"zan-noticebar": "../../dist/noticebar/index"
}
} }

View File

@ -1,30 +1,63 @@
<import src="/dist/noticebar/index.wxml" />
<view class="container"> <view class="container">
<view class="doc-title zan-hairline--bottom">NOTICEBAR</view> <view class="doc-title zan-hairline--bottom">NOTICEBAR</view>
<view class="zan-panel-title">滚动通告栏</view> <view class="zan-panel-title">滚动通告栏</view>
<view class="zan-panel"> <view class="zan-panel">
<template <zan-noticebar
is="zan-noticebar" text="{{ bar1.text }}"
data="{{ ...movable, componentId: 'movable' }}" scrollable="{{ bar1.scrollable }}"
></template> />
</view> </view>
<view class="zan-panel-title">静止通告栏1</view> <view class="zan-panel-title">延时滚动通告栏</view>
<view class="zan-panel"> <view class="zan-panel">
<template <zan-noticebar
is="zan-noticebar" text="{{ bar1.text }}"
data="{{ ...static1, componentId: 'static1' }}" scrollable="{{ bar1.scrollable }}"
></template> delay="{{ bar1.delay }}"
/>
</view> </view>
<view class="zan-panel-title">静止通告栏2</view> <view class="zan-panel-title">初始速度低滚动通告栏</view>
<view class="zan-panel"> <view class="zan-panel">
<template <zan-noticebar
is="zan-noticebar" text="{{ bar1.text }}"
data="{{ ...static2, componentId: 'static2' }}" scrollable="{{ bar1.scrollable }}"
></template> speed="{{ bar5.speed }}"
/>
</view>
<view class="zan-panel-title">改变颜色通告栏</view>
<view class="zan-panel">
<zan-noticebar
text="{{ bar2.text }}"
color="{{ bar2.color }}"
background-color="{{ bar2.backgroundColor }}"
/>
</view>
<view class="zan-panel-title">静止通告栏</view>
<view class="zan-panel">
<zan-noticebar
text="{{ bar3.text }}"
/>
</view>
<view class="zan-panel-title">带icon公告</view>
<view class="zan-panel">
<zan-noticebar
text="{{ bar4.text }}"
left-icon="{{ bar4.leftIcon }}"
/>
</view>
<view class="zan-panel-title">可关闭公告</view>
<view class="zan-panel">
<zan-noticebar
text="{{ bar5.text }}"
mode="{{ bar5.mode }}"
/>
</view> </view>
</view> </view>

View File

@ -1,6 +1,3 @@
const interval = 50;
let moduleId = 1;
Page({ Page({
data: { data: {
tab1: { tab1: {

View File

@ -1,49 +1,95 @@
## Noticebar 通告栏 ## Noticebar 通告栏
### 使用指南 ### 使用指南
在 app.wxss 中引入组件库所有样式 在 index.json 中引入组件
```css ```json
@import "path/to/zanui-weapp/dist/index.wxss"; {
"usingComponents": {
"zan-noticebar": "path/to/zanui-weapp/dist/noticebar/index"
}
}
``` ```
在需要使用的页面里引入组件库模板和脚本 在 index.js 中声明组件数据
```html
<import src="path/to/zanui-weapp/dist/noticebar/index.wxml" />
<!-- 直接使用 zan-noticebar 模板,并且直接传入设置值 -->
<template is="zan-noticebar" data="{{ ...data, componentId: 'noticebar' }}"></template>
```
// 在 Page 中混入 Noticebar 里面声明的方法
```js ```js
const { Noticebar, extend } = require('path/to/zanui-weapp/dist/index'); // 在 Page 中声明 Noticebar 依赖的展示数据
Page({
Page(extend({}, Noticebar, { data: {
// ... text: 'xxx',
})); scrollable: 'xxx',
...
}
})
``` ```
### 代码演示 ### 代码演示
`Noticebar` 组件支持滚动和静止两种展示方式,通过 text 传入展示文案 `Noticebar` 组件支持滚动和静止两种展示方式,通过 text 传入展示文案
### 静止公告栏
```html ```html
<template is="zan-noticebar" data="{{ text: '展示文案', componentId: 'noticebar' }}"></template> <zan-noticebar
text="{{ text }}"
/>
``` ```
**注意** ### 滚动通告栏
```html
如果组件需要开启滚动展示,需要在 Page 的脚本中执行 initZanNoticeBarScroll 方法,来开启滚动展示 <zan-noticebar
```js text="{{ text }}"
Page(extend({}, Noticebar, { scrollable="true"
// ... />
onShow() {
// 在方法中传入对应的 componentId
this.initZanNoticeBarScroll('movable');
}
// ...
}));
``` ```
| 参数 | 说明 | 类型 | 默认值 | 必须 | ### 延时滚动通告栏
```html
<zan-noticebar
text="{{ text }}"
scrollable="true"
delay="{{ delay }}"
/>
```
### 改变滚动通告栏滚动速度
```html
<zan-noticebar
text="{{ text }}"
scrollable="true"
speed="{{ speed }}"
/>
```
### 自定义通告栏字体颜色和背景色
```html
<zan-noticebar
text="{{ text }}"
color="{{ color }}"
background-color="{{ backgroundColor }}"
/>
```
### 添加左侧icon通告栏
```html
<zan-noticebar
text="{{ text }}"
left-icon="https://img.yzcdn.cn/public_files/2017/8/10/6af5b7168eed548100d9041f07b7c616.png"
/>
```
### 可关闭通告栏
```html
<zan-noticebar
text="{{ text }}"
mode="closeable"
/>
```
| 参数 | 说明 | 类型 | 默认值 | 可选值 |
|-----------|-----------|-----------|-------------|-------------| |-----------|-----------|-----------|-------------|-------------|
| text | 通告栏展示文案 | String | - | | | text | 通告栏展示文案 | String | - | |
| componentId | 用于区分页面多个 Noticebar 组件,在调用 initZanNoticeBarScroll 时需要传入 | String | - | | | mode | 通告栏模式 | String | '' | `closeable` |
| delay | 滚动延时时间 | Number | 0 | |
| speed | 滚动速度 | Number | 40 | |
| scrollable | 是否可滚动 | Boolean | false | |
| leftIcon | 左侧图标 | String | - | |
| color | 通告栏字体颜色 | String | `#f60` | |
| backgroundColor | 通告栏背景色 | String | `#fff7cc` |

View File

@ -1,74 +1,165 @@
const ZanNoticeBar = { const VALID_MODE = ['closeable'];
initZanNoticeBarScroll(componentId) { const FONT_COLOR = '#f60';
this.zanNoticeBarNode = this.zanNoticeBarNode || {}; const BG_COLOR = '#fff7cc';
this.zanNoticeBarNode[`${componentId}`] = {
width: undefined,
wrapWidth: undefined,
animation: null,
resetAnimation: null
};
const currentComponent = this.zanNoticeBarNode[`${componentId}`]; Component({
wx.createSelectorQuery() properties: {
text: {
type: String,
value: ''
},
mode: {
type: String,
value: ''
},
url: {
type: String,
value: ''
},
openType: {
type: String,
value: 'navigate'
},
delay: {
type: Number,
value: 0
},
speed: {
type: Number,
value: 40
},
scrollable: {
type: Boolean,
value: false
},
leftIcon: {
type: String,
value: ''
},
color: {
type: String,
value: FONT_COLOR
},
backgroundColor: {
type: String,
value: BG_COLOR
}
},
data: {
show: true,
hasRightIcon: false,
width: undefined,
wrapWidth: undefined,
elapse: undefined,
animation: null,
resetAnimation: null,
timer: null
},
attached() {
const { mode } = this.data;
if (mode && this._checkMode(mode)) {
this.setData({
hasRightIcon: true
});
}
},
ready() {
this._init();
},
methods: {
_checkMode(val) {
const isValidMode = ~VALID_MODE.indexOf(val);
if (!isValidMode) {
console.warn(`mode only accept value of ${VALID_MODE}, now get ${val}.`);
}
return isValidMode;
},
_init() {
wx.createSelectorQuery()
.in(this) .in(this)
.select(`#${componentId}__content`) .select('.zan-noticebar__content')
.boundingClientRect((rect) => { .boundingClientRect(rect => {
if (!rect || !rect.width) { if (!rect || !rect.width) {
console.warn('页面缺少 noticebar 元素'); throw new Error('页面缺少 noticebar 元素');
return; return;
} }
this.setData({
width: rect.width
});
currentComponent.width = rect.width; wx.createSelectorQuery()
wx
.createSelectorQuery()
.in(this) .in(this)
.select(`#${componentId}__content-wrap`) .select('.zan-noticebar__content-wrap')
.boundingClientRect((rect) => { .boundingClientRect((rect) => {
if (!rect || !rect.width) { if (!rect || !rect.width) {
return; return;
} }
clearTimeout(this.data[componentId].setTimeoutId) const wrapWidth = rect.width;
const { width, speed, scrollable, delay } = this.data;
currentComponent.wrapWidth = rect.width; if (scrollable && wrapWidth < width) {
if (currentComponent.wrapWidth < currentComponent.width) { const elapse = width / speed * 1000;
var mstime = currentComponent.width / 40 * 1000; console.log(`delay: ${delay}`)
currentComponent.animation = wx.createAnimation({ const animation = wx.createAnimation({
duration: mstime, duration: elapse,
timingFunction: 'linear' timeingFunction: 'linear',
delay
}); });
currentComponent.resetAnimation = wx.createAnimation({ const resetAnimation = wx.createAnimation({
duration: 0, duration: 0,
timingFunction: 'linear' timeingFunction: 'linear'
});
this.setData({
elapse,
wrapWidth,
animation,
resetAnimation
}, () => {
this._scroll();
}); });
this.scrollZanNoticeBar(componentId, mstime);
} }
}) })
.exec(); .exec();
}) })
.exec(); .exec();
}, },
scrollZanNoticeBar(componentId, mstime) { _scroll() {
const currentComponent = this.zanNoticeBarNode[`${componentId}`]; const { animation, resetAnimation, wrapWidth, elapse, speed } = this.data;
const resetAnimationData = currentComponent.resetAnimation.translateX(currentComponent.wrapWidth).step(); const resetAnimationData = resetAnimation.translateX(wrapWidth).step();
this.setData({ const animationData = animation.translateX(-elapse * speed / 1000).step();
[`${componentId}.animationData`]: resetAnimationData.export()
});
const aninationData = currentComponent.animation.translateX(-mstime * 40 / 1000).step();
setTimeout(() => {
this.setData({ this.setData({
[`${componentId}.animationData`]: aninationData.export() animationData: resetAnimation.export()
}); });
}, 100); setTimeout(() => {
this.setData({
animationData: animationData.export()
})
}, 100);
const setTimeoutId = setTimeout(() => { const timer = setTimeout(() => {
this.scrollZanNoticeBar(componentId, mstime); this._scroll();
}, mstime); }, elapse);
this.setData({
[`${componentId}.setTimeoutId`]: setTimeoutId this.setData({
}) timer
});
},
_handleButtonClick() {
const { timer } = this.data;
timer && clearTimeout(timer);
this.setData({
show: false,
timer: null
});
}
} }
}; })
module.exports = ZanNoticeBar;

View File

@ -0,0 +1,6 @@
{
"component": true,
"usingComponents": {
"zan-icon": "../icon/index"
}
}

View File

@ -1,7 +1,43 @@
.zan-noticebar { .zan-noticebar {
color: #f60; display: flex;
padding: 9px 10px; padding: 9px 10px;
font-size: 12px; font-size: 12px;
line-height: 1.5; line-height: 1.5;
background-color: #fff7cc;
&--within-icon {
position: relative;
padding-right: 30px;
}
&__left-icon {
height: 18px;
min-width: 20px;
padding-top: 1px;
box-sizing: border-box;
> image {
width: 16px;
height: 16px;
}
}
&__right-icon {
position: absolute;
top: 10px;
right: 10px;
font-size: 15px;
line-height: 1;
}
&__content-wrap {
position: relative;
flex: 1;
height: 18px;
overflow: hidden;
}
&__content {
position: absolute;
white-space: nowrap;
}
} }

View File

@ -1,16 +1,31 @@
<template name="zan-noticebar"> <view
<view class="zan-noticebar"> wx:if="{{ show }}"
<view class="zan-noticebar {{ hasRightIcon ? 'zan-noticebar--within-icon' : '' }}"
id="{{ componentId }}__content-wrap" style="color: {{ color }};background-color: {{ backgroundColor }}"
style="height: 18px; overflow: hidden; position: relative;" >
> <view wx:if="{{ leftIcon }}" class="zan-noticebar__left-icon">
<view <image src="{{ leftIcon }}" />
animation="{{ animationData }}" </view>
id="{{ componentId }}__content" <view class="zan-noticebar__content-wrap">
style="position: absolute; white-space: nowrap;" <view class="zan-noticebar__content" animation="{{ animationData }}">
> {{ text }}
{{ text }}
</view>
</view> </view>
</view> </view>
</template>
<block wx:if="{{ mode }}">
<zan-icon
wx:if="{{ mode === 'closeable' }}"
class="zan-noticebar__right-icon"
type="close"
bindtap="_handleButtonClick"
/>
<navigator
wx:if="{{ mode === 'link' }}"
url="{{ url }}"
open-type="{{ openType }}"
>
<zan-icon class="zan-noticebar__right-icon" type="arrow" />
</navigator>
</block>
</view>

View File

@ -5,9 +5,13 @@
```json ```json
{ {
"usingComponents": { "usingComponents": {
"zan-tab": "path/to/zanui-weapp/dist/icon/index" "zan-tab": "path/to/zanui-weapp/dist/tab/index"
} }
} }
```
在 index.js 中声明组件数据
```js
// 在 Page 中声明 Tab 依赖的展示数据 // 在 Page 中声明 Tab 依赖的展示数据
Page({ Page({
data: { data: {
@ -36,15 +40,14 @@ Page({
| 参数 | 说明 | 类型 | 默认值 | 必须 | | 参数 | 说明 | 类型 | 默认值 | 必须 |
|-----------|-----------|-----------|-------------|-------------| |-----------|-----------|-----------|-------------|-------------|
| tab.scroll | 是否开启 tab 左右滑动模式 | Boolean | - | | | scroll | 是否开启 tab 左右滑动模式 | Boolean | - | |
| tab.list | 可选项列表 | Array | - | | | list | 可选项列表 | Array | - | |
| tab.selectedId | 选中id | - | - | | | selectedId | 选中id | - | - | |
| tab.height | tab高度 | Number | - | | | height | tab高度 | Number | - | |
| tab.fixed | 是否固定位置 | Boolean | - | | | fixed | 是否固定位置 | Boolean | - | |
| componentId | 用于区分页面多个 tab 组件 | String | - | |
tab 组件中,tab.list 数据格式如下 tab 组件中list 数据格式如下
```js ```js
[{ [{
// tab 项 id // tab 项 id

View File

@ -26,10 +26,6 @@ Component({
currentTab: newVal currentTab: newVal
}); });
} }
},
componentId: {
type: String,
default: ''
} }
}, },