户籍信息录入

This commit is contained in:
itgaojian 2023-12-06 14:22:42 +08:00
parent 152fcabe03
commit 0ac48d15f3
1028 changed files with 54224 additions and 327 deletions

27
app.js
View File

@ -1,17 +1,20 @@
//app.js
var restAjax = require('utils/restAjax.js');
var dialog = require('utils/dialog.js');
var dics = require('utils/dic.js')
App({
loginUrl: 'https://www.tenlion.com.cn/usercenter/',
// loginUrl: 'http://192.168.0.103:7001/usercenter/',
// requestUrl: 'http://192.168.0.120:8083/servicecity/',
requestUrl: 'https://www.tenlion.com.cn/servicecity/',
restAjax: restAjax,
dialog: dialog,
onLaunch: function () {
},
globalData: {
userInfo: null
}
// loginUrl: 'https://www.tenlion.com.cn/usercenter/',
loginUrl: 'http://219.147.99.164:8082/usercenter/',
requestUrl: 'http://219.147.99.164:8082/servicecity/',
personUrl: 'http://219.147.99.164:8082/population/',
// requestUrl: 'https://www.tenlion.com.cn/servicecity/',
restAjax: restAjax,
dialog: dialog,
dics: dics,
onLaunch: function () {
},
globalData: {
userInfo: null
}
})

View File

@ -1,17 +1,22 @@
{
"pages":[
"pages": [
"pages/index/index",
"pages/caseCheck/caseCheck",
"pages/caseReport/caseReport",
"pages/caseDetail/caseDetail",
"pages/process/process",
"pages/waitCheck/waitCheck"
"pages/waitCheck/waitCheck",
"pages/census/census",
"pages/mine/mine",
"pages/censusinput/censusinput",
"pages/chooseArea/chooseArea",
"pages/censusDetail/censusDetail"
],
"window":{
"backgroundTextStyle":"light",
"navigationBarBackgroundColor": "#008cff",
"navigationBarTitleText": "片长制城市管理服务平台",
"navigationBarTextStyle":"white"
"window": {
"backgroundTextStyle": "light",
"navigationBarBackgroundColor": "#4583FE",
"navigationBarTitleText": "包头高新网格化",
"navigationBarTextStyle": "white"
},
"style": "v2",
"sitemapLocation": "sitemap.json",
@ -20,30 +25,27 @@
"desc": "你的位置信息将用于小程序位置接口的效果展示"
}
},
"usingComponents": {
"scroller": "components/coolui-scroller/scroller/index"
},
"tabBar": {
"color": "#000",
"borderStyle": "black",
"selectedColor": "#fff",
"backgroundColor": "#1089f2",
"borderStyle": "white",
"selectedColor": "#4583FE",
"backgroundColor": "#F8F8F8",
"list": [
{
"pagePath": "pages/caseReport/caseReport",
"iconPath": "images/report.png",
"text": "案件上报",
"selectedIconPath": "images/report-on.png"
},
{
"pagePath": "pages/index/index",
"iconPath": "images/history.png",
"text": "上报历史",
"selectedIconPath": "images/history-on.png"
"iconPath": "images/ic_home_nomarl_icon.png",
"text": "首页",
"selectedIconPath": "images/ic_home_sel_icon.png"
},
{
"pagePath": "pages/waitCheck/waitCheck",
"iconPath": "images/check.png",
"text": "待检查",
"selectedIconPath": "images/check-on.png"
"pagePath": "pages/mine/mine",
"iconPath": "images/ic_mine_nomarl_icon.png",
"text": "我的",
"selectedIconPath": "images/ic_mine_sel_icon.png"
}
]
}
}
}

View File

@ -1,10 +1,43 @@
/**app.wxss**/
@import "/styles/iconfont.wxss";
.container {
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
padding: 200rpx 0;
box-sizing: border-box;
}
height: 100%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-between;
padding: 200rpx 0;
box-sizing: border-box;
}
::-webkit-scrollbar {
display: none;
}
.empty-data {
font-size: 16px;
color: #5f5f5f;
text-align: center;
justify-self: center;
align-self: center;
margin-top: 20px;
}
.wx-switch-input {
width: 90rpx !important;
height: 48rpx !important;
}
/* false的样式 */
.wx-switch-input::before {
width: 100rpx !important;
height: 40rpx !important;
}
/* true的样式 */
.wx-switch-input::after {
width: 40rpx !important;
height: 40rpx !important;
}

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 缘℃Style
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,178 @@
# coolui-scroller
<a href="https://www.npmjs.com/package/coolui-scroller"><img src="https://img.shields.io/npm/v/coolui-scroller.svg" alt="Version"></a>&nbsp;
<a href="https://www.npmjs.com/package/coolui-scroller"><img src="https://img.shields.io/npm/l/coolui-scroller.svg" alt="License"></a>&nbsp;
<a href="https://www.npmjs.com/package/coolui-scroller"><img src="https://img.shields.io/npm/dt/coolui-scroller" alt="Download"></a>&nbsp;
<a href="https://github.com/wzs28150/coolui-scroller"><img src="https://img.shields.io/github/stars/wzs28150/coolui-scroller?style=social" alt="Stars"></a>
## 前言
### 初衷
本来写这个组件的初衷,是在我写了一个小程序之后,发现小程序如果要实现下拉刷新、上拉加载有两种方式:
1. 页面级的:利用页面 Page 里提供的方法。下拉虽说是那个东西但是它只有下拉三个点的动画效果而且只能显示在头部就很尴尬。很多时候一个列表的头部往往会有一些组件比如搜索、分类导航等等。所以往往列表都是局部的非页面级的。这时候下拉时动画出现在最顶部就显得很突兀。
```javascript
Page({
onPullDownRefresh: function () {
// 监听用户下拉刷新事件。
},
onReachBottom: function () {
// 监听用户上拉触底事件。
},
onPageScroll: function () {
// 监听用户滑动页面事件。
},
});
```
2. 组件级的:利用 scroll-view。 但是当你打开 scroll-view 官方文档时,映入眼帘的是一列列的参数属性方法。要完全弄懂里面的内容,恐怕你得上手写写,挨个试试里面的参数和方法才行。而对于下拉刷新这个效果文档上有个简易的 demo 可寻。上拉加载也只有 bindscrolltolower 这么个方法和 lower-threshold 阈值。所以要实现起来完全还得靠自己。
所以在写项目的最后我把页面的列表下拉刷新,上拉加载进行了初步的封装。单独拿出来方便之后重复使用。所以有了起初的 1.0 版。
### 发展
#### V2.0
scroll-view 组件初期并没有那么多配置,所以 1.0 实现的效果很有限。
后来随着官方 scroll-view 组件的不断的更新。增加了很多新的属性和事件使得下拉可以自定义起来。虽然也有很多地方不尽人意,但是可玩度还是有很多的。所以又升级了 2.0 版增加了很多下拉的自定义动画效果和上拉加载的效果。
2.0 版组件还是围绕着 scroll-view,写法上只有一个封装好的 scroller 组件。内置了一个基础的下拉效果。提供下拉的插槽位置。并给出了几个有趣的下拉效果 demo(如:天猫效果、京东小人效果)让下拉又有了更多的可能性;配置上也考虑了很多增加了列表为空时的设置上拉加载的配置。整个配置就是一个 Obj,细化到文字、背景。
V2.0 配置:
```js
// data 中配置
scroll: {
// 设置分页信息
pagination: {
page: 1,
totalPage: 10,
limit: 10,
length: 100
},
// 设置数据为空时的图片
empty: {
img: 'http://coolui.coolwl.cn/assets/mescroll-empty.png'
},
// 设置下拉刷新
refresh: {
type: 'default',
style: 'black',
background: "#000"
},
// 设置上拉加载
loadmore: {
type: 'default',
icon: 'http://upload-images.jianshu.io/upload_images/5726812-95bd7570a25bd4ee.gif',
background: '#f2f2f2',
// backgroundImage: 'http://coolui.coolwl.cn/assets/bg.jpg',
title: {
show: true,
text: '加载中',
color: "#999",
shadow: 5
}
}
},
```
之后由于疫情及个人原因这个组件搁置了一阵子。当我再次打开它时便有了重构的想法。
#### V3.0
3.0 版打算把之前各个部分的插槽进行细化及拆分。并新增空列表插槽及组件、初次进入程序时的手势提示组件、顶部插槽及顶部插槽可用的组件(如:搜索组件、分类组件、下拉筛选组件)。
除了组件的变化外,核心列表准备加入长列表处理,解决数据量大时列表会出现的问题(如setData 加载大数据的耗时高、列表渲染出来的 Dom 结构多、占用的内存高,造成页面被系统回收的概率变大等)。起初想以官方给出的 recycle-view 组件进行扩展。但是使用中,遇到很多坑及不方便之处。最让我接受不了的是需要设置 itemSize 这个方法。当我在不确定列表元素宽高的时候就很难设置。后来经过大量的思考和查资料及尝试。决定采用知乎上 daisy 提出的长列表解决方案。
该组件还在开发中各组件陆续上线~
### v3.0 版
1. 基于小程序原生组件 scroll-view 的扩展与封装,实现简单的上拉加载下拉刷新
2. 扩展下拉刷新动画,有灵感的朋友可以丰富更多下拉动画
3. 上传至 npm 包可安装下载并 npm 构建
4. 修改参数配置使组件使用更便捷
5. 增加加载插槽可以自定义加载更多样式
6. 增加多组件配合使列表功能更丰富
### 开发进度
1. ~~调整为虚拟长列表模式~~
2. ~~支持多组件搭配,使插件更灵活~~
3. ~~新增组件 coolui-scroller-item(列表项组件)~~
4. ~~新增组件 coolui-scroller-page(长列表分页组件)~~
5. ~~新增组件 coolui-scroller-empty(空列表组件)~~
6. ~~新增组件 coolui-scroller-handtip(手势提示组件)~~
7. ~~新增组件 coolui-scroller-loadmore(加载更多组件)~~
8. ~~新增组件 coolui-scroller-nav(分类导航组件)~~
9. ~~新增组件 coolui-scroller-refresh(下拉刷新组件)~~
10. ~~新增组件 coolui-scroller-parallax(下拉刷新视差位移组件)~~
11. ~~新增组件 coolui-scroller-search(搜索组件)~~
12. ~~新增组件 coolui-scroller-sort(分类筛选及排序组件)~~
### 支持 coolui-scroller
做一个组件库是一个繁琐且长期的事情,接下来我将花费业余时间进行多版本的完善。
如果 coolui-scroller 对您的工作或者学习有所帮助,您可以捐赠 coolui-scroller 的研发工作,捐赠无门槛,哪怕是一瓶肥宅快乐水,也可以帮助我多敲半小时代码。
| 微信 | 支付宝 |
| ------------------------------------------ | ------ |
| ![微信](https://wzs28150.github.io/coolui-scroller/v3/images/wx.jpg) | ![支付宝](https://wzs28150.github.io/coolui-scroller/v3/images/zfb.jpg) |
## 示例 demo
请微信扫码打开小程序查看
![示例](https://wzs28150.github.io/coolui-scroller/v3/images/demo.jpg)
示例代码: [https://github.com/wzs28150/coolui-scroller/tree/demo](https://github.com/wzs28150/coolui-scroller/tree/demo)
请 clone 下载到本地使用微信开发者工具查看
```
git clone -b demo https://github.com/wzs28150/coolui-scroller.git
```
## 安装
### npm 安装
```
npm i coolui-scroller --production
```
### npm 构建
安装之后开发者工具点击 npm 构建:<br/>
![npm构建1](https://wzs28150.github.io/coolui-scroller/v3/images/set1.png)<br/>
当看到站点里面出现 miniprogram_npm 文件夹就算安装完成了<br/>
![npm构建2](https://wzs28150.github.io/coolui-scroller/v3/images/set2.png)
## 引入
### 1.调用组件
在`app.json`或`index.json`中引入组件
```json
"usingComponents": {
"scroller": "coolui-scroller/scroller/index"
}
```
### 2.页面结构
```html
<scroller class="my-scroller" > </scroller>
```
### 3.配置
在 js 的 data 中进行配置参数设置v3.0 版将功能细化到各个组件中具体配置详见([组件](https://wzs28150.github.io/coolui-scroller/v3/components/scroller.html))
### 4.组件
根据自己的业务场景选用组件,也可以在对应的插槽中自定义

View File

@ -0,0 +1,19 @@
Component({
relations: {
'../scroller/index': {
type: 'parent',
linked() {}
}
},
externalClasses: ['img-class', 'text-class'],
properties: {
emptyImg: {
type: String,
value: ''
},
emptyText: {
type: String,
value: '暂无内容'
}
}
})

View File

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@ -0,0 +1,6 @@
<view class="coolui-scroller-empty">
<view class="coolui-scroller-empty-inner">
<image src="{{emptyImg}}" mode="aspectFill" wx:if="{{emptyImg}}" class="empty-img img-class"></image>
<view class="empty-text text-class">{{emptyText}}</view>
</view>
</view>

View File

@ -0,0 +1,25 @@
/* components/coolui-scroller-item/coolui-scroller-item.wxss */
:host {
display: block;
height: 100%;
}
.coolui-scroller-empty {
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.empty-img{
width: 30vw;
height: 30vw;
display: block;
margin: 0 auto;
}
.empty-text{
text-align: center;
font-size: 28rpx;
color: #999;
margin: 50rpx auto;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@ -0,0 +1,55 @@
Component({
properties: {
top: {
type: String,
value: 0
},
bottom: {
type: String,
value: 0
},
left: {
type: String,
value: 0
},
right: {
type: String,
value: 0
},
key: {
type: String,
value: 'isTipShow'
},
opacity: {
type: Number,
value: 0.5
}
},
data: {
isTipShow: true
},
methods: {
close: function () {
try {
wx.setStorageSync(this.data.key, 'true')
this.setData({
isTipShow: true
})
} catch (e) {
}
}
},
ready() {
try {
var isKey = wx.getStorageSync(this.data.key)
if (!isKey) {
this.setData({
isTipShow: false
})
}
} catch (e) {
console.log(1);
}
}
})

View File

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@ -0,0 +1,39 @@
<view class="hand" style="background-color: rgba(0, 0, 0, {{opacity}});" hidden="{{isTipShow}}" >
<image src="./icons/close.png" mode="aspectFill" class="close" bindtap="close"></image>
<view class="top" wx:if="{{top}}">
<view>{{top}}</view>
<view class="">
<image src="./icons/tap3.png" mode="aspectFill" class="tap"></image>
</view>
<view class="arrow_down">
<image src="./icons/arrow_down.png" mode="aspectFill" class="arrow"></image>
</view>
</view>
<view class="bottom" wx:if="{{bottom}}">
<view class="arrow_top">
<image src="./icons/arrow_top.png" mode="aspectFill" class="arrow"></image>
</view>
<view class="">
<image src="./icons/tap.png" mode="aspectFill" class="tap"></image>
</view>
<view>{{bottom}}</view>
</view>
<view class="left" wx:if="{{left}}">
<view class="">
<image src="./icons/arrow_right.png" mode="aspectFill" class="arrow"></image>
</view>
<view class="">
<image src="./icons/tap.png" mode="aspectFill" class="tap"></image>
</view>
<view>{{left}}</view>
</view>
<view class="right" wx:if="{{right}}">
<view>
<image src="./icons/arrow_left.png" mode="aspectFill" class="arrow"></image>
</view>
<view>
<image src="./icons/tap2.png" mode="aspectFill" class="tap"></image>
</view>
<view>{{right}}</view>
</view>
</view>

View File

@ -0,0 +1,154 @@
.hand {
position: fixed;
width: 100vw;
height: 100vh;
left: 0;
top: 0;
z-index: 90;
background-color: rgba(0, 0, 0, 0.5);
font-size: 28rpx;
}
.hand .close {
position: absolute;
right: 15px;
top: 15px;
width: 80rpx;
height: 80rpx;
}
.hand .tap {
width: 90rpx;
height: 131rpx;
}
.hand .top {
position: absolute;
top: 15px;
left: 50%;
transform: translateX(-50%);
color: #fff;
text-align: center;
}
.hand .top .arrow {
width: 22rpx;
height: 50rpx;
transform: translateX(50rpx);
}
.hand .top .tap {
animation: movetop 3s infinite;
}
.hand .bottom {
position: absolute;
bottom: 15px;
left: 50%;
transform: translateX(-50%);
color: #fff;
text-align: center;
}
.hand .bottom .arrow {
width: 22rpx;
height: 50rpx;
transform: translateX(-50rpx);
}
.hand .bottom .tap {
animation: movebottom 3s infinite;
}
.hand .left {
position: absolute;
left: 15px;
top: 50%;
transform: translateY(-50%);
color: #fff;
text-align: left;
}
.hand .left .arrow {
width: 50rpx;
height: 22rpx;
display: block;
}
.hand .left .tap {
animation: moveleft 3s infinite;
}
.hand .right {
position: absolute;
right: 15px;
top: 50%;
transform: translateY(-50%);
color: #fff;
text-align: right;
}
.hand .right .arrow {
width: 50rpx;
height: 22rpx;
}
.hand .right .tap {
animation: moveright 3s infinite;
}
@keyframes moveleft {
0% {
transform: translateX(0);
}
50% {
transform: translateX(80rpx);
}
100% {
transform: translateX(0);
}
}
@keyframes moveright {
0% {
transform: translateX(0);
}
50% {
transform: translateX(-80rpx);
}
100% {
transform: translateX(0);
}
}
@keyframes movetop {
0% {
transform: translateY(0);
}
50% {
transform: translateY(80rpx);
}
100% {
transform: translateY(0);
}
}
@keyframes movebottom {
0% {
transform: translateY(0);
}
50% {
transform: translateY(-80rpx);
}
100% {
transform: translateY(0);
}
}

View File

@ -0,0 +1,53 @@
/**
* coolui-scroller组件的api使用
* 提供wx.createScrollContext进行管理功能
*/
function observePage(pageIndex, that) {
wx.getSystemInfoAsync({
success: (res) => {
const { windowHeight } = res
// this.windowHeight = windowHeight
const observerObj = wx
.createIntersectionObserver(that)
.relativeToViewport({
top: 2 * windowHeight,
bottom: 2 * windowHeight,
})
observerObj.observe(`#wrp_${pageIndex}`, (res) => {
if (res.intersectionRatio <= 0) {
try {
that.setData({
['list[' + pageIndex + ']']: [
{
height: that.pageHeightArr[pageIndex],
},
],
})
} catch (error) {
console.log(error)
}
} else {
try {
that.setData({
['list[' + pageIndex + ']']: that.wholeList[pageIndex],
})
} catch (error) {
console.log(error)
}
}
})
},
})
}
function setHeight(that) {
const page = that.param.page
this.query = wx.createSelectorQuery()
this.query.select(`#wrp_${page}`).boundingClientRect()
this.query.exec(function (res) {
that.pageHeightArr[page] = res[0] && res[0].height
})
observePage(page, that)
}
module.exports.setHeight = setHeight

View File

@ -0,0 +1,33 @@
Component({
relations: {
"../scroller/index": {
type: "parent",
linked() {},
},
},
properties: {
ripple: {
type: Boolean,
value: false
},
},
data: {
rippleStyle: "",
},
methods: {
itemTap(e) {
if (this.data.ripple) {
var x = e.changedTouches[0].pageX;
var y = e.currentTarget.offsetTop;
this.setData({
rippleStyle: "left:" + x + "px;animation: ripple 0.5s linear;",
});
setTimeout((res) => {
this.setData({
rippleStyle: "",
});
}, 500);
}
},
},
});

View File

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@ -0,0 +1,4 @@
<view class="wx-coolui-scroller-item" bind:touchstart="itemTap">
<slot></slot>
<view class="ripple" style="{{rippleStyle}}"></view>
</view>

View File

@ -0,0 +1,25 @@
:host {
display: block;
}
.wx-coolui-scroller-item {
height: 100%;
position: relative;
overflow: hidden;
}
.ripple {
background-color: rgba(0,0,0, 0.2);
border-radius: 100%;
height:10px;
width:10px;
position: absolute;
transform: scale(0);
top: 50%;
}
@keyframes ripple {
100% {
transform: scale(80);
transform: scale(80);
background-color: transparent;
}
}

View File

@ -0,0 +1,49 @@
Component({
options: {
addGlobalClass: true,
},
relations: {
"../scroller/index": {
type: "parent"
},
},
properties: {
noMoreTextStyle: {
type: String,
value: "",
},
status: {
type: String,
value: "more",
},
loading: {
type: Object,
value: {
text: "\u52A0\u8F7D\u4E2D",
color: "#999999"
}
},
more: {
type: Object,
value: {
text: "\u67E5\u770B\u66F4\u591A",
color: "#333333"
}
},
noMore: {
type: Object,
value: {
text: "\u6CA1\u6709\u66F4\u591A",
color: "#999999"
},
},
color: {
type: String,
value: "#999999",
},
shake: {
type: Boolean,
value: false,
},
}
});

View File

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@ -0,0 +1,96 @@
:host {
display: block;
}
@keyframes loading {
0% {
-webkit-transform: rotate(0deg);
transform : rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
transform : rotate(360deg);
}
}
.coolui-scroller-loadmore {
width : 100%;
height : 100rpx;
font-size : 28rpx;
display : flex;
justify-content: center;
align-items : center;
.cool-indicator {
display : -webkit-flex;
display : -ms-flexbox;
display : flex;
line-height : 1;
visibility : hidden;
opacity : 0;
-webkit-transition: all 0.3s cubic-bezier(0.55, 0.085, 0.68, 0.53);
-o-transition : all 0.3s cubic-bezier(0.55, 0.085, 0.68, 0.53);
transition : all 0.3s cubic-bezier(0.55, 0.085, 0.68, 0.53);
&.cool-indicator--isopened {
opacity : 1;
visibility: initial;
}
}
.cool-indicator__body,
.cool-indicator__content {
-webkit-flex : 0 0 auto;
-ms-flex : 0 0 auto;
flex : 0 0 auto;
-webkit-box-flex: 0;
}
.at-indicator__content {
-webkit-align-self : center;
-ms-flex-item-align: center;
align-self : center;
margin-left : 24rpx;
color : #999;
font-size : 28rpx;
}
.cool-loading,
.cool-loading__ring {
display : inline-block;
position: relative;
width : 36rpx;
height : 36rpx;
}
.cool-loading__ring {
-webkit-box-sizing: border-box;
box-sizing : border-box;
display : block;
position : absolute;
margin : 2px;
border-width : 2px;
border-style : solid;
border-color : #6190e8 transparent transparent;
border-radius : 50%;
-webkit-animation : loading 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
animation : loading 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
&:nth-child(1) {
-webkit-animation-delay: -.45s;
animation-delay : -0.45s;
}
&:nth-child(2) {
-webkit-animation-delay: -.3s;
animation-delay : -0.3s;
}
&:nth-child(3) {
-webkit-animation-delay: -.15s;
animation-delay : -0.15s;
}
}
}

View File

@ -0,0 +1,16 @@
<view class="coolui-scroller-loadmore">
<block wx:if="{{status === 'more'}}" style="color: {{more.color}}">{{more.text}}</block>
<block wx:elif="{{status === 'loading'}}">
<view class="cool-indicator cool-indicator--isopened">
<view class="cool-indicator__body">
<view class="cool-loading">
<view class="cool-loading__ring" style="border-color:{{loading.color}} transparent transparent;"></view>
<view class="cool-loading__ring" style="border-color:{{loading.color}} transparent transparent;"></view>
<view class="cool-loading__ring" style="border-color:{{loading.color}} transparent transparent;"></view>
</view>
</view>
</view>
<text class="at-indicator__content" style="color: {{loading.color}}">{{loading.text}}</text>
</block>
<block wx:elif="{{status === 'noMore'}}" style="color: {{noMore.color}}">{{noMore.text}}</block>
</view>

View File

@ -0,0 +1,94 @@
:host {
display: block;
}
@keyframes loading {
0% {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
}
.coolui-scroller-loadmore {
width: 100%;
height: 100rpx;
font-size: 28rpx;
display: flex;
justify-content: center;
align-items: center;
}
.coolui-scroller-loadmore .cool-indicator {
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
line-height: 1;
visibility: hidden;
opacity: 0;
-webkit-transition: all 0.3s cubic-bezier(0.55, 0.085, 0.68, 0.53);
-o-transition: all 0.3s cubic-bezier(0.55, 0.085, 0.68, 0.53);
transition: all 0.3s cubic-bezier(0.55, 0.085, 0.68, 0.53);
}
.coolui-scroller-loadmore .cool-indicator.cool-indicator--isopened {
opacity: 1;
visibility: initial;
}
.coolui-scroller-loadmore .cool-indicator__body,
.coolui-scroller-loadmore .cool-indicator__content {
-webkit-flex: 0 0 auto;
-ms-flex: 0 0 auto;
flex: 0 0 auto;
-webkit-box-flex: 0;
}
.coolui-scroller-loadmore .at-indicator__content {
-webkit-align-self: center;
-ms-flex-item-align: center;
align-self: center;
margin-left: 24rpx;
color: #999;
font-size: 28rpx;
}
.coolui-scroller-loadmore .cool-loading,
.coolui-scroller-loadmore .cool-loading__ring {
display: inline-block;
position: relative;
width: 36rpx;
height: 36rpx;
}
.coolui-scroller-loadmore .cool-loading__ring {
-webkit-box-sizing: border-box;
box-sizing: border-box;
display: block;
position: absolute;
margin: 2px;
border-width: 2px;
border-style: solid;
border-color: #6190e8 transparent transparent;
border-radius: 50%;
-webkit-animation: loading 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
animation: loading 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
}
.coolui-scroller-loadmore .cool-loading__ring:nth-child(1) {
-webkit-animation-delay: -.45s;
animation-delay: -0.45s;
}
.coolui-scroller-loadmore .cool-loading__ring:nth-child(2) {
-webkit-animation-delay: -.3s;
animation-delay: -0.3s;
}
.coolui-scroller-loadmore .cool-loading__ring:nth-child(3) {
-webkit-animation-delay: -.15s;
animation-delay: -0.15s;
}

View File

@ -0,0 +1,80 @@
// pages/second-floor/circle/index.js
Component({
externalClasses: ['nav-bar-class'],
relations: {
'../second-floor/index': {
type: 'parent',
linked(target) {
this.setData({
target,
})
},
},
},
properties: {
type: {
type: String,
value: 'default',
},
config: {
type: Object,
value: {
back: {
show: true,
},
background: {
color: '#ffffff',
},
text: {
color: '#000000',
shadow: 0,
},
},
},
},
/**
* 组件的初始数据
*/
data: {
StatusBar: null,
statusBarHeight: 0,
Custom: null,
},
/**
* 组件的方法列表
*/
methods: {
BackPage() {
if (this.data.config.back.click) {
this.data.config.back.click()
} else {
wx.navigateBack({
delta: 1,
})
}
},
},
ready() {
const that = this
wx.getSystemInfoAsync({
success: (e) => {
that.setData({
StatusBar: e.statusBarHeight,
})
let capsule = wx.getMenuButtonBoundingClientRect()
if (capsule) {
that.setData({
Custom: capsule,
statusBarHeight: capsule.bottom + capsule.top - e.statusBarHeight,
})
} else {
that.setData({
statusBarHeight: e.statusBarHeight + 50,
})
}
},
})
},
})

View File

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@ -0,0 +1,43 @@
.nav-bar {
position: relative;
.nav-bar-inner {
display : flex;
align-items: center;
box-sizing : border-box;
position : relative;
}
.action {
position : absolute;
width : 40rpx;
height : 40rpx;
margin-left: 24rpx;
.line {
width : 24rpx;
height : 4rpx;
background-color : #fff;
position : absolute;
left : 50%;
top : 50%;
transform-origin : 0 center;
// border-radius : 0 50px 50px 0;
margin-top : 0rpx;
transform : translate(-40%, -50%) rotate(45deg);
&+.line {
margin-top: 0.5rpx;
transform : translate(-40%, -50%) rotate(-45deg);
}
}
}
.content {
text-align: center;
width : 100%;
font-size : 34rpx;
}
}

View File

@ -0,0 +1,18 @@
<!-- pages/second-floor/circle/index.wxml -->
<!-- <text>{{p}}</text> -->
<view class="nav-bar" style="height:{{statusBarHeight}}px;background-color:{{config.background.color}}">
<view class="nav-bar-inner" style="height:{{statusBarHeight}}px;padding-top:{{StatusBar}}px;{{config.background.img?'background-image:url(' + config.background.img+')':''}}">
<block wx:if="{{type === 'default'}}">
<view class="action" bindtap="BackPage" wx:if="{{config.back}}">
<view class="line" style="background-color:{{config.text.color}}"></view>
<view class="line" style="background-color:{{config.text.color}}"></view>
</view>
<view class="content" style="top:{{StatusBar}}px; color: {{config.text.color}}">
<slot />
</view>
</block>
<block wx:else>
<slot />
</block>
</view>
</view>

View File

@ -0,0 +1,40 @@
.nav-bar {
position: relative;
}
.nav-bar .nav-bar-inner {
display: flex;
align-items: center;
box-sizing: border-box;
position: relative;
}
.nav-bar .action {
position: absolute;
width: 40rpx;
height: 40rpx;
margin-left: 24rpx;
}
.nav-bar .action .line {
width: 24rpx;
height: 4rpx;
background-color: #fff;
position: absolute;
left: 50%;
top: 50%;
transform-origin: 0 center;
margin-top: 0rpx;
transform: translate(-40%, -50%) rotate(45deg);
}
.nav-bar .action .line + .line {
margin-top: 0.5rpx;
transform: translate(-40%, -50%) rotate(-45deg);
}
.nav-bar .content {
text-align: center;
width: 100%;
font-size: 34rpx;
}

View File

@ -0,0 +1,78 @@
// miniprogram_npm/coolui-scroller/nav-pannel/index.js
Component({
options: {
multipleSlots: true,
addGlobalClass: true,
},
relations: {
'../scroller/index': {
type: 'child',
linked: function (target) {
// console.log(target)
},
},
},
properties: {
active: {
type: Number,
value: 0,
},
animation: {
type: Boolean,
value: false,
},
type: {
type: String,
value: 'side',
},
},
observers: {
active: function (val) {
// console.log(val)
// this.scrollNodes =
// this.scrollNodes ?? this.getRelationNodes('../scroller/index')
// if (this.scrollNodes[val]) {
// console.log(this.scrollNodes[val])
// }
},
},
data: {
width: 0,
height: 0,
scrollerLength: 0,
},
lifetimes: {
attached: function () {
// 计算宽高
let that = this
wx.createSelectorQuery()
.in(this)
.select('.wx-coolui-nav-pannel')
.boundingClientRect()
.exec(function (res) {
if (res.length > 0 && res[0]) {
that.setData({
width: res[0].width,
height: res[0].height,
})
}
})
},
detached: function () {
// 在组件实例被从页面节点树移除时执行
},
},
ready() {
this.init()
},
methods: {
init() {
// 计算子元素个数
let that = this
this.scrollNodes = this.getRelationNodes('../scroller/index')
that.setData({
scrollerLength: that.scrollNodes.length,
})
},
},
})

View File

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@ -0,0 +1,48 @@
:host {
display: block;
width : 100%;
height : 100%;
}
$active: var(--active);
.wx-coolui-nav-pannel {
height : 100%;
overflow: hidden;
// flex : 1;
&-inner {
height: 100%;
&.side {
display : flex;
transform: translateX(var(--left));
scroller {
flex: 1;
}
}
&.fade {
position: relative;
scroller {
position: absolute;
width : 100%;
height : 100%;
left : 0;
top : 0;
z-index : 0;
&:first-child {
position: relative;
z-index : 1;
}
}
}
}
}

View File

@ -0,0 +1,5 @@
<view class="wx-coolui-nav-pannel">
<view class="wx-coolui-nav-pannel-inner {{type}}" style="width:{{type === 'side' ? width * scrollerLength : width}}px;--left:{{-width * active}}px; {{animation?'transition: transform 0.4s;':''}}--active:{{active}}">
<slot />
</view>
</view>

View File

@ -0,0 +1,41 @@
:host {
display: block;
width: 100%;
height: 100%;
}
.wx-coolui-nav-pannel {
height: 100%;
overflow: hidden;
}
.wx-coolui-nav-pannel-inner {
height: 100%;
}
.wx-coolui-nav-pannel-inner.side {
display: flex;
transform: translateX(var(--left));
}
.wx-coolui-nav-pannel-inner.side scroller {
flex: 1;
}
.wx-coolui-nav-pannel-inner.fade {
position: relative;
}
.wx-coolui-nav-pannel-inner.fade scroller {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
z-index: 0;
}
.wx-coolui-nav-pannel-inner.fade scroller:first-child {
position: relative;
z-index: 1;
}

View File

@ -0,0 +1,116 @@
Component({
relations: {
'../scroller/index': {
type: 'parent',
linked() {},
},
},
/**
* 组件的属性列表
*/
properties: {
list: Array,
border: {
type: Boolean,
value: true,
},
text: {
type: Object,
value: {
color: '#333333',
activeColor: '#d13435',
},
},
background: {
type: Object,
value: {
color: '#333333',
activeColor: '#d13435',
},
},
navPerView: {
type: [Number, String],
value: 4.5,
observer: function (newVal) {
this._changeNavPerView(newVal)
},
},
spaceBetween: {
type: Number,
value: 0,
},
type: {
type: String,
value: 'line', //可选 line,roundplain
},
active: {
type: Number,
value: 0,
observer: function (newVal) {
this.setData({
toView: 'item' + (newVal - 1),
})
// console.log(this);
this._change(newVal)
},
},
},
data: {
toView: 'item0',
navWidth: 0,
scroll: false,
index: 0,
},
lifetimes: {
attached: function () {
// 在组件实例进入页面节点树时执行
let that = this
that._changeNavPerView(that.data.navPerView)
},
detached: function () {
// 在组件实例被从页面节点树移除时执行
},
},
pageLifetimes: {
// 组件所在页面的生命周期函数
show: function () {},
hide: function () {},
resize: function () {},
},
methods: {
_changeNav(e) {
this.setData({
active: e.currentTarget.dataset.index,
})
},
_change(index) {
this.triggerEvent('change', {
id: this.data.list[index].id,
})
},
_catchTouchMove() {
return false
},
_changeNavPerView(navPerView) {
let that = this
wx.createSelectorQuery()
.in(this)
.select('.wx-coolui-nav')
.boundingClientRect()
.exec(function (res) {
// console.log(res)
if (res.length > 0 && res[0]) {
// console.log(that.data.navPerView)
that.setData({
navWidth:
navPerView === 'auto'
? 'auto'
: (res[0].width - that.data.spaceBetween * (navPerView - 1)) /
navPerView +
'px',
})
}
})
},
},
})

View File

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@ -0,0 +1,112 @@
.wx-coolui-nav {
border-bottom: 1px solid transparent;
height : 83rpx;
&.border {
border-bottom: 1px solid #eee;
}
.nav-inner {
white-space: nowrap;
.item {
display : inline-block;
text-align : center;
height : 84rpx;
font-size : 0;
line-height: 0;
color : #333;
transition : color 0.4s;
.text {
position : relative;
display : inline-block;
line-height: 84rpx;
font-size : 28rpx;
width : 100%;
&>view:first-child {
position : relative;
z-index : 1;
overflow : hidden;
text-overflow: ellipsis;
white-space : nowrap;
}
}
&.round {
.text {
padding: 0 20px;
width : calc(100% - 40px);
}
.line {
display : block;
position : absolute;
left : 50%;
transform : translateX(-50%) translateY(50%);
bottom : 50%;
width : 100%;
height : 60%;
background-color: #ccc;
transition : width 0.4s;
border-radius : 50px;
z-index : 0;
}
}
&.plain {
.text {
padding: 0 20px;
width : calc(100% - 40px);
}
.line {
display : block;
position : absolute;
left : 50%;
transform : translateX(-50%) translateY(50%);
bottom : 50%;
width : calc(100% - 2px);
height : 60%;
background-color: transparent !important;
border : 1px solid #ccc;
transition : width 0.4s;
border-radius : 50px;
z-index : 0;
}
}
&.line {
.text {
.line {
display : block;
position : absolute;
left : 50%;
transform : translateX(-50%);
bottom : 0;
width : 0;
height : 4rpx;
background-color: transparent;
transition : width 0.4s;
}
}
&.on {
color: #0cba70;
.text {
.line {
width : 100%;
// transition: width 0.4s;
}
}
}
}
}
}
}

View File

@ -0,0 +1,10 @@
<view class="wx-coolui-nav {{border ? 'border' : ''}}">
<scroll-view scroll-x scroll-with-animation enhanced show-scrollbar="{{false}}" scroll-animation-duration="{{500}}" scroll-into-view="{{toView}}" class="nav-inner">
<view class="item {{type}} {{active == index?'on':'' }}" style="width: {{navWidth}}; margin-right: {{index == list.length - 1 ? 0 : spaceBetween}}px; {{active == index?'color:'+text.activeColor:'color:' + text.color}}" id="item{{index}}" wx:for="{{list}}" data-index="{{index}}" bind:tap="_changeNav" wx:key="id" catchtouchmove='_catchTouchMove'>
<view class="text">
<view>{{item.title}}</view>
<view class="line" style="{{active == index?'background-color:'+background.activeColor:'background-color:' + (type === 'line' ?'transparent' : background.color)}};{{type === 'plain' ? (active == index ? ('border-color:' + background.activeColor): ('border-color:' + background.color)): ''}}"></view>
</view>
</view>
</scroll-view>
</view>

View File

@ -0,0 +1,97 @@
.wx-coolui-nav {
border-bottom: 1px solid transparent;
height: 83rpx;
}
.wx-coolui-nav.border {
border-bottom: 1px solid #eee;
}
.wx-coolui-nav .nav-inner {
white-space: nowrap;
}
.wx-coolui-nav .nav-inner .item {
display: inline-block;
text-align: center;
height: 84rpx;
font-size: 0;
line-height: 0;
color: #333;
transition: color 0.4s;
}
.wx-coolui-nav .nav-inner .item .text {
position: relative;
display: inline-block;
line-height: 84rpx;
font-size: 28rpx;
width: 100%;
}
.wx-coolui-nav .nav-inner .item .text > view:first-child {
position: relative;
z-index: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.wx-coolui-nav .nav-inner .item.round .text {
padding: 0 20px;
width: calc(100% - 40px);
}
.wx-coolui-nav .nav-inner .item.round .line {
display: block;
position: absolute;
left: 50%;
transform: translateX(-50%) translateY(50%);
bottom: 50%;
width: 100%;
height: 60%;
background-color: #ccc;
transition: width 0.4s;
border-radius: 50px;
z-index: 0;
}
.wx-coolui-nav .nav-inner .item.plain .text {
padding: 0 20px;
width: calc(100% - 40px);
}
.wx-coolui-nav .nav-inner .item.plain .line {
display: block;
position: absolute;
left: 50%;
transform: translateX(-50%) translateY(50%);
bottom: 50%;
width: calc(100% - 2px);
height: 60%;
background-color: transparent !important;
border: 1px solid #ccc;
transition: width 0.4s;
border-radius: 50px;
z-index: 0;
}
.wx-coolui-nav .nav-inner .item.line .text .line {
display: block;
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 0;
width: 0;
height: 4rpx;
background-color: transparent;
transition: width 0.4s;
}
.wx-coolui-nav .nav-inner .item.line.on {
color: #0cba70;
}
.wx-coolui-nav .nav-inner .item.line.on .text .line {
width: 100%;
}

View File

@ -0,0 +1,31 @@
{
"name": "coolui-scroller",
"version": "3.3.2",
"description": "微信小程序Scroll 上拉加载下拉刷新组件 ",
"main": "./index.js",
"scripts": {
"push": "npm publish",
"build-doc": "cd ../doc && pnpm docs:build",
"prepublish": "pnpm build-doc"
},
"repository": {
"type": "git",
"url": "git@github.com:wzs28150/coolui-scroller.git"
},
"publishConfig": {
"@wzs28150:registry": "https://npm.pkg.github.com"
},
"keywords": [
"weapp",
"scroller",
"pull-to-refresh",
"push-to-loadmore"
],
"miniprogram": "./",
"author": "wzs",
"license": "MIT",
"bugs": {
"url": "https://github.com/wzs28150/coolui-scroller/issues"
},
"homepage": "https://github.com/wzs28150/coolui-scroller#readme"
}

View File

@ -0,0 +1,32 @@
Component({
options: {
multipleSlots: true,
addGlobalClass: true
},
externalClasses: ['parallax-class'],
relations: {
'../refresh/index': {
type: 'parent',
linked(target) {
this.setData({
...target.data
})
}
}
},
properties: {
parallax: {
type: Number,
value: 0
},
direction: {
type: String,
value: 'to bottom'
}
},
data: {
threshold: 0,
triggered: true,
config: {}
}
})

View File

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@ -0,0 +1,5 @@
.wx-coolui-scroller-parallax {
position : absolute;
transform : translate3d(0, 0, 0);
transition: all 0.01s;
}

View File

@ -0,0 +1,20 @@
<block wx:if="{{direction == 'to top'}}">
<view class="wx-coolui-scroller-parallax parallax-class" style="transform: translate3d(0, {{-(parallax * threshold * config.height / 100)}}px, 0); ">
<slot></slot>
</view>
</block>
<block wx:if="{{direction == 'to bottom'}}">
<view class="wx-coolui-scroller-parallax parallax-class" style="transform: translate3d(0, {{(parallax * threshold * config.height / 100)}}px, 0);">
<slot></slot>
</view>
</block>
<block wx:if="{{direction == 'to left'}}">
<view class="wx-coolui-scroller-parallax parallax-class" style="transform: translate3d({{-(parallax * threshold * config.height / 100)}}px, 0, 0);">
<slot></slot>
</view>
</block>
<block wx:if="{{direction == 'to right'}}">
<view class="wx-coolui-scroller-parallax parallax-class" style="transform: translate3d({{(parallax * threshold * config.height / 100)}}px, 0, 0); ">
<slot></slot>
</view>
</block>

View File

@ -0,0 +1,5 @@
.wx-coolui-scroller-parallax {
position: absolute;
transform: translate3d(0, 0, 0);
transition: all 0.01s;
}

View File

@ -0,0 +1,110 @@
Component({
options: {
multipleSlots: true,
addGlobalClass: true,
},
externalClasses: ['refresh-class'],
relations: {
'../scroller/index': {
type: 'parent',
linked(target) {},
},
'../parallax/index': {
type: 'child',
linked(target) {
// console.log(target);
},
},
},
properties: {
type: {
type: String,
value: 'default',
},
threshold: {
type: Number,
value: 0,
},
isloading: {
type: Boolean,
value: false,
},
refreshstate: {
type: String,
value: 'pulldown', // pulldown loosen loading
},
config: {
type: Object,
value: {
shake: false,
height: 50,
isAutoTriggered: true,
text: {
color: '#000000', // 文字颜色
shadow: 0, // 是否开启shadow阴影,0为不开启,数值越大阴影范围越大
},
},
},
},
data: {
triggered: false,
textWidth: null,
scrollOption: {},
},
ready() {
this.parallaxNodes = this.getRelationNodes('../parallax/index')
let that = this
wx.createSelectorQuery()
.in(this)
.select('.has-bg')
.boundingClientRect()
.exec(function (res) {
if (res.length > 0 && res[0]) {
that.setData({
textWidth: res[0].width,
})
}
})
},
methods: {
changeThreshold({ threshold }) {
const that = this
return new Promise((resolve) => {
let refreshstate = 'pulldown'
if (that.data.triggered && !that.data.isloading) {
refreshstate = 'loosen'
}
that.setData(
{
threshold: threshold,
refreshstate: refreshstate,
},
() => {
resolve()
if (that.parallaxNodes.length > 0) {
that.parallaxNodes.forEach((elem, index) => {
elem.setData({
threshold: threshold,
})
})
}
}
)
})
},
setLoading({ isloading }) {
const that = this
return new Promise((resolve) => {
that.setData(
{
isloading: isloading,
refreshstate: isloading ? 'loading' : 'pulldown',
},
() => {
resolve()
}
)
})
},
},
})

View File

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@ -0,0 +1,148 @@
.wx-coolui-scroller-refresh {
width : 100%;
background-size : cover;
background-position: center bottom;
background-repeat : no-repeat;
position : relative;
overflow : hidden;
.refresh-inner {
position : absolute;
text-align : center;
width : 100%;
font-size : 28rpx;
display : flex;
justify-content: center;
align-items : center;
.down {
width : 12px;
height : 12px;
margin-right : 20rpx;
// background-color: #000;
position : relative;
.line {
&:nth-child(1) {
display : block;
width : 2px;
height : 18px;
background-color: #000;
position : absolute;
top : 50%;
left : 50%;
transform : translate(-50%, -50%);
border-radius : 2px;
opacity : 1;
}
&:nth-child(2) {
width : 8px;
height : 2px;
background-color: #000;
display : block;
position : absolute;
bottom : -3px;
left : 50%;
transform : rotate(-45deg);
transform-origin: 0 50%;
border-radius : 2px;
opacity : 1;
}
&:nth-child(3) {
width : 8px;
height : 2px;
background-color: #000;
display : block;
position : absolute;
bottom : -3px;
right : 50%;
transform : rotate(45deg);
transform-origin: 100% 50%;
border-radius : 2px;
opacity : 1;
}
}
&.loading {
display : inline-block;
position: relative;
width : 36rpx;
height : 36rpx;
.line {
-webkit-box-sizing: border-box;
box-sizing : border-box;
display : block;
position : absolute;
margin : -18rpx 2px 2px -18rpx;
border-width : 2px;
border-style : solid;
border-color : #6190e8 transparent transparent;
border-radius : 50%;
-webkit-animation : circle 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
animation : circle 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
width : 36rpx;
height : 36rpx;
left : 50%;
top : 50%;
transform-origin : 50% 50%;
background-color : transparent;
transform : translate(-50%, -50%);
&:nth-child(1) {
-webkit-animation-delay: -.45s;
animation-delay : -0.45s;
}
&:nth-child(2) {
-webkit-animation-delay: -.3s;
animation-delay : -0.3s;
}
&:nth-child(3) {
-webkit-animation-delay: -.15s;
animation-delay : -0.15s;
}
}
}
}
.has-bg {
font-weight : bold;
background-clip : text;
-webkit-background-clip : text;
color : transparent !important;
background-size : 100% auto;
// transition : all .4s;
background-position : -100% -100%;
background-repeat : no-repeat;
&.loading {
animation: play 0.5s line infinite;
}
}
@keyframes circle {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
@keyframes play {
from {
opacity: 1;
}
to {
opacity: 0.5;
}
}
}
}

View File

@ -0,0 +1,19 @@
<view class="wx-coolui-scroller-refresh refresh-class" style="height:{{config.height}}px;{{config.background.img?'background-image:url('+config.background.img+');':''}}padding-top:{{config.background.height? config.background.height - config.height : 0}}px;">
<view class="refresh-inner" wx:if="{{type == 'base'}}" style="height:{{config.height}}px;color:{{config.text.color}};{{config.text.shadow?'text-shadow:0 0 '+config.text.shadow+'rpx '+config.text.color+' outset;':''}}">
<view class="down {{triggered && isloading?'loading':''}}" style="transform: rotate({{threshold*180}}deg);">
<view class="line" style="border-color:{{config.text.color}} transparent transparent;{{triggered && isloading?'background-color:transparent':'background-color:' + config.text.color}}"></view>
<view class="line" style="border-color:{{config.text.color}} transparent transparent;{{triggered && isloading?'background-color:transparent':'background-color:' + config.text.color}}"></view>
<view class="line" style="border-color:{{config.text.color}} transparent transparent;{{triggered && isloading?'background-color:transparent':'background-color:' + config.text.color}}"></view>
</view>
<block wx:if="{{refreshstate == 'pulldown'}}">下拉刷新</block>
<block wx:elif="{{refreshstate == 'loosen'}}">松手刷新</block>
<block wx:elif="{{refreshstate == 'loading'}}">刷新中...</block>
</view>
<view class="refresh-inner" wx:if="{{type == 'logoText'}}">
<text class="{{config.text.img ? 'has-bg' : ''}} {{triggered && isloading?'loading':''}}" style="font-size: {{config.text.size}}rpx; line-height: {{config.text.size}}rpx; color: {{config.text.color}}; background-image: url('{{config.text.img}}');background-position: {{( -textWidth + threshold*textWidth)}}px center;{{config.text.shadow?'text-shadow:0 0 '+config.text.shadow+'rpx '+config.text.color+' outset;':''}} {{config.text.font?('font-family:' + config.text.font): ''}}">
{{config.text.content}}
</text>
</view>
<slot name="parallax" />
<slot />
</view>

View File

@ -0,0 +1,141 @@
.wx-coolui-scroller-refresh {
width: 100%;
background-size: cover;
background-position: center bottom;
background-repeat: no-repeat;
position: relative;
overflow: hidden;
}
.wx-coolui-scroller-refresh .refresh-inner {
position: absolute;
text-align: center;
width: 100%;
font-size: 28rpx;
display: flex;
justify-content: center;
align-items: center;
}
.wx-coolui-scroller-refresh .refresh-inner .down {
width: 12px;
height: 12px;
margin-right: 20rpx;
position: relative;
}
.wx-coolui-scroller-refresh .refresh-inner .down .line:nth-child(1) {
display: block;
width: 2px;
height: 18px;
background-color: #000;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 2px;
opacity: 1;
}
.wx-coolui-scroller-refresh .refresh-inner .down .line:nth-child(2) {
width: 8px;
height: 2px;
background-color: #000;
display: block;
position: absolute;
bottom: -3px;
left: 50%;
transform: rotate(-45deg);
transform-origin: 0 50%;
border-radius: 2px;
opacity: 1;
}
.wx-coolui-scroller-refresh .refresh-inner .down .line:nth-child(3) {
width: 8px;
height: 2px;
background-color: #000;
display: block;
position: absolute;
bottom: -3px;
right: 50%;
transform: rotate(45deg);
transform-origin: 100% 50%;
border-radius: 2px;
opacity: 1;
}
.wx-coolui-scroller-refresh .refresh-inner .down.loading {
display: inline-block;
position: relative;
width: 36rpx;
height: 36rpx;
}
.wx-coolui-scroller-refresh .refresh-inner .down.loading .line {
-webkit-box-sizing: border-box;
box-sizing: border-box;
display: block;
position: absolute;
margin: -18rpx 2px 2px -18rpx;
border-width: 2px;
border-style: solid;
border-color: #6190e8 transparent transparent;
border-radius: 50%;
-webkit-animation: circle 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
animation: circle 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
width: 36rpx;
height: 36rpx;
left: 50%;
top: 50%;
transform-origin: 50% 50%;
background-color: transparent;
transform: translate(-50%, -50%);
}
.wx-coolui-scroller-refresh .refresh-inner .down.loading .line:nth-child(1) {
-webkit-animation-delay: -.45s;
animation-delay: -0.45s;
}
.wx-coolui-scroller-refresh .refresh-inner .down.loading .line:nth-child(2) {
-webkit-animation-delay: -.3s;
animation-delay: -0.3s;
}
.wx-coolui-scroller-refresh .refresh-inner .down.loading .line:nth-child(3) {
-webkit-animation-delay: -.15s;
animation-delay: -0.15s;
}
.wx-coolui-scroller-refresh .refresh-inner .has-bg {
font-weight: bold;
background-clip: text;
-webkit-background-clip: text;
color: transparent !important;
background-size: 100% auto;
background-position: -100% -100%;
background-repeat: no-repeat;
}
.wx-coolui-scroller-refresh .refresh-inner .has-bg.loading {
animation: play 0.5s line infinite;
}
@keyframes circle {
0% {
transform: rotate(0);
}
100% {
transform: rotate(360deg);
}
}
@keyframes play {
from {
opacity: 1;
}
to {
opacity: 0.5;
}
}

View File

@ -0,0 +1,18 @@
Component({
options: {
multipleSlots: true,
addGlobalClass: true
},
relations: {
'../scroller/index': {
type: 'parent',
linked() {}
}
},
properties: {
pageList: {
type: Array,
value: []
}
}
})

View File

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@ -0,0 +1,6 @@
<view class="coolui-scroller-page">
<view wx:if="{{ pageList.length == 1 && pageList[0].height }}" style="height: {{ pageList[0].height}}px"></view>
<block wx:else>
<slot></slot>
</block>
</view>

View File

@ -0,0 +1,6 @@
:host {
display: block;
}
.wx-coolui-scroller-item {
height: 100%;
}

View File

@ -0,0 +1,293 @@
Component({
options: {
multipleSlots: true,
addGlobalClass: true,
},
relations: {
'../scroll-page/index': {
type: 'child',
linked: function (target) {},
},
'../nav/index': {
type: 'child',
linked: function (target) {},
},
'../empty/index': {
type: 'child',
linked: function (target) {},
},
'../refresh/index': {
type: 'child',
linked: function (target) {
this.setData({
type: target.data.type,
refreshConfig: target.data.config,
})
},
},
'../nav-pannel/index': {
type: 'parent',
linked: function (target) {
// console.log(target)
},
},
},
properties: {
isEmpty: {
type: Boolean,
value: false,
},
background: {
type: String,
value: '#f2f2f2',
},
isBackBtn: {
type: Boolean,
value: false,
},
enableFlex: {
type: Boolean,
value: false,
},
toView: {
type: String,
value: '',
},
top: {
type: Number,
value: 0,
},
animation: {
type: Boolean,
value: true,
},
},
data: {
active: false,
contentHeight: 0,
triggered: false,
isLoading: false,
timeout: null,
isBackToTopShow: false,
threshold: 0,
refreshConfig: {
shake: false,
height: 50,
style: 'black',
},
},
ready() {
this.setWapHeight()
this.refreshNodes = this.getRelationNodes('../refresh/index')
this.refreshNode = this.refreshNodes[0] ? this.refreshNodes[0] : null
},
methods: {
setWapHeight() {
const that = this
const query = that.createSelectorQuery().in(this)
query
.select('#content')
.boundingClientRect(function (res) {
if (res) {
that.setData({
contentHeight: res.height,
})
that.triggerEvent('contentHeight', res.height)
}
})
.select('#header')
.boundingClientRect(function (headerRes) {
if (headerRes) {
that.setData({
contentHeight: that.data.contentHeight - headerRes.height,
})
that.triggerEvent(
'contentHeight',
that.data.contentHeight - headerRes.height
)
}
})
.exec()
},
debounce(fn, wait) {
const that = this
that.setData({
timeout: null,
})
return function () {
if (that.data.timeout !== null) {
clearTimeout(that.data.timeout)
}
const timeout = setTimeout(() => {
fn()
}, wait)
that.setData({
timeout,
})
}
},
onLoadmore() {
const that = this
that.debounce(() => {
that.triggerEvent('loadmore')
if (that.data.refreshConfig.shake) {
wx.vibrateShort()
}
}, 500)()
},
onDefaultRefresh() {
const that = this
if (that.data.type == 'default') {
that.triggerEvent('refresh')
that.debounce(() => {
that.settriggered(false)
}, 1000)()
}
},
onRefresh() {
const that = this
if (that.data.refreshConfig.shake) {
wx.vibrateShort()
}
if (this.data.isLoading) {
console.log('refresh')
wx.showNavigationBarLoading()
if ('isAutoTriggered' in that.data.refreshConfig) {
if (that.data.refreshConfig.isAutoTriggered) {
that.triggerEvent('refresh')
that.debounce(() => {
that.settriggered(false)
setTimeout(() => {
that.onRestore()
}, 300)
}, 1000)()
} else {
if (that.data.triggered) {
that.triggerEvent('refresh')
}
}
} else {
that.triggerEvent('refresh')
that.debounce(() => {
that.settriggered(false)
setTimeout(() => {
that.onRestore()
}, 300)
}, 1000)()
}
}
},
onPulling(evt) {
console.log('pull')
const that = this
that.settriggered(true).then(() => {
// console.log(evt.detail.dy, that.data.refreshConfig.height);
let p = Math.min(
evt.detail.dy / (that.data.refreshConfig.height + 20),
1
)
that.p = p ? p : 0
that.setThreshold(that.p)
})
},
settriggered(flag) {
const that = this
return new Promise((resolve) => {
if (flag != that.data.triggered) {
if (that.refreshNode) {
that.refreshNode.setData({
triggered: flag,
})
}
that.setData(
{
triggered: flag,
},
() => {
resolve()
}
)
} else {
resolve()
}
})
},
setThreshold(p) {
const that = this
return new Promise((resolve) => {
if (that.refreshNode) {
that.refreshNode
.changeThreshold({
threshold: p,
})
.then(() => {
resolve()
})
}
})
},
onRestore() {
const that = this
if (that.data.isLoading) {
console.log('restore')
wx.hideNavigationBarLoading()
that.triggerEvent('restore')
that.debounce(() => {
that.setThreshold(0).then(() => {
that.p = 0
that.refreshNode.setLoading({
isloading: false,
})
that.setData({
isLoading: false,
triggered: false,
})
})
}, 100)()
}
},
scroll(e) {
if (e.detail.scrollTop > 100 && this.data.isBackToTopShow == false) {
this.setData({
isBackToTopShow: true,
})
} else if (
e.detail.scrollTop <= 100 &&
this.data.isBackToTopShow == true
) {
this.setData({
isBackToTopShow: false,
})
}
},
dragend() {
if (this.data.type != 'default') {
if (this.p > 0.6 && this.data.isLoading == false) {
this.setData(
{
isLoading: true,
},
() => {
this.refreshNode
.setLoading({
isloading: true,
})
.then(() => {
this.onRefresh()
})
}
)
} else {
this.settriggered(false)
}
}
},
backToTop() {
// this.triggerEvent("refresh");
this.setData({
top: 0,
})
},
},
})

View File

@ -0,0 +1,5 @@
{
"component": true,
"usingComponents": {
}
}

View File

@ -0,0 +1,20 @@
<view id="content" class="wrap {{active?'active':''}}">
<view class="slot-header" id="header">
<slot name="header"></slot>
</view>
<scroll-view scroll-y class="scroll flex" enable-passive="{{true}}" enhanced="{{true}}" fast-deceleration="{{true}}" enable-back-to-top="{{true}}" enable-flex="{{enableFlex}}" refresher-enabled="{{type?true:false}}" refresher-threshold="{{refreshConfig.height?refreshConfig.height:50}}" lower-threshold="{{100}}" refresher-default-style="{{type == 'default' ? refreshConfig.style : 'none'}}" refresher-background="{{refreshConfig.background.color}}" refresher-triggered="{{triggered}}" bindrefresherrefresh="onDefaultRefresh" bindrefresherpulling="onPulling" bindrefresherrestore="onRestore" bindscrolltolower="onLoadmore" bindscroll="scroll" bind:touchend="dragend" scroll-top="{{top}}" scroll-with-animation="{{animation}}" scroll-into-view="{{toView}}" style="height:{{contentHeight}}px;">
<view slot="refresher" wx:if="{{type != 'default'}}" class="refresh-container">
<slot name="refresh"></slot>
</view>
<view class="inner" style="min-height:{{contentHeight}}px;">
<slot></slot>
<view style="height:{{contentHeight}}px" hidden="{{!isEmpty}}" class="slot-empty">
<slot name="empty"></slot>
</view>
<view class="slot-loadmore" hidden="{{isEmpty}}">
<slot name="loadmore"></slot>
</view>
</view>
</scroll-view>
<view class="backToTop" wx:if="{{isBackToTopShow && isBackBtn}}" bindtap="backToTop"></view>
</view>

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@ -0,0 +1,85 @@
Component({
options: {
multipleSlots: true,
addGlobalClass: true,
},
relations: {
'./coolui-scroller': {
type: 'parent',
linked() {},
},
},
externalClasses: [
'search-btn-class',
'search-inner-class',
'search-placeholder-class',
],
properties: {
placeholder: {
type: String,
value: '请输入要搜索的内容',
},
button: {
type: Object,
value: {
show: false,
text: '搜索',
},
},
round: {
type: Boolean,
value: false,
},
clearable: {
type: Boolean,
value: false,
},
key: String,
},
data: {
// height: 100
isBtnShow: false,
isFocus: false,
},
methods: {
heightChange() {},
focus() {
this.setData({
isBtnShow: true,
})
},
blur() {
if (this.data.key.length == 0) {
this.setData({
isBtnShow: false,
isFocus: false,
})
}
},
input({ detail }) {
this.setData({
key: detail.value,
})
},
btnClick() {
if (this.data.key) {
this.triggerEvent('btnClick', {
key: this.data.key,
})
}
},
clear() {
this.setData({
key: '',
isFocus: true,
})
},
confirm() {
if (this.data.key) {
this.triggerEvent('confirm', {
key: this.data.key,
})
}
},
},
})

View File

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,17 @@
<!-- components/coolui-scroller-item/coolui-scroller-item.wxml -->
<view class="wx-coolui-scroller-search {{(button.show||isBtnShow)?'on':''}} {{clearable && key.length > 0?'clearable':''}}">
<slot name="leftout"></slot>
<view class="search-inner {{round?'round':''}}">
<view class="search-placeholder">
<view class="search-icon"></view>
{{key.length==0?(placeholder?placeholder:"请输入要搜索的内容"):''}}
</view>
<input class="search-input" type="text" model:value="{{key}}" bind:tap="focus" bindblur="blur" focus="{{isFocus}}" bindconfirm="confirm" bindinput="input" />
<view class="search-close" bind:tap="clear"></view>
</view>
<block wx:if="{{!button.hide}}">
<button wx:if="{{button.show||isBtnShow}}" class="button search-btn" bind:tap="btnClick">
{{button.text ? button.text : '搜索'}}
</button>
</block>
</view>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,117 @@
// pages/second-floor/circle/index.js
Component({
externalClasses: ['second-floor-refresh-class', 'second-floor-refresh-back'],
relations: {
'../second-floor/index': {
type: 'parent',
linked(target) {
this.setData({
target,
})
},
},
},
properties: {
refreshConfig: {
type: Object,
value: {
loadingText: '正在加载',
backText: '返回首页',
downText: '下拉刷新',
tipText: '松开刷新,继续下拉有惊喜~',
moreText: '继续下拉有惊喜~',
color: '#ffffff',
},
},
},
/**
* 组件的初始数据
*/
data: {
text: '',
isLoading: false,
isFloorShow: false,
p: 0,
scroll_height: 0,
target: null,
status: 'down',
},
/**
* 组件的方法列表
*/
methods: {
setText(p) {
if (p > 0 && p <= this.data.scroll_height / 6) {
if (this.data.text !== this.data.refreshConfig.downText) {
this.setData({
text: this.data.refreshConfig.downText,
status: 'down',
})
}
} else if (
p > this.data.scroll_height / 6 &&
p <= this.data.scroll_height / 3
) {
if (this.data.text !== this.data.refreshConfig.tipText) {
this.setData({
text: this.data.refreshConfig.tipText,
status: 'tip',
})
}
} else {
if (this.data.text !== this.data.refreshConfig.moreText) {
this.setData({
text: this.data.refreshConfig.moreText,
status: 'more',
})
}
}
this.setData({
p,
})
},
setLoading(flag) {
this.setData({
isLoading: flag,
status: 'loading',
text: this.data.refreshConfig.loadingText,
})
},
setDown() {
this.setData({
isLoading: false,
text: this.data.refreshConfig.downText,
p: 0,
status: 'down',
})
},
setSecondShow(flag) {
const text = flag ? this.data.refreshConfig.backText : ''
this.setData({
isFloorShow: flag,
text,
status: 'back',
})
},
back() {
if (this.data.isFloorShow) {
this.data.target.back()
}
},
},
ready() {
const defaultConfig = {
loadingText: '正在加载',
backText: '返回首页',
downText: '下拉刷新',
tipText: '松开刷新,继续下拉有惊喜~',
moreText: '继续下拉有惊喜~',
color: '#ffffff',
}
this.setData({
refreshConfig: { ...defaultConfig, ...this.data.refreshConfig },
})
},
})

View File

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@ -0,0 +1,164 @@
/* pages/second-floor/circle/index.wxss */
:host {
display : block;
width : 100%;
font-size: 28rpx;
}
.second-floor-refresh {
display : flex;
align-items : center;
justify-content: center;
padding : 30rpx 0;
line-height : 1em;
.circle {
display : flex;
width : 48rpx;
height : 48rpx;
margin-right: 20rpx;
position : relative;
border : none;
&.loading {
border : 1px dashed;
border-radius: 100%;
animation : loading 1s infinite linear;
}
}
}
@keyframes loading {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.left {
width : 12px;
height : 24px;
position: relative;
overflow: hidden;
}
.leftcircle {
width : 22px;
height : 22px;
border : 1px solid;
position : absolute;
border-radius : 50%;
left : 0rpx;
top : 0rpx;
border-bottom : 1px solid transparent !important;
border-left : 1px solid transparent !important;
transform : rotate(45deg);
animation-name : circle_left;
animation-duration : 2s;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
.right {
width : 12px;
height : 24px;
position: relative;
overflow: hidden;
}
.rightcircle {
width : 22px;
height : 22px;
border-radius : 50%;
border : 1px solid;
position : absolute;
border-top : 1px solid transparent !important;
border-right : 1px solid transparent !important;
right : 0rpx;
top : 0rpx;
animation-name : circle_right;
animation-duration : 2s;
animation-timing-function: linear;
animation-iteration-count: infinite;
transform : rotate(45deg);
}
.circle.loading {
.leftcircle,
.rightcircle {
border: none;
}
}
.second-floor-refresh {
.downicon {
width : 12rpx;
height : 12rpx;
position : absolute;
top : 50%;
left : 50%;
transform: translate(-50%, -50%);
.line {
&:nth-child(1) {
display : block;
width : 1px;
height : 22rpx;
background-color: #fff;
position : absolute;
top : 50%;
left : 50%;
transform : translate(-50%, -50%);
border-radius : 2rpx;
opacity : 1;
}
&:nth-child(2) {
width : 15rpx;
height : 1px;
background-color: #fff;
display : block;
position : absolute;
bottom : -3px;
left : 50%;
transform : rotate(-45deg);
transform-origin: 0 50%;
border-radius : 2rpx;
opacity : 1;
}
&:nth-child(3) {
width : 15rpx;
height : 1px;
background-color: #fff;
display : block;
position : absolute;
bottom : -3px;
right : 50%;
transform : rotate(45deg);
transform-origin: 100% 50%;
border-radius : 2rpx;
opacity : 1;
}
}
}
.circle.loading .downicon {
display: none;
}
text {
display : block;
text-align : center;
line-height: 1.5em;
}
}
/* .second-floor-refresh .downicon.up {
transform: translate(-50%, -50%) rotate(180deg);
} */

View File

@ -0,0 +1,18 @@
<!-- pages/second-floor/circle/index.wxml -->
<!-- <text>{{p}}</text> -->
<view class="second-floor-refresh second-floor-refresh-class second-floor-refresh-{{status}}" bind:tap="back" style="color: {{refreshConfig.color}}">
<view class="circle {{isLoading ? 'loading':''}}" wx:if="{{p < scroll_height / 3}}" style="border-color: {{refreshConfig.color}};">
<view class="left">
<view class="leftcircle" style="transform: rotate({{p < 50 ? (45 - p * 3.6) : -135}}deg);border-color: {{refreshConfig.color}};"></view>
</view>
<view class="right">
<view class="rightcircle" style="transform: rotate({{(p >= 50 && p <= 100) ? (45 - (p - 50) * 3.6) : (p > 100 ? -135 : 45 )}}deg);border-color: {{refreshConfig.color}};"></view>
</view>
<view class="downicon {{(p < scroll_height / 3 && p > scroll_height / 6) ? 'up' : ''}}">
<view class="line"></view>
<view class="line"></view>
<view class="line"></view>
</view>
</view>
<text decode="true">{{text}}</text>
</view>

View File

@ -0,0 +1,155 @@
/* pages/second-floor/circle/index.wxss */
:host {
display: block;
width: 100%;
font-size: 28rpx;
}
.second-floor-refresh {
display: flex;
align-items: center;
justify-content: center;
padding: 30rpx 0;
line-height: 1em;
}
.second-floor-refresh .circle {
display: flex;
width: 48rpx;
height: 48rpx;
margin-right: 20rpx;
position: relative;
border: none;
}
.second-floor-refresh .circle.loading {
border: 1px dashed;
border-radius: 100%;
animation: loading 1s infinite linear;
}
@keyframes loading {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.left {
width: 12px;
height: 24px;
position: relative;
overflow: hidden;
}
.leftcircle {
width: 22px;
height: 22px;
border: 1px solid;
position: absolute;
border-radius: 50%;
left: 0rpx;
top: 0rpx;
border-bottom: 1px solid transparent !important;
border-left: 1px solid transparent !important;
transform: rotate(45deg);
animation-name: circle_left;
animation-duration: 2s;
animation-timing-function: linear;
animation-iteration-count: infinite;
}
.right {
width: 12px;
height: 24px;
position: relative;
overflow: hidden;
}
.rightcircle {
width: 22px;
height: 22px;
border-radius: 50%;
border: 1px solid;
position: absolute;
border-top: 1px solid transparent !important;
border-right: 1px solid transparent !important;
right: 0rpx;
top: 0rpx;
animation-name: circle_right;
animation-duration: 2s;
animation-timing-function: linear;
animation-iteration-count: infinite;
transform: rotate(45deg);
}
.circle.loading .leftcircle,
.circle.loading .rightcircle {
border: none;
}
.second-floor-refresh .downicon {
width: 12rpx;
height: 12rpx;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.second-floor-refresh .downicon .line:nth-child(1) {
display: block;
width: 1px;
height: 22rpx;
background-color: #fff;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 2rpx;
opacity: 1;
}
.second-floor-refresh .downicon .line:nth-child(2) {
width: 15rpx;
height: 1px;
background-color: #fff;
display: block;
position: absolute;
bottom: -3px;
left: 50%;
transform: rotate(-45deg);
transform-origin: 0 50%;
border-radius: 2rpx;
opacity: 1;
}
.second-floor-refresh .downicon .line:nth-child(3) {
width: 15rpx;
height: 1px;
background-color: #fff;
display: block;
position: absolute;
bottom: -3px;
right: 50%;
transform: rotate(45deg);
transform-origin: 100% 50%;
border-radius: 2rpx;
opacity: 1;
}
.second-floor-refresh .circle.loading .downicon {
display: none;
}
.second-floor-refresh text {
display: block;
text-align: center;
line-height: 1.5em;
}
/* .second-floor-refresh .downicon.up {
transform: translate(-50%, -50%) rotate(180deg);
} */

View File

@ -0,0 +1,546 @@
// miniprogram_npm/coolui-scroller/second-floor/index.js
Component({
options: {
multipleSlots: true,
addGlobalClass: true,
},
externalClasses: ['second-floor-class'],
relations: {
'../second-floor-refresh/index': {
type: 'child',
linked(target) {
// console.log(target);
},
},
'../nav-bar/index': {
type: 'child',
linked(target) {
// console.log(target.data)
// console.log(target.data.statusBarHeight)
// this.setData({
// navBar: target,
// })
},
},
},
properties: {
threshold: {
type: Number,
value: 0,
},
offset: {
type: Number,
value: 0,
},
center: {
type: Boolean,
value: false,
observer: function (newVal) {
this.init()
},
},
bottom: {
type: Boolean,
value: true,
observer: function (newVal) {
this.init()
},
},
top: {
type: Boolean,
value: false,
observer: function (newVal) {
this.init()
},
},
scale: {
type: Boolean,
value: false,
observer: function (newVal) {
this.init()
},
},
tip: {
type: Object,
value: {
show: false,
height: 100,
times: 1,
duration: 2000,
},
},
},
data: {
scroll_height: 0,
touchy: 0,
isLoading: false,
isFloorShow: false,
wapperAnimationData: {},
innerAnimationData: {},
statusBarHeight: 0,
navBar: null,
},
lifetimes: {
attached: function () {
// 在组件实例进入页面节点树时执行
// this.init()
let info = wx.getSystemInfoSync()
console.log(info)
this.setData({
scroll_height: info.windowHeight,
})
},
},
ready() {
this.init(() => {
this.navNodes = this.getRelationNodes('../nav-bar/index')
this.navNode = this.navNodes[0] ? this.navNodes[0] : null
this.setData({
statusBarHeight: this.navNode.data.statusBarHeight,
})
})
},
methods: {
debounce(fn, wait) {
const that = this
that.setData({
timeout: null,
})
return function () {
if (that.data.timeout !== null) {
clearTimeout(that.data.timeout)
}
const timeout = setTimeout(() => {
fn()
}, wait)
that.setData({
timeout,
})
}
},
/**
* @name: 初始化
* @description: 根据设置初始化动画初始化参数初始化子组件
* @return {*}
*/
init(callback = null) {
let info = wx.getSystemInfoSync()
this.refreshNodes = this.getRelationNodes('../second-floor-refresh/index')
this.refreshNode = this.refreshNodes[0] ? this.refreshNodes[0] : null
this.refreshNode.setData({
scroll_height: this.data.scroll_height,
})
this.refreshNode.setDown()
let animation = this.setAnimation(
-this.data.scroll_height + this.data.offset,
0
)
console.log(this.data.offset)
let animationInner = null
let scaleXy = this.data.scale ? 0.1 : 1
if (this.data.top) {
animationInner = this.setAnimation(
this.data.scroll_height,
0,
scaleXy,
scaleXy
)
}
if (this.data.center) {
animationInner = this.setAnimation(
this.data.scroll_height / 2,
0,
scaleXy,
scaleXy
)
}
if (this.data.bottom) {
animationInner = this.setAnimation(0, 0, scaleXy, scaleXy)
}
this.setData(
{
wapperAnimationData: animation.export(),
innerAnimationData: animationInner ? animationInner.export() : {},
threshold: this.data.threshold,
},
() => {
this.wapper = this.selectComponent('.second-floor-wapper')
if (callback) {
callback()
}
if (this.data.tip.show) {
this.tipShow()
}
}
)
},
tipShow(
duration = this.data.tip.duration,
wait = this.data.tip.duration,
times = this.data.tip.times
) {
const animation = wx.createAnimation()
let offset = -this.data.scroll_height + this.data.offset
animation.translateY(offset).step({
duration,
timingFunction: 'ease-in',
})
this.setData(
{
wapperAnimationData: animation.export(),
threshold: 0,
},
() => {
this.refreshNode.setText(this.data.scroll_height / 2)
if (this.data.tip.show) {
setTimeout(() => {
animation
.translateY(-this.data.scroll_height + this.data.tip.height)
.step({
duration,
timingFunction: 'ease-out',
})
this.setData(
{
wapperAnimationData: animation.export(),
threshold: this.data.tip.height,
},
() => {
this.refreshNode.setText(this.data.scroll_height / 2)
if (times > 1) {
setTimeout(() => {
this.tipShow(duration, wait, times - 1)
}, wait)
} else {
setTimeout(() => {
this.setData(
{
tip: {
show: false,
height: this.data.tip.height,
times: this.data.tip.times,
},
},
() => {
this.tipShow(duration, wait, times - 1)
}
)
}, wait)
}
}
)
}, duration)
}
}
)
},
/**
* @name: 触摸拖拽开始
* @description: 记录初始触摸位置
* @param {*} e
* @return {*}
*/
touchStart(e) {
console.log(this.data.tip.show)
// 正在刷新时不操作触摸
if (this.data.tip.show) {
return false
}
if (this.data.isLoading) {
return false
}
this.setData({
touchy: e.changedTouches[0].clientY,
})
},
/**
* @name: 拖动时执行
* @description: 修改页面动画传递触摸动态参数给refresh组件
* @return {*}
*/
touchMove(e) {
if (this.data.tip.show) {
return false
}
// 正在刷新时不进行操作, 二楼已加载是不进行操作
if (!this.data.isFloorShow && !this.data.isLoading) {
const distance = Math.round(
e.changedTouches[0].clientY - this.data.touchy
)
let scaleXy = 1
if (this.data.scale) {
scaleXy = 0.1 + distance / 200
scaleXy = scaleXy >= 1 ? 1 : scaleXy
}
if (distance > 0) {
let animation = this.setAnimation(
-this.data.scroll_height + distance + this.data.offset,
0
)
let animationInner = null
if (this.data.top) {
animationInner = this.setAnimation(
this.data.scroll_height - distance,
0,
scaleXy,
scaleXy
)
}
if (this.data.bottom) {
animationInner = this.setAnimation(0, 0, scaleXy, scaleXy)
}
if (this.data.center) {
animationInner = this.setAnimation(
(this.data.scroll_height - distance) / 2,
0,
scaleXy,
scaleXy
)
}
// console.log(animationInner);
this.setData({
wapperAnimationData: animation.export(),
innerAnimationData: animationInner ? animationInner.export() : null,
threshold: distance,
})
this.refreshNode.setText(distance)
}
}
},
/**
* @name: 松手后执行
* @description: 松手时如果拖拽的距离大于屏幕三分之一直接执行拉到二楼动画如果大于六分之一小于三分之一则回到六分之一并开启刷新状态如果小于六分之一直接回弹
* @return {*}
*/
touchEnd() {
if (this.data.tip.show) {
return false
}
// 正在刷新时不进行操作, 二楼已加载是不进行操作,只点屏幕不拖拽时不进行操作
if (
!this.data.isFloorShow &&
this.data.threshold > 0 &&
!this.data.isLoading
) {
// 大于3分之1 直接拉到二楼
if (this.data.threshold > this.data.scroll_height / 3) {
const animation = this.setAnimation(0, 400)
let animationInner = null
if (this.data.top) {
animationInner = this.setAnimation(0, 400, 1, 1)
}
if (this.data.bottom) {
animationInner = this.setAnimation(0, 0, 1, 1)
}
if (this.data.center) {
animationInner = this.setAnimation(0, 400, 1, 1)
}
this.setData(
{
wapperAnimationData: animation.export(),
innerAnimationData: animationInner ? animationInner.export() : {},
},
() => {
setTimeout(() => {
this.refreshNode.setSecondShow(true)
this.setData({
isFloorShow: true,
})
this.triggerEvent('secondShow')
}, 400)
}
)
} else {
if (this.data.threshold > this.data.scroll_height / 6) {
// 大于6分之一小于3分之一回到 6分之一停顿开始刷新
const animation = this.setAnimation(
-this.data.scroll_height + this.data.scroll_height / 6,
400
)
let animationInner = null
if (this.data.top) {
animationInner = this.setAnimation(
this.data.scroll_height - this.data.scroll_height / 6,
400
)
}
if (this.data.bottom) {
animationInner = this.setAnimation(0, 0)
}
if (this.data.center) {
animationInner = this.setAnimation(
(this.data.scroll_height - this.data.scroll_height / 6) / 2,
400
)
}
this.setData(
{
wapperAnimationData: animation.export(),
innerAnimationData: animationInner
? animationInner.export()
: {},
},
() => {
this.triggerEvent('refresh')
this.setData({
isLoading: true,
})
this.refreshNode.setLoading(true)
}
)
} else {
// 小于6分之一 直接回顶部
this.back(false)
}
}
}
},
/**
* @name: 回弹及二楼关闭
* @description: 拖动小于6分之一直接回顶部或外部自定义调用关闭二楼
* @return {*}
*/
back(callback = true) {
return new Promise((resolve) => {
const animation = this.setAnimation(
-this.data.scroll_height + this.data.offset,
800
)
let animationInner = null
if (this.data.top) {
animationInner = this.setAnimation(
this.data.scroll_height,
800,
1,
this.data.scale ? 0 : 1
)
}
if (this.data.bottom) {
animationInner = this.setAnimation(0, 0, 1, this.data.scale ? 0 : 1)
}
if (this.data.center) {
animationInner = this.setAnimation(
this.data.scroll_height / 2,
800,
1,
this.data.scale ? 0 : 1
)
}
this.setData(
{
wapperAnimationData: animation.export(),
innerAnimationData: animationInner ? animationInner.export() : {},
},
() => {
setTimeout(() => {
// this.refreshNode.setShow(false)
this.refreshNode.setDown()
this.setData(
{
isFloorShow: false,
threshold: 0,
},
() => {
if (callback) {
this.triggerEvent('secondBack')
resolve()
}
}
)
}, 800)
}
)
})
},
/**
* @name: 刷新后的回弹
* @description: 刷新之后回弹方法再请求完数据之后执行
* @return {*}
*/
settriggered() {
return new Promise((resolve) => {
const animation = this.setAnimation(
-this.data.scroll_height + this.data.offset,
800
)
let animationInner = null
if (this.data.top) {
animationInner = this.setAnimation(
this.data.scroll_height,
800,
1,
this.data.scale ? 0 : 1
)
}
if (this.data.bottom) {
animationInner = this.setAnimation(0, 0, 1, this.data.scale ? 0 : 1)
}
if (this.data.center) {
animationInner = this.setAnimation(
this.data.scroll_height / 2,
800,
1,
this.data.scale ? 0 : 1
)
}
this.setData(
{
wapperAnimationData: animation.export(),
innerAnimationData: animationInner ? animationInner.export() : {},
isLoading: false,
},
() => {
setTimeout(() => {
this.refreshNode.setDown()
this.setData(
{
threshold: 0,
},
() => {
resolve()
}
)
}, 400)
}
)
})
},
setAnimation(
y,
duration = 400,
scale = 1,
opacity = 1,
timingFunction = 'ease-out'
) {
let transformOrigin = '50% 50% 0'
if (this.data.top) {
transformOrigin = '50% 0 0'
}
if (this.data.bottom) {
transformOrigin = '50% 100% 0'
}
if (this.data.center) {
transformOrigin = '50% 50% 0'
}
const animation = wx.createAnimation({
delay: 0,
duration: duration,
timingFunction: timingFunction,
transformOrigin: transformOrigin,
})
animation.translateY(y).scale(scale, scale).opacity(opacity)
animation.step()
return animation
},
},
})

View File

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@ -0,0 +1,34 @@
.wx-coolui-scroller-second-floor {
overflow: hidden;
height : 100vh !important;
.second-floor-wapper {
// -webkit-transition: transformY(-50%) scale(1, 1);
transform: translateY(-50%) scale(1, 1);
height : 200vh;
.second-floor-inner {
height: 100vh;
}
.first-floor {
height : 100vh;
overflow: hidden;
}
.second-floor-inner .second-floor-text {
width : 100%;
position : absolute;
bottom : 0;
display : flex;
justify-content: center;
align-items : center;
z-index : 99;
}
}
.second-floor-inner {
position: relative;
overflow: hidden;
}
}

View File

@ -0,0 +1,20 @@
<view class="wx-coolui-scroller-second-floor second-floor-class" style="" bind:touchstart="touchStart" bind:touchend="touchEnd" bind:touchmove="touchMove">
<view class="second-floor-wapper" animation="{{wapperAnimationData}}">
<view class="second-floor-inner" style="">
<view style="height: 100vh;" animation="{{innerAnimationData}}">
<slot name="second-floor"></slot>
</view>
<div class="second-floor-text">
<slot name="second-floor-refresh"></slot>
</div>
</view>
<view class="first-floor" style="">
<view style="height: {{statusBarHeight}}px">
<slot name="nav-bar"></slot>
</view>
<view style="height: calc(100vh - {{statusBarHeight}}px)">
<slot></slot>
</view>
</view>
</view>
</view>

View File

@ -0,0 +1,33 @@
.wx-coolui-scroller-second-floor {
overflow: hidden;
height: 100vh !important;
}
.wx-coolui-scroller-second-floor .second-floor-wapper {
transform: translateY(-50%) scale(1, 1);
height: 200vh;
}
.wx-coolui-scroller-second-floor .second-floor-wapper .second-floor-inner {
height: 100vh;
}
.wx-coolui-scroller-second-floor .second-floor-wapper .first-floor {
height: 100vh;
overflow: hidden;
}
.wx-coolui-scroller-second-floor .second-floor-wapper .second-floor-inner .second-floor-text {
width: 100%;
position: absolute;
bottom: 0;
display: flex;
justify-content: center;
align-items: center;
z-index: 99;
}
.wx-coolui-scroller-second-floor .second-floor-inner {
position: relative;
overflow: hidden;
}

View File

@ -0,0 +1,139 @@
// components/coolui-scroller-item/coolui-scroller-item.js
Component({
relations: {
'../../coolui-scroller/index': {
type: 'parent', // 关联的目标节点应为子节点
linked() {},
},
'../item/index': {
type: 'child',
linked: function (target) {},
linkChanged: function (target) {},
unlinked: function (target) {},
},
},
properties: {
overlay: {
type: Boolean,
value: true,
},
overlayDuration: {
type: Number,
value: 500,
},
scroll: {
type: Boolean,
value: false,
},
},
data: {
active: null,
overlayHeight: 0,
isOverLayShow: false,
opacityAnimation: {},
},
/**
* 组件的方法列表
*/
methods: {
setOverlayHeight() {
const that = this
wx.getSystemInfoAsync({
success: (sysRes) => {
const { windowHeight } = sysRes
const query = that.createSelectorQuery().in(this)
query
.select('#overlay')
.boundingClientRect(function (res) {
if (res) {
that.setData({
overlayHeight: windowHeight - res.top,
})
}
})
.exec()
},
})
},
toggle(active) {
const that = this
let flag = false
flag =
active === that.data.active && that.data.active !== null
? true
: active == null
? true
: false
that.setData({
active: active,
})
this.toggleOverlay(flag)
this.toggleDropdown()
},
toggleOverlay(flag) {
const that = this
var animation = wx.createAnimation({
duration: that.data.overlayDuration,
timingFunction: 'ease-in',
})
if (flag) {
if (that.data.isOverLayShow === true) {
// 不显示
animation.opacity(0).step()
that.setData(
{
opacityAnimation: animation.export(),
},
() => {
setTimeout(() => {
that.setData({
isOverLayShow: false,
})
}, that.data.overlayDuration)
}
)
} else {
// 显示
animation.opacity(1).step()
this.setData(
{
isOverLayShow: true,
},
() => {
that.setData({
opacityAnimation: animation.export(),
})
}
)
}
} else {
if (that.data.isOverLayShow !== true) {
animation.opacity(1).step()
this.setData(
{
isOverLayShow: true,
},
() => {
that.setData({
opacityAnimation: animation.export(),
})
}
)
}
}
this.setOverlayHeight()
},
toggleDropdown() {
var nodes = this.getRelationNodes('../item/index')
nodes.forEach((item, index) => {
item.toggleDropdown(this.data.active)
})
},
close() {
this.toggle(null)
},
},
ready() {},
})

View File

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@ -0,0 +1,6 @@
<view class="coolui-scroller-nav {{scroll?'scroll':'flex'}}">
<slot></slot>
</view>
<block wx:if="{{overlay}}">
<view class="overlay" id="overlay" style="height:{{overlayHeight}}px;" animation="{{opacityAnimation}}" hidden="{{!isOverLayShow}}" bind:tap="close" ></view>
</block>

View File

@ -0,0 +1,41 @@
/* components/coolui-scroller-item/coolui-scroller-item.wxss */
:host {
display : block;
width : 100%;
box-shadow: 0 2px 12px rgb(100 101 102 / 12%);
position : relative;
}
.coolui-scroller-nav {
width : 100%;
height: 100rpx;
}
.coolui-scroller-nav.flex {
display: flex;
}
.coolui-scroller-nav.scroll {
white-space: nowrap;
overflow-x : scroll;
scroll-behavior:smooth
}
.coolui-scroller-nav::-webkit-scrollbar {
display: none;
}
.coolui-scroller-nav-scroll {
white-space: nowrap;
overflow : visible;
}
.overlay {
position : absolute;
top : 100rpx;
left : 0;
width : 100%;
height : 100vh;
background-color: rgba(0, 0, 0, 0.6);
opacity : 0;
}

View File

@ -0,0 +1,166 @@
// components/coolui-scroller-nav/item/index.js
Component({
relations: {
"../index/index": {
type: "parent",
linked: function (target) {
// console.log(target);
},
},
},
properties: {
title: {
type: String,
},
name: {
type: String,
},
type: {
type: String,
},
value: {
type: String,
},
options: {
type: Array,
},
color: {
type: String,
},
activeColor: {
type: String,
},
multiple: {
type: Boolean,
value: false,
},
actionBar: {
type: Boolean,
value: false,
},
},
data: {
isDropdownShow: false,
overlayDuration: 0,
dropAnimation: {},
select: null,
selectArray: [],
},
methods: {
toggle() {
var nodes = this.getRelationNodes("../index/index");
this.setData({
overlayDuration: nodes[0].data.overlayDuration,
});
// console.log(this.data.name);
nodes[0].toggle(this.data.name);
},
toggleDropdown(active) {
if (active === this.data.name) {
if (this.data.isDropdownShow === false) {
if (this.data.multiple) {
this.setData({
selectArray: this.data.value ? this.data.value.split(",") : [],
isDropdownShow: true,
});
} else {
this.setData({
select: parseInt(this.data.value),
isDropdownShow: true,
});
}
} else {
this.setData({
isDropdownShow: false,
});
}
} else {
this.setData({
isDropdownShow: false,
});
}
},
select(e) {
var nodes = this.getRelationNodes("../index/index");
if (this.data.multiple) {
const selectArray = this.data.selectArray;
const id = e.target.dataset.id;
const isIn = this.inArray(id, selectArray);
if (isIn === false) {
selectArray.push(e.target.dataset.id);
} else {
selectArray.splice(isIn, 1);
}
this.setData({
selectArray: selectArray.sort(),
});
} else {
if (!this.data.actionBar) {
this.setData(
{
select:
e.target.dataset.id != this.data.select
? e.target.dataset.id
: null,
value: e.target.dataset.id != this.data.select
? e.target.dataset.id
: null,
},
() => {
setTimeout(() => {
nodes[0].toggle(null);
}, 600);
}
);
} else {
this.setData({
select: e.target.dataset.id != this.data.select
? e.target.dataset.id
: null,
});
}
}
},
inArray(search, array) {
for (var i in array) {
if (array[i] == search) {
return i;
}
}
return false;
},
clear() {
this.setData({
value: "",
selectArray: [],
});
},
confirm() {
var nodes = this.getRelationNodes("../index/index");
if (this.data.multiple) {
this.setData(
{
value: this.data.selectArray.join(","),
},
() => {
setTimeout(() => {
nodes[0].toggle(null);
}, 500);
}
);
} else {
this.setData(
{
value: this.data.select,
},
() => {
setTimeout(() => {
nodes[0].toggle(null);
}, 500);
}
);
}
},
},
ready() {},
});

View File

@ -0,0 +1,4 @@
{
"component": true,
"usingComponents": {}
}

View File

@ -0,0 +1,43 @@
<wxs module="tools">
function inArray(search, array) {
for (var i = 0; i < array.length; i++) {
if (array[i] === search) {
return true;
}
}
return false;
}
module.exports.inArray = inArray;
</wxs>
<view class="coolui-scroller-nav-item" bindtap="toggle">
<view class="item-title {{type == 'sort'?'sort':''}} {{isDropdownShow ? 'on' : ''}} {{value == 1 && type == 'sort' ? 'up':'down'}}" style="color: {{isDropdownShow ? activeColor : color}}">
<view class="item-title-inner">
{{type == 'sort'? (value == 0 ? options[0].title : options[value].title) : title}}
</view>
</view>
</view>
<view class="dropdown-menu {{isDropdownShow ? 'on' : ''}}">
<view class="dropdown-menu-inner {{isDropdownShow ? 'on' : ''}}">
<view class="dropdown-menu-inner-scroll">
<block wx:if="{{options}}">
<block wx:if="{{multiple}}">
<view class="option-item {{tools.inArray(index, selectArray)?'on':''}}" bind:tap="select" data-id="{{index}}" wx:for="{{options}}" wx:key="id">
{{item.title}}
</view>
</block>
<block wx:else>
<view class="option-item {{index === select ? 'on' : ''}}" bind:tap="select" data-id="{{index}}" wx:for="{{options}}" wx:key="id">
{{item.title}}
</view>
</block>
</block>
<block>
<slot></slot>
</block>
</view>
<view class="action-bar" wx:if="{{actionBar}}">
<button type="default" bind:tap="clear">清空</button>
<button type="primary" bind:tap="confirm" style="background:{{activeColor}}">确定</button>
</view>
</view>
</view>

File diff suppressed because one or more lines are too long

BIN
images/ic_check_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
images/ic_empty_data.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

BIN
images/ic_history_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 605 B

BIN
images/ic_home_sel_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 616 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 932 B

BIN
images/ic_mine_sel_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 946 B

BIN
images/ic_register_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
images/ic_report_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More