├── .wechatide └── fileCache.cfg ├── README.md ├── app.js ├── app.json ├── app.wxss ├── component ├── box │ ├── box.js │ ├── box.json │ ├── box.wxml │ └── box.wxss ├── button │ ├── button.js │ ├── button.json │ ├── button.wxml │ └── button.wxss ├── checkbox-group │ ├── checkbox-group.js │ ├── checkbox-group.json │ ├── checkbox-group.wxml │ └── checkbox-group.wxss ├── checkbox │ ├── checkbox.js │ ├── checkbox.json │ ├── checkbox.wxml │ └── checkbox.wxss ├── clip │ ├── clip.js │ ├── clip.json │ ├── clip.wxml │ └── clip.wxss ├── col │ ├── col.js │ ├── col.json │ ├── col.wxml │ └── col.wxss ├── drawer │ ├── drawer.js │ ├── drawer.json │ ├── drawer.wxml │ └── drawer.wxss ├── drop │ ├── drop.js │ ├── drop.json │ ├── drop.wxml │ └── drop.wxss ├── fixed │ ├── fixed.js │ ├── fixed.json │ ├── fixed.wxml │ └── fixed.wxss ├── flex │ ├── flex.js │ ├── flex.json │ ├── flex.wxml │ └── flex.wxss ├── gesture │ ├── gesture.js │ ├── gesture.json │ ├── gesture.wxml │ └── gesture.wxss ├── grid │ ├── grid.js │ ├── grid.json │ ├── grid.wxml │ └── grid.wxss ├── indexes-item │ ├── indexes-item.js │ ├── indexes-item.json │ ├── indexes-item.wxml │ └── indexes-item.wxss ├── indexes │ ├── indexes.js │ ├── indexes.json │ ├── indexes.wxml │ └── indexes.wxss ├── input │ ├── input.js │ ├── input.json │ ├── input.wxml │ └── input.wxss ├── line │ ├── line.js │ ├── line.json │ ├── line.wxml │ └── line.wxss ├── list │ ├── list.js │ ├── list.json │ ├── list.wxml │ └── list.wxss ├── loading │ ├── loading.js │ ├── loading.json │ ├── loading.wxml │ └── loading.wxss ├── modal │ ├── modal.js │ ├── modal.json │ ├── modal.wxml │ └── modal.wxss ├── page │ ├── page.js │ ├── page.json │ ├── page.wxml │ └── page.wxss ├── radio-group │ ├── radio-group.js │ ├── radio-group.json │ ├── radio-group.wxml │ └── radio-group.wxss ├── radio │ ├── radio.js │ ├── radio.json │ ├── radio.wxml │ └── radio.wxss ├── region │ ├── area.min.js │ ├── region.js │ ├── region.json │ ├── region.wxml │ └── region.wxss ├── search │ ├── search.js │ ├── search.json │ ├── search.wxml │ └── search.wxss ├── size │ ├── size.js │ ├── size.json │ ├── size.wxml │ └── size.wxss ├── swiper │ ├── swiper.js │ ├── swiper.json │ ├── swiper.wxml │ └── swiper.wxss ├── switch │ ├── switch.js │ ├── switch.json │ ├── switch.wxml │ └── switch.wxss ├── tab │ ├── tab.js │ ├── tab.json │ ├── tab.wxml │ └── tab.wxss ├── tabs │ ├── tabs.js │ ├── tabs.json │ ├── tabs.wxml │ └── tabs.wxss ├── top │ ├── top.js │ ├── top.json │ ├── top.wxml │ └── top.wxss └── upload │ ├── upload.js │ ├── upload.json │ ├── upload.wxml │ └── upload.wxss ├── images ├── gui.png └── nav │ ├── gui-active.png │ ├── gui-default.png │ ├── index-active.png │ └── index-default.png ├── pages ├── button │ ├── button.js │ ├── button.json │ ├── button.wxml │ └── button.wxss ├── checkbox │ ├── checkbox.js │ ├── checkbox.json │ ├── checkbox.wxml │ └── checkbox.wxss ├── clip │ ├── clip.js │ ├── clip.json │ ├── clip.wxml │ └── clip.wxss ├── drawer │ ├── drawer.js │ ├── drawer.json │ ├── drawer.wxml │ └── drawer.wxss ├── drop │ ├── array.js │ ├── drop.js │ ├── drop.json │ ├── drop.wxml │ ├── drop.wxss │ └── img.jpg ├── fixed │ ├── fixed.js │ ├── fixed.json │ ├── fixed.wxml │ └── fixed.wxss ├── flex │ ├── flex.js │ ├── flex.json │ ├── flex.wxml │ └── flex.wxss ├── gesture │ ├── gesture.js │ ├── gesture.json │ ├── gesture.wxml │ └── gesture.wxss ├── grid │ ├── grid.js │ ├── grid.json │ ├── grid.wxml │ └── grid.wxss ├── gui │ ├── gui.js │ ├── gui.json │ ├── gui.wxml │ └── gui.wxss ├── index │ ├── index.js │ ├── index.json │ ├── index.wxml │ └── index.wxss ├── indexes │ ├── city.js │ ├── indexes.js │ ├── indexes.json │ ├── indexes.wxml │ └── indexes.wxss ├── input │ ├── input.js │ ├── input.json │ ├── input.wxml │ └── input.wxss ├── line │ ├── line.js │ ├── line.json │ ├── line.wxml │ └── line.wxss ├── list │ ├── list.js │ ├── list.json │ ├── list.wxml │ └── list.wxss ├── loading │ ├── loading.js │ ├── loading.json │ ├── loading.wxml │ └── loading.wxss ├── modal │ ├── modal.js │ ├── modal.json │ ├── modal.wxml │ └── modal.wxss ├── page │ ├── page.js │ ├── page.json │ ├── page.wxml │ └── page.wxss ├── radio │ ├── radio.js │ ├── radio.json │ ├── radio.wxml │ └── radio.wxss ├── region │ ├── region.js │ ├── region.json │ ├── region.wxml │ └── region.wxss ├── search │ ├── search.js │ ├── search.json │ ├── search.wxml │ └── search.wxss ├── size │ ├── size.js │ ├── size.json │ ├── size.wxml │ └── size.wxss ├── swiper │ ├── swiper.js │ ├── swiper.json │ ├── swiper.wxml │ └── swiper.wxss ├── switch │ ├── switch.js │ ├── switch.json │ ├── switch.wxml │ └── switch.wxss ├── tab │ ├── tab.js │ ├── tab.json │ ├── tab.wxml │ └── tab.wxss ├── textarea │ ├── textarea.js │ ├── textarea.json │ ├── textarea.wxml │ └── textarea.wxss ├── top │ ├── top.js │ ├── top.json │ ├── top.wxml │ └── top.wxss └── upload │ ├── upload.js │ ├── upload.json │ ├── upload.wxml │ └── upload.wxss ├── project.config.json └── sitemap.json /README.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | 4 |

5 | 6 | # GUI 7 | GUI 一款基于小程序规范的组件库,简单、易用、可扩展 8 | 9 | ![GUI-QRCODE](https://github.com/Gensp/GUI/blob/c30e536ae8be5fcedab835020076122a06a888b1/qrcode.jpg) 10 | 11 | 使用微信扫一扫体验小程序组件示例 12 | 13 | ## 文档 14 | 前端小哥正在整理中... 15 | 16 | ## 使用之前 17 | 在开始使用 GUI 之前,您需了解 [微信小程序自定义组件](https://developers.weixin.qq.com/miniprogram/dev/framework/custom-component/) 的相关文档 18 | 19 | ## 如何使用 20 | 到 [GitHub](https://github.com/Gensp/GUI) 下载 GUI 的代码,将组件目录 component 拷贝到自己的项目中。然后按照如下的方式使用组件,以 Input 为例,其它组件在对应的文档页查看: 21 | 22 | 1、添加所需要的组件,在引用页面的 json 中配置: 23 | 24 | ``` 25 | "usingComponents": { 26 | "g-input": "../../component/input/input" //路径根据自己项目位置配置 27 | } 28 | ``` 29 | 30 | 2、在 wxml 中使用组件: 31 | 32 | ``` 33 | 34 | 35 | ``` 36 | 37 | ## 预览所有组件 38 | 在GitHub下载代码后,直接用微信web开发者工具新建小程序打开即可。 39 | 40 | ## 更新日志 41 | v1.0.4(2019-11-25) 42 | - 新增Page、Top、Search组件 43 | - Flex布局,新增配置选项 space(间隔) 44 | 45 | v1.0.3(2019-11-21) 46 | - 新增Upload(图片上传)组件 47 | 48 | v1.0.2(2019-11-20) 49 | - 新增Grid、Clip、Fixed、Swiper、Drop、Indexes组件 50 | 51 | v1.0.1(2018-12-20) 52 | - 新增Gesture(手势)、Region(省市区)组件 53 | 54 | v1.0.0(2018-09-27) 55 | - 初始版本 56 | - 整理了一些常用基本组件,后续会慢慢再更新一些常用功能组件。 57 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | //app.js 2 | App({ 3 | onLaunch: function () { 4 | 5 | } 6 | }) -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": [ 3 | "pages/index/index", 4 | "pages/input/input", 5 | "pages/list/list", 6 | "pages/flex/flex", 7 | "pages/button/button", 8 | "pages/textarea/textarea", 9 | "pages/radio/radio", 10 | "pages/checkbox/checkbox", 11 | "pages/switch/switch", 12 | "pages/loading/loading", 13 | "pages/modal/modal", 14 | "pages/drawer/drawer", 15 | "pages/tab/tab", 16 | "pages/line/line", 17 | "pages/size/size", 18 | "pages/gui/gui", 19 | "pages/gesture/gesture", 20 | "pages/region/region", 21 | "pages/clip/clip", 22 | "pages/grid/grid", 23 | "pages/indexes/indexes", 24 | "pages/drop/drop", 25 | "pages/swiper/swiper", 26 | "pages/fixed/fixed", 27 | "pages/upload/upload", 28 | "pages/top/top", 29 | "pages/page/page", 30 | "pages/search/search" 31 | ], 32 | "window": { 33 | "backgroundTextStyle": "light", 34 | "navigationBarBackgroundColor": "#fff", 35 | "navigationBarTitleText": "GUI", 36 | "navigationBarTextStyle": "black" 37 | }, 38 | "tabBar": { 39 | "backgroundColor": "#fff", 40 | "borderStyle": "black", 41 | "color": "#999", 42 | "selectedColor": "#2ca9e1", 43 | "list": [ 44 | { 45 | "pagePath": "pages/index/index", 46 | "iconPath": "images/nav/index-default.png", 47 | "selectedIconPath": "images/nav/index-active.png", 48 | "text": "组件" 49 | }, 50 | { 51 | "pagePath": "pages/gui/gui", 52 | "iconPath": "images/nav/gui-default.png", 53 | "selectedIconPath": "images/nav/gui-active.png", 54 | "text": "GUI" 55 | } 56 | ] 57 | }, 58 | "sitemapLocation": "sitemap.json" 59 | } -------------------------------------------------------------------------------- /app.wxss: -------------------------------------------------------------------------------- 1 | /**app.wxss**/ 2 | page{ 3 | color: #333; 4 | font-size: 28rpx; 5 | background-color: #f3f4f8; 6 | } 7 | -------------------------------------------------------------------------------- /component/box/box.js: -------------------------------------------------------------------------------- 1 | // component/title/title.js 2 | Component({ 3 | 4 | externalClasses: ['g-class'], 5 | 6 | /** 7 | * 组件的属性列表 8 | */ 9 | properties: { 10 | 11 | title:{ 12 | type: String, 13 | value:'' 14 | }, 15 | 16 | //可选:border 17 | mode:{ 18 | type: String, 19 | value: '' 20 | } 21 | 22 | }, 23 | 24 | /** 25 | * 组件的方法列表 26 | */ 27 | methods: { 28 | 29 | } 30 | }) 31 | -------------------------------------------------------------------------------- /component/box/box.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /component/box/box.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{title}} 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /component/box/box.wxss: -------------------------------------------------------------------------------- 1 | /* component/title/title.wxss */ 2 | .g-box{ 3 | color: #666; 4 | } 5 | .g-title{ 6 | min-height: 48rpx; 7 | line-height: 48rpx; 8 | padding:30rpx 30rpx 10rpx; 9 | } 10 | .g-border{ 11 | position: relative; 12 | } 13 | .g-border::before, 14 | .g-border::after{ 15 | content: ''; 16 | position: absolute; 17 | z-index: 3; 18 | left: 0; 19 | width: 100%; 20 | border-bottom: 1px solid #e5e5e5; 21 | transform: scaleY(.5); 22 | } 23 | .g-border::before{ 24 | top: 0; 25 | } 26 | .g-border::after{ 27 | bottom: 0; 28 | } -------------------------------------------------------------------------------- /component/button/button.js: -------------------------------------------------------------------------------- 1 | // component/button/button.js 2 | Component({ 3 | 4 | behaviors: ['wx://form-field'], 5 | 6 | externalClasses: ['g-class'], 7 | 8 | /** 9 | * 组件的属性列表 10 | */ 11 | properties: { 12 | 13 | //按钮尺寸可选:normal、midd1e、small 14 | size:{ 15 | type: String, 16 | value: 'normal' 17 | }, 18 | 19 | //按钮类型可选:default、primary、danger 20 | type: { 21 | type: String, 22 | value: 'default' 23 | }, 24 | 25 | //圆角 26 | radius:{ 27 | type: Boolean, 28 | value: false 29 | }, 30 | 31 | //是否禁用 32 | disabled:{ 33 | type:Boolean, 34 | value: false 35 | }, 36 | 37 | //是否镂空(透明) 38 | plain:{ 39 | type: Boolean, 40 | value: false 41 | }, 42 | 43 | //微信开放能力(参造小程序button[open-type]) 44 | opentype:{ 45 | type: String, 46 | value: '' 47 | } 48 | }, 49 | 50 | /** 51 | * 组件的方法列表 52 | */ 53 | methods: { 54 | 55 | //获取用户信息(open-type为getUserInfo时生效) 56 | inGetUserInfo(event){ 57 | this.triggerEvent('getuserinfo', event); 58 | }, 59 | 60 | //获取手机号码(open-type为getPhoneNumber时生效) 61 | inGerPhoneNumber(event){ 62 | this.triggerEvent('getphonenumber', event); 63 | }, 64 | 65 | //打开授权页 66 | inOpenSetting(event){ 67 | this.triggerEvent('opensetting', event); 68 | }, 69 | 70 | //点击 71 | inTap(event){ 72 | if(this.data.disabled) return; 73 | this.triggerEvent('intap', event); 74 | }, 75 | } 76 | }) 77 | -------------------------------------------------------------------------------- /component/button/button.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /component/button/button.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 18 | 19 | 20 | 21 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /component/button/button.wxss: -------------------------------------------------------------------------------- 1 | /* component/button/button.wxss */ 2 | .g-btn{ 3 | position: relative; 4 | color: #666; 5 | background-color: #fff; 6 | border-radius: 8rpx; 7 | overflow: initial; 8 | } 9 | .g-btn-radius{ 10 | border-radius: 50px; 11 | } 12 | .g-btn-plain.g-btn-radius::after{ 13 | border-radius: 100px; 14 | } 15 | .g-btn-normal{ 16 | font-size: 28rpx; 17 | height: 88rpx; 18 | line-height: 88rpx; 19 | padding: 0 30rpx; 20 | } 21 | .g-btn-middle{ 22 | height: 68rpx; 23 | line-height: 68rpx; 24 | padding: 0 20rpx; 25 | font-size: 26rpx; 26 | } 27 | .g-btn-small{ 28 | height: 48rpx; 29 | line-height: 48rpx; 30 | padding: 0 10rpx; 31 | font-size: 24rpx; 32 | } 33 | .g-btn::after{ 34 | border: 0; 35 | border-radius: 16rpx; 36 | } 37 | .g-btn:not(.g-btn-disabled):active{ 38 | opacity: .6; 39 | } 40 | .g-btn-primary{ 41 | color: #fff; 42 | background-color: #2ca9e1; 43 | } 44 | .g-btn-danger{ 45 | color: #fff; 46 | background-color: #f05f5f; 47 | } 48 | .g-btn-plain{ 49 | background: none!important; 50 | } 51 | .g-btn-plain::after{ 52 | content: ""; 53 | width: 200%; 54 | height: 200%; 55 | position: absolute; 56 | display: block; 57 | top: 0; 58 | left: 0; 59 | border: 1px solid rgba(0,0,0, .2); 60 | transform-origin: 0 0; 61 | pointer-events: none; 62 | box-sizing: border-box; 63 | transform: scale(0.5); 64 | } 65 | .g-btn-plain.g-btn-primary{ 66 | color: #2ca9e1; 67 | } 68 | .g-btn-plain.g-btn-primary::after{ 69 | border-color: #2ca9e1; 70 | } 71 | .g-btn-plain.g-btn-danger{ 72 | color: #f05f5f; 73 | } 74 | .g-btn-plain.g-btn-danger::after{ 75 | border-color: #f05f5f; 76 | } 77 | button.g-btn-default.g-btn-disabled{ 78 | color: rgba(0,0,0, .2); 79 | background-color: rgba(255,255,255,.8); 80 | } 81 | button.g-btn-primary.g-btn-disabled{ 82 | color: rgba(255,255,255, .5); 83 | background-color: rgba(44,169,225,.8); 84 | } 85 | button.g-btn-danger.g-btn-disabled{ 86 | color: rgba(255,255,255, .5); 87 | background-color: rgba(240,95,95,.8); 88 | } 89 | button.g-btn-plain.g-btn-primary.g-btn-disabled{ 90 | color: rgba(44,169,225,.5) 91 | } 92 | button.g-btn-plain.g-btn-danger.g-btn-disabled{ 93 | color: rgba(240,95,95,.5); 94 | } 95 | button.g-btn-plain.g-btn-default.g-btn-disabled::after{ 96 | border-color: rgba(0,0,0, .1) 97 | } 98 | button.g-btn-plain.g-btn-primary.g-btn-disabled::after{ 99 | border-color: rgba(44,169,225,.5) 100 | } 101 | button.g-btn-plain.g-btn-danger.g-btn-disabled::after{ 102 | border-color: rgba(240,95,95,.5); 103 | } -------------------------------------------------------------------------------- /component/checkbox-group/checkbox-group.js: -------------------------------------------------------------------------------- 1 | // component/checkbox-group/checkbox-group.js 2 | Component({ 3 | externalClasses: ['g-class'], 4 | relations: { 5 | '../checkbox/checkbox': { 6 | type: 'child', 7 | linked() { 8 | this.activeChange(); 9 | }, 10 | linkChanged() { 11 | this.activeChange(); 12 | }, 13 | unlinked() { 14 | this.activeChange(); 15 | } 16 | } 17 | }, 18 | /** 19 | * 组件的属性列表 20 | */ 21 | properties: { 22 | active: { 23 | type: Object, 24 | value: [], 25 | observer: 'activeChange' 26 | }, 27 | }, 28 | 29 | /** 30 | * 组件的方法列表 31 | */ 32 | methods: { 33 | activeChange(val = this.data.active) { 34 | if(!val) return; 35 | let items = this.getRelationNodes('../checkbox/checkbox'); 36 | if (items.length > 0) { 37 | items.forEach(item => { 38 | const key_idx = val.indexOf(item.data.key); 39 | item.activeChange(key_idx !== -1); 40 | }); 41 | } 42 | }, 43 | 44 | emitEvent(item) { 45 | this.triggerEvent('inchange', item); 46 | } 47 | } 48 | }) 49 | -------------------------------------------------------------------------------- /component/checkbox-group/checkbox-group.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /component/checkbox-group/checkbox-group.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /component/checkbox-group/checkbox-group.wxss: -------------------------------------------------------------------------------- 1 | /* component/checkbox-group/checkbox-group.wxss */ -------------------------------------------------------------------------------- /component/checkbox/checkbox.js: -------------------------------------------------------------------------------- 1 | // component/checkbox/checkbox.js 2 | Component({ 3 | externalClasses: ['g-class'], 4 | relations: { 5 | '../checkbox-group/checkbox-group': { 6 | type: 'parent' 7 | } 8 | }, 9 | /** 10 | * z 11 | * 组件的属性列表 12 | */ 13 | properties: { 14 | //可选:default、list 15 | mode: { 16 | type: String, 17 | value: 'list' 18 | }, 19 | 20 | //索引值 21 | index: { 22 | type: Number, 23 | value: 0 24 | }, 25 | 26 | key:{ 27 | type: [Number, String], 28 | value: '' 29 | }, 30 | 31 | value: { 32 | type: String, 33 | value: '' 34 | }, 35 | 36 | //选中的颜色 37 | color: { 38 | type: String, 39 | value: '#2ca9e1' 40 | }, 41 | 42 | //是否选中 43 | checked: { 44 | type: Boolean, 45 | value: false 46 | }, 47 | 48 | //是否禁用 49 | disabled: { 50 | type: Boolean, 51 | value: false 52 | }, 53 | 54 | //可选:left、right 55 | align: { 56 | type: String, 57 | value: 'left', 58 | } 59 | }, 60 | 61 | /** 62 | * 组件的方法列表 63 | */ 64 | methods: { 65 | activeChange(active) { 66 | this.setData({ checked: active }); 67 | }, 68 | 69 | inChange(e) { 70 | const me = this; 71 | if (me.data.disabled) return; 72 | const { key } = me.data; 73 | const parent = me.getRelationNodes('../checkbox-group/checkbox-group')[0]; 74 | let { active } = parent.data; 75 | const key_idx = active.indexOf(key); 76 | if(key_idx == -1){ 77 | active.push(key); 78 | } 79 | else{ 80 | active.splice(key_idx,1); 81 | } 82 | parent ? parent.emitEvent({active}) : me.triggerEvent('inchange', {active}); 83 | } 84 | } 85 | }) 86 | -------------------------------------------------------------------------------- /component/checkbox/checkbox.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": { 4 | "g-list": "../list/list" 5 | } 6 | } -------------------------------------------------------------------------------- /component/checkbox/checkbox.wxml: -------------------------------------------------------------------------------- 1 | 2 | 20 | -------------------------------------------------------------------------------- /component/checkbox/checkbox.wxss: -------------------------------------------------------------------------------- 1 | /* component/checkbox/checkbox.wxss */ 2 | .color-gray{ 3 | color: #999; 4 | } 5 | radio{ 6 | width: 48rpx; 7 | height: 48rpx; 8 | } 9 | .g-value{ 10 | position: relative; 11 | top: 2rpx; 12 | } 13 | .g-left radio{ 14 | margin-right: 16rpx; 15 | } 16 | .g-right radio{ 17 | margin-left: 16rpx; 18 | } 19 | .radio-main{ 20 | display: flex; 21 | } 22 | .g-right .radio-main{ 23 | flex-direction: row-reverse; 24 | } -------------------------------------------------------------------------------- /component/clip/clip.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /component/clip/clip.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | {{cancelTxt}} 15 | {{scuuessTxt}} 16 | 17 | 18 | -------------------------------------------------------------------------------- /component/clip/clip.wxss: -------------------------------------------------------------------------------- 1 | /* component/clip/clip.wxss */ 2 | .g-clip-bar{ 3 | position: fixed; 4 | top: 0; 5 | left: 0; 6 | z-index: 99; 7 | width: 100%; 8 | height: 100%; 9 | background-color: #000; 10 | display: flex; 11 | flex-flow: row; 12 | flex-direction: column; 13 | } 14 | .g-clip-top{ 15 | position: relative; 16 | flex: 1; 17 | } 18 | .g-clip-bom{ 19 | position: relative; 20 | z-index: 3; 21 | height: 88rpx; 22 | color: #fff; 23 | display: flex; 24 | } 25 | .g-clip-bom > view:nth-child(1){ 26 | flex: 1; 27 | color: rgba(255,255,255, .6); 28 | } 29 | .g-clip-btn{ 30 | padding:0 30rpx; 31 | display: inline-block; 32 | height: 88rpx; 33 | line-height: 88rpx; 34 | } 35 | .g-clip-bom:after { 36 | content: ''; 37 | display: block; 38 | position: absolute; 39 | top:0; 40 | left: 0; 41 | height: 1px; 42 | width: 100%; 43 | border-bottom: 1rpx solid rgba(255,255,255, .2); 44 | transform-origin: 50% 100%; 45 | } 46 | .isIPX .g-clip-bom{ 47 | height: calc(88rpx + 34px); 48 | } 49 | .g-clip-canvas{ 50 | position: fixed; 51 | top: 0; 52 | left: 100%; 53 | } 54 | .g-clip-box{ 55 | position: absolute; 56 | width: calc(100% - 64rpx); 57 | height: calc(100vw - 64rpx); 58 | left: 50%; 59 | top: 50%; 60 | transform: translate(-50%, -50%); 61 | } 62 | .g-clip-area{ 63 | position: absolute; 64 | z-index: 3; 65 | width: 100%; 66 | height: 100%; 67 | border:2rpx solid #fff; 68 | box-sizing: border-box; 69 | box-shadow: 0 0 0 2000rpx rgba(0,0,0, .75) 70 | } 71 | .g-clip-img{ 72 | width: 100%; 73 | height: 100%; 74 | } 75 | .g-clip-arrow::before, 76 | .g-clip-arrow::after{ 77 | content: ''; 78 | position: absolute; 79 | display: block; 80 | width: 32rpx; 81 | height: 32rpx; 82 | } 83 | .g-clip-arrow.top::before{ 84 | left: -6rpx; 85 | top: -6rpx; 86 | border-top: 6rpx solid #fff; 87 | border-left: 6rpx solid #fff; 88 | } 89 | .g-clip-arrow.top::after{ 90 | right: -6rpx; 91 | top: -6rpx; 92 | border-top: 6rpx solid #fff; 93 | border-right: 6rpx solid #fff; 94 | } 95 | .g-clip-arrow.bom::before{ 96 | left: -6rpx; 97 | bottom: -6rpx; 98 | border-left: 6rpx solid #fff; 99 | border-bottom: 6rpx solid #fff; 100 | } 101 | .g-clip-arrow.bom::after{ 102 | right: -6rpx; 103 | bottom: -6rpx; 104 | border-right: 6rpx solid #fff; 105 | border-bottom: 6rpx solid #fff; 106 | } 107 | .animate-img{ 108 | transition: all .2s ease-in-out; 109 | } -------------------------------------------------------------------------------- /component/col/col.js: -------------------------------------------------------------------------------- 1 | // component/col/col.js 2 | Component({ 3 | externalClasses: ['g-class'], 4 | 5 | relations: { 6 | '../flex/flex': { 7 | type: 'parent', 8 | linked() { 9 | this.spaceChange(); 10 | }, 11 | }, 12 | 13 | '../grid/grid': { 14 | type: 'parent', 15 | linked() { 16 | this.modeChange(); 17 | }, 18 | } 19 | }, 20 | 21 | /** 22 | * 组件的属性列表 23 | */ 24 | properties: { 25 | span: { 26 | type: Number, 27 | value: 12 28 | }, 29 | 30 | //偏移量 31 | offset: { 32 | type: Number, 33 | value: 0 34 | } 35 | }, 36 | 37 | /** 38 | * 组件的初始数据 39 | */ 40 | data: { 41 | gridmode:'', 42 | //间隔,单位rpx 43 | space: 0 44 | }, 45 | 46 | /** 47 | * 组件的方法列表 48 | */ 49 | methods: { 50 | //间隔 51 | spaceChange(){ 52 | let items = this.getRelationNodes('../flex/flex'); 53 | this.setData({ 54 | 'space': items[0].data.space 55 | }) 56 | }, 57 | 58 | //宫格布局mode参数 59 | modeChange(mode){ 60 | let items = this.getRelationNodes('../grid/grid'); 61 | console.log(items[0].data.mode) 62 | if (items[0].data.mode){ 63 | this.setData({ 64 | 'gridmode': items[0].data.mode 65 | }) 66 | return; 67 | } 68 | }, 69 | } 70 | }) 71 | -------------------------------------------------------------------------------- /component/col/col.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /component/col/col.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /component/col/col.wxss: -------------------------------------------------------------------------------- 1 | /* component/col/col.wxss */ 2 | .g-col{ 3 | position: relative; 4 | float:left; 5 | box-sizing: border-box; 6 | } 7 | .g-col-12 { 8 | width: 100%; 9 | } 10 | .g-col-11 { 11 | width: 91.66666667%; 12 | } 13 | .g-col-10 { 14 | width: 83.33333333%; 15 | } 16 | .g-col-9 { 17 | width: 75%; 18 | } 19 | .g-col-8 { 20 | width: 66.66666667%; 21 | } 22 | .g-col-7 { 23 | width: 58.33333333%; 24 | } 25 | .g-col-6 { 26 | width: 50%; 27 | } 28 | .g-col-5 { 29 | width: 41.66666667%; 30 | } 31 | .g-col-4 { 32 | width: 33.33333333%; 33 | } 34 | .g-col-3 { 35 | width: 25%; 36 | } 37 | .g-col-2 { 38 | width: 16.66666667%; 39 | } 40 | .g-col-1 { 41 | width: 8.33333333%; 42 | } 43 | .g-offset-12 { 44 | margin-left: 100%; 45 | } 46 | .g-offset-11 { 47 | margin-left: 91.66666667%; 48 | } 49 | .g-offset-10 { 50 | margin-left: 83.33333333%; 51 | } 52 | .g-offset-9 { 53 | margin-left: 75%; 54 | } 55 | .g-offset-8 { 56 | margin-left: 66.66666667%; 57 | } 58 | .g-offset-7 { 59 | margin-left: 58.33333333%; 60 | } 61 | .g-offset-6 { 62 | margin-left: 50%; 63 | } 64 | .g-offset-5 { 65 | margin-left: 41.66666667%; 66 | } 67 | .g-offset-4 { 68 | margin-left: 33.33333333%; 69 | } 70 | .g-offset-3 { 71 | margin-left: 25%; 72 | } 73 | .g-offset-2 { 74 | margin-left: 16.66666667%; 75 | } 76 | .g-offset-1 { 77 | margin-left: 8.33333333%; 78 | } 79 | .g-grid-border::after{ 80 | content: ''; 81 | display: block; 82 | position: absolute; 83 | top: 0; 84 | left: 0; 85 | width: 200%; 86 | height: 200%; 87 | -webkit-transform-origin: 0 0; 88 | transform-origin: 0 0; 89 | box-sizing: border-box; 90 | pointer-events: none; 91 | border-bottom:1px solid #ddd; 92 | border-left: 1px solid #ddd; 93 | transform: scale(.5); 94 | margin-left: -1px; 95 | } -------------------------------------------------------------------------------- /component/drawer/drawer.js: -------------------------------------------------------------------------------- 1 | // component/drawer/drawer.js 2 | Component({ 3 | externalClasses: ['g-class', 'g-class-mask'], 4 | /** 5 | * 组件的属性列表 6 | */ 7 | properties: { 8 | 9 | show: { 10 | type: Boolean, 11 | value: 'false' 12 | }, 13 | 14 | //可选:top、right、bottom、left 15 | position: { 16 | type: String, 17 | value: 'left' 18 | }, 19 | //position为left、right时生效 20 | width: { 21 | type: String, 22 | value: '' 23 | }, 24 | //position为top、bottom时生效 25 | height: { 26 | type: String, 27 | value: '' 28 | }, 29 | //显隐动画 30 | animate: { 31 | type: Boolean, 32 | value: true 33 | } 34 | }, 35 | 36 | /** 37 | * 组件的初始数据 38 | */ 39 | data: { 40 | isIPX: wx.getSystemInfoSync().model.indexOf('iPhone X') == -1 ? '' : 'isIPX', 41 | animateClass: '' 42 | }, 43 | /** 44 | * 组件的方法列表 45 | */ 46 | methods: { 47 | //点击遮罩 48 | inTapMask(e) { 49 | this.triggerEvent('inmask'); 50 | }, 51 | 52 | inTest() { 53 | const me = this; 54 | me.setData({ 55 | 'show': true 56 | }) 57 | setTimeout(function () { 58 | me.setData({ 59 | 'animateClass': 'g-drawer-show' 60 | }) 61 | }, 50) 62 | 63 | console.log(123) 64 | }, 65 | } 66 | }) 67 | -------------------------------------------------------------------------------- /component/drawer/drawer.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /component/drawer/drawer.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /component/drawer/drawer.wxss: -------------------------------------------------------------------------------- 1 | /* component/drawer/drawer.wxss */ 2 | .g-mask, 3 | .g-fixed-bar{ 4 | visibility:hidden; 5 | position: fixed; 6 | } 7 | .g-mask{ 8 | top: 0; 9 | left: 0; 10 | z-index: 49; 11 | width: 100%; 12 | height: 100%; 13 | background-color: rgba(0, 0, 0, .5); 14 | } 15 | .g-fixed-bar{ 16 | z-index: 50; 17 | box-sizing: border-box; 18 | background-color: #fff; 19 | transition: transform ease 0s; 20 | } 21 | .animate.g-fixed-bar{ 22 | transition: transform ease .3s; 23 | } 24 | .g-mask-show, 25 | .g-drawer-show{ 26 | visibility: initial; 27 | } 28 | .g-drawer-top{ 29 | top: 0; 30 | left: 0; 31 | width: 100%; 32 | height: 60%; 33 | transform: translate3d(0, -100%, 0); 34 | } 35 | .g-drawer-right{ 36 | top: 0; 37 | right: 0; 38 | width: 60%; 39 | height: 100%; 40 | transform: translate3d(100%, 0, 0); 41 | } 42 | .g-drawer-bottom{ 43 | bottom: 0; 44 | left: 0; 45 | width: 100%; 46 | height: 60%; 47 | transform: translate3d(0, 100%, 0); 48 | } 49 | .g-drawer-bottom.isIPX{ 50 | padding-bottom: 34px; 51 | } 52 | .g-drawer-left{ 53 | top: 0; 54 | left: 0; 55 | width: 60%; 56 | height: 100%; 57 | transform: translate3d(-100%, 0, 0); 58 | } 59 | .g-drawer-show{ 60 | transform: translate3d(0, 0, 0); 61 | } -------------------------------------------------------------------------------- /component/drop/drop.js: -------------------------------------------------------------------------------- 1 | // component/drop/drop.js 2 | Component({ 3 | externalClasses: ['g-class'], 4 | 5 | /** 6 | * 组件的属性列表 7 | */ 8 | properties: { 9 | imgurl:{ 10 | type: String, 11 | value: '' 12 | }, 13 | 14 | dataJson:{ 15 | type: Object, 16 | value: {} 17 | }, 18 | 19 | key:{ 20 | type: String, 21 | value: '' 22 | }, 23 | 24 | //容器宽度 25 | boxW:{ 26 | type: Number, 27 | value: '' 28 | }, 29 | 30 | //容器高度 31 | boxH: { 32 | type: Number, 33 | value: '' 34 | }, 35 | 36 | //选中状态 37 | active:{ 38 | type: Boolean, 39 | value: false 40 | } 41 | }, 42 | 43 | /** 44 | * 组件的初始数据 45 | */ 46 | data: { 47 | data:{} 48 | }, 49 | 50 | ready(){ 51 | this.initImg(); 52 | }, 53 | 54 | /** 55 | * 组件的方法列表 56 | */ 57 | methods: { 58 | 59 | //初始化图片 60 | initImg(){ 61 | const me = this; 62 | let { imgurl, boxW, boxH } = me.data; 63 | if (me.data.dataJson.rotate){ 64 | me.setData({ 65 | 'data': me.data.dataJson 66 | }) 67 | me.triggerEvent('init', me.data.dataJson); 68 | } 69 | else{ 70 | //获取图片信息 71 | wx.getImageInfo({ 72 | src: imgurl, 73 | success(res) { 74 | let data = { 75 | active: me.data.active, 76 | key: me.data.key, 77 | imgurl: imgurl, 78 | width: res.width, 79 | height: res.height, 80 | //定位居中 81 | left: boxW / 2 - res.width / 2, 82 | top: boxH / 2 - res.height / 2, 83 | scale: 1, //缩放 84 | oScale: 1, //缩放方向 85 | rotate: 1, //角度 86 | } 87 | 88 | //中心点 89 | data.cx = data.left + data.width / 2, 90 | data.cy = data.top + data.height / 2; 91 | 92 | me.setData({ 93 | 'data': data 94 | }) 95 | me.triggerEvent('init', data); 96 | } 97 | }) 98 | } 99 | 100 | }, 101 | 102 | //图片开始移动 103 | imgTouchStart(e) { 104 | const me = this; 105 | let { data, active } = me.data; 106 | 107 | data.lx = e.touches[0].clientX; 108 | data.ly = e.touches[0].clientY; 109 | 110 | me.setData({ 111 | 'data': data 112 | }) 113 | me.triggerEvent('imgStart', data); 114 | }, 115 | //图片移动中 116 | imgTouchMove(e) { 117 | const me = this; 118 | let { data, active } = me.data; 119 | 120 | data._lx = e.touches[0].clientX; 121 | data._ly = e.touches[0].clientY; 122 | 123 | data.left += data._lx - data.lx; 124 | data.top += data._ly - data.ly; 125 | data.cx += data._lx - data.lx; 126 | data.cy += data._ly - data.ly; 127 | 128 | data.lx = e.touches[0].clientX; 129 | data.ly = e.touches[0].clientY; 130 | 131 | me.setData({ 132 | 'data': data 133 | }) 134 | me.triggerEvent('imgMove', data); 135 | }, 136 | //图片移动结束 137 | imgTouchEnd(e) { 138 | const me = this; 139 | let { data, active } = me.data; 140 | 141 | me.triggerEvent('imgEnd', data); 142 | }, 143 | 144 | //缩放、旋转开始 145 | inTouchStart(e) { 146 | const me = this; 147 | console.log(e) 148 | let { data, active } = me.data; 149 | 150 | //获取作为移动前角度的坐标 151 | data.tx = e.touches[0].clientX; 152 | data.ty = e.touches[0].clientY; 153 | //移动前的角度 154 | data.angleBefore = me.inCalcAngle(data.cx, data.cy, data.tx, data.ty); 155 | //获取图片半径 156 | data.radius = me.inGetRadius(data.cx, data.cy, data.left, data.top); 157 | 158 | }, 159 | //缩放、旋转中 160 | inTouchMove(e) { 161 | const me = this; 162 | let { data, active } = me.data; 163 | 164 | //记录移动后的位置 165 | data._tx = e.touches[0].clientX; 166 | data._ty = e.touches[0].clientY; 167 | 168 | //移动的点到圆心的距离 169 | data.moveDistance = me.inGetRadius(data.cx, data.cy, data._tx, data._ty+10); 170 | 171 | data.scale = data.moveDistance / data.radius; 172 | data.oScale = 1 / data.scale; 173 | 174 | 175 | //移动后位置的角度 176 | data.angleAfter = me.inCalcAngle(data.cx, data.cy, data._tx, data._ty); 177 | //角度差 178 | data.angleDiffer = data.angleAfter - data.angleBefore; 179 | 180 | //叠加的角度差 181 | data.rotate += data.angleDiffer; 182 | data.angle = data.rotate; //赋值 183 | 184 | //用过移动后的坐标赋值为移动前坐标 185 | data.tx = e.touches[0].clientX; 186 | data.ty = e.touches[0].clientY; 187 | data.angleBefore = me.inCalcAngle(data.cx, data.cy, data.tx, data.ty); 188 | 189 | this.setData({ 190 | 'data': data 191 | }) 192 | }, 193 | //缩放、旋转结束 194 | inTouchEnd(e) { 195 | console.log(e) 196 | }, 197 | 198 | //删除 199 | inDelDrop(e){ 200 | this.triggerEvent('indel', this.data.data); 201 | }, 202 | 203 | //获取半径 204 | inGetRadius(cx, cy, pointer_x, pointer_y) { 205 | var ox = pointer_x - cx; 206 | var oy = pointer_y - cy; 207 | return Math.sqrt( 208 | ox * ox + oy * oy 209 | ); 210 | }, 211 | 212 | /* 213 | *参数1和2为图片圆心坐标 214 | *参数3和4为手点击的坐标 215 | *返回值为手点击的坐标到圆心的角度 216 | */ 217 | inCalcAngle (cx, cy, pointer_x, pointer_y) { 218 | var ox = pointer_x - cx; 219 | var oy = pointer_y - cy; 220 | var to = Math.abs(ox / oy); 221 | var angle = Math.atan(to) / (2 * Math.PI) * 360; 222 | // console.log("ox.oy:", ox, oy) 223 | if (ox < 0 && oy < 0)//相对在左上角,第四象限,js中坐标系是从左上角开始的,这里的象限是正常坐标系 224 | { 225 | angle = -angle; 226 | } else if (ox <= 0 && oy >= 0)//左下角,3象限 227 | { 228 | angle = -(180 - angle) 229 | } else if (ox > 0 && oy < 0)//右上角,1象限 230 | { 231 | angle = angle; 232 | } else if (ox > 0 && oy > 0)//右下角,2象限 233 | { 234 | angle = 180 - angle; 235 | } 236 | return angle; 237 | }, 238 | } 239 | }) 240 | -------------------------------------------------------------------------------- /component/drop/drop.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /component/drop/drop.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /component/drop/drop.wxss: -------------------------------------------------------------------------------- 1 | /* component/drop/drop.wxss */ 2 | .opacity{ 3 | opacity: .7; 4 | } 5 | .item-drop{ 6 | position: absolute; 7 | z-index: 10; 8 | left: 50%; 9 | top: 50%; 10 | transform-origin: center; 11 | } 12 | .drop-img{ 13 | transform-origin: center; 14 | border:1px solid transparent; 15 | } 16 | .drop-icon{ 17 | position: absolute; 18 | width: 40rpx; 19 | height: 40rpx; 20 | background-position: center; 21 | background-size: cover; 22 | background-color: rgba(44,169,225, .95); 23 | border-radius: 50%; 24 | transform-origin: center; 25 | } 26 | .drop-active{ 27 | border-color: #2ca9e1; 28 | } 29 | .drop-close{ 30 | top: -20rpx; 31 | left: -20rpx; 32 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAMAAAC5zwKfAAAArlBMVEUAAAAsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeH////c8fo4ruPh8/s1reLa8PozrOLD5/c7r+O+5fa44vXj9PvR7PnL6viW1PD7/v+v3vSKz+7m9fur3fOp3PNcvehQuOb0bZMCAAAAInRSTlMAC+Dr9fJ3bkgfFgjbnU/Wx724qJZZAv7j0ZFcKSQU5UZFArp3FQAAAqFJREFUWMPFmYl2qjAURSODIEVwrGNte9AipdZOb/r/H3tWeC+rcjMAWav7A7bHDDfJhSnY3HuTYWy7cOxwMZx49xvWnE60XMxwwWyxjDpNbNf+2IEAZ+xf1w3nWZBieXViXnVtKLG7V7q+qQUtrKmWrjeCNqOe2rdyUQN3pRq9PmrSl45kMEBtBoFk+EI0IBQO5PoWjbhd076bORoyvyHHL0RjwoCY3wFaMKjOdR+t6FfWM1qyulgwLlrifl08I7Rm9KW+wABT7utYMIDFS24XRuj+D2jDCPa/iB4IXo8/M4jIXpLkHRW88nyzKF+SJNudyLdPThCjWJyFPgiOyacxFfloIfyzcAw6oShjWvj2qDI+T4kDgtljYUxF+R6o33I+pyUCTWnc0fmec1BEJ+EEAsiM2ZbnI5ichCGgnzHd8nwUIWMBAFVGMh9NwBeNRsZd6cshxOf7WJ1x96DKB3R56Vdk5L5cfhQMAb2MPJ+MIYuhZTz+3uv4EDMbaiNH5YPNXKiN+j64DBoc3grfSwolzIGaWSF8y6FGYwyRHZMyYQb1X7ZAQNQXvh4Vk7IAR1ifuVGVMVYu7LTcv38OfBdKGAq3XrUePOoY+7LicLl/nzTGsSssX0R90cnoSwtsfllfnpTGgLFQNx837jMICPkhReUjxqw0phAfUpE4H/9/uhkj4UGP/JnwSTLyg56NaR9Pom8ciy9Le0mOYs+8o4ovvs7xfCLjD+o6J75wcp/I+IoKnuRK/Ete/T4OH+SV2Pyl3fyzwvzDx/zTzPzj0fzz1vwD3HyLoH0Tw3ibhWQ9b+hbC1tVMRoQ9yQ94SbNtI203bdETZaqxmlUryEZmW6ZGm7qmm47G26MG27df//HhZLg7vz5wwEcOx5OvLuAyfkL6cmcPY2q2W0AAAAASUVORK5CYII=) 33 | } 34 | .drop-scale{ 35 | bottom:-20rpx; 36 | right: -20rpx; 37 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAMAAAC5zwKfAAAAyVBMVEUAAAAsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeEsqeH////v+f2l2/OT0/BQuOZGtOUzrOLU7vnP7Pkvq+Lr9/zY7/rD5/e34vWh2fKb1/Fmwen2/P7k9Pus3vRgvulVuudMtuby+v3I6fe+5faN0e85r+OCzO13yOze8ftpwuraYi5fAAAAInRSTlMAC9/rRxT18ncfnNuV49a9qFkmBwK4bFxQ0HD+yMaQTdK3yqRkkAAAApZJREFUWMPF2W1XokAUwPHhGYRAUxTtafdOqWmpuZpWq7X7/T/UKgfjMKMwd5xz9v+qV79DQcPMhVRkme0gCg0HbEPvRkHbtIh82t1t9wqYrrq3d5qM1jLrNpzIrpst7MX1dChN72kYzjWgMsMVJhs6CKU3hDjvJwgXe9VexwFETqeCa9YAWa1Z5lk3gO7GKvnz+SCR753yLi9AqotLjCcvWj5I51u817yGM7rm73UNzqrGPc9wZh3mgXHOBZ3iwxPDdxNa6HklKMaF9QXyKNMYBGvknqaXgH1RUM/XRxc4cP7ZT5t/gXDuwdMMHpwBPkPLwDbwIJ084sU2SWvpDHg/khT1VgqawICLx7mkaKZgnQXpFmZ7cYQW6+ktsTlwDfA7FZ+QoK3twAQ4cACZiL7GZAcGR0HJawx2oH8ChKmE6BNiwTEwF8c40coeGu6mpH3gRZO4R8AhFETMnXH5pX+63MB343ShQL0KIihtjFwoIhJCeVO6HCDAkBhQ0Rvq4TaIA0pzCCiO2KpBQ/WvrKsFDfJDLRiSSC0YoXZdX8vRoPJfzxX3hpTS9wrRJSYOpItcfHqZrfnlywLx+nvx/Q2yNpQu+QWW+AhxXhBfKV1AMR+7F37Zi/eZ+LD78chLKgG8ODwFJsyLHifyoK1lWxG0+Dw8CtazzRKuh4PIgyazncOJPKi38g0nqtdUhE8W7DFbYqT4MWNAQ2M27ViRMqDLHCtQbXhQ15iDj1Crv7/2rdYTDmwwRzORtmN6aMGCsczhcUXZmMMj9ni7/cN4UzjUUX0AVz4iUD/EUD9mUT8I4vNCGS/0lA/TSmoGWC9okvIS3EAyIZV5sbgXe4qHuqrHzooH44pH9///40Lx84cNYBuhyOePf+ELncYW90RbAAAAAElFTkSuQmCC) 38 | } -------------------------------------------------------------------------------- /component/fixed/fixed.js: -------------------------------------------------------------------------------- 1 | // component/fixed/fixed.js 2 | Component({ 3 | externalClasses: ['g-class'], 4 | 5 | observers:{ 6 | 'scrollTop'(val){ 7 | this.inSetFixedClass(); 8 | } 9 | }, 10 | 11 | /** 12 | * 组件的属性列表 13 | */ 14 | properties: { 15 | scrollTop:{ 16 | type: [String, Number], 17 | value: 0 18 | } 19 | }, 20 | 21 | /** 22 | * 组件的初始数据 23 | */ 24 | data: { 25 | fixedData:null, 26 | toggleClass:'' 27 | }, 28 | 29 | ready(){ 30 | this.inGetFixedBox('#fixed-bar'); 31 | }, 32 | 33 | /** 34 | * 组件的方法列表 35 | */ 36 | methods: { 37 | 38 | //获取指定节点相关参数 39 | inGetQuery(obj, call){ 40 | const query = this.createSelectorQuery(); 41 | query.select(obj).boundingClientRect(); 42 | query.selectViewport().scrollOffset(); 43 | query.exec(function (res) { 44 | call(res[0]); 45 | }); 46 | }, 47 | 48 | //获取吸顶容器节点参数 49 | inGetFixedBox(obj){ 50 | const me = this; 51 | me.inGetQuery(obj, res=>{ 52 | console.log(res) 53 | me.setData({ 54 | 'fixedData':res 55 | }) 56 | }) 57 | }, 58 | 59 | //设置吸顶容器class 60 | inSetFixedClass(){ 61 | const { scrollTop, fixedData } = this.data; 62 | if (!fixedData) return; 63 | if (!this.timeOut){ 64 | //避免频繁setData造成卡顿,控制50ms执行一次 65 | this.timeOut = setTimeout(()=>{ 66 | if (scrollTop >= fixedData.top){ 67 | this.setData({ 68 | 'toggleClass': 'fixed' 69 | }) 70 | } 71 | else{ 72 | this.setData({ 73 | 'toggleClass': '' 74 | }) 75 | } 76 | this.timeOut = undefined; 77 | },50) 78 | } 79 | }, 80 | } 81 | }) 82 | -------------------------------------------------------------------------------- /component/fixed/fixed.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /component/fixed/fixed.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /component/fixed/fixed.wxss: -------------------------------------------------------------------------------- 1 | /* component/fixed/fixed.wxss */ 2 | .fixed{ 3 | position: fixed; 4 | width: 100%; 5 | left: 0; 6 | top: 0; 7 | } -------------------------------------------------------------------------------- /component/flex/flex.js: -------------------------------------------------------------------------------- 1 | // component/flex/flex.js 2 | Component({ 3 | externalClasses: ['g-class'], 4 | 5 | relations: { 6 | '../col/col': { 7 | type: 'child' 8 | } 9 | }, 10 | 11 | /** 12 | * 组件的属性列表 13 | */ 14 | properties: { 15 | //间隔,单位rpx 16 | space:{ 17 | type: [String, Number], 18 | value: 0 19 | } 20 | } 21 | }) 22 | -------------------------------------------------------------------------------- /component/flex/flex.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /component/flex/flex.wxml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /component/flex/flex.wxss: -------------------------------------------------------------------------------- 1 | /* component/flex/flex.wxss */ 2 | .g-flex::after{ 3 | content:""; 4 | display:table; 5 | clear:both; 6 | } -------------------------------------------------------------------------------- /component/gesture/gesture.js: -------------------------------------------------------------------------------- 1 | // component/gesture/gesture.js 2 | let touchStart, touchEnd; 3 | Component({ 4 | externalClasses: ['g-class'], 5 | options: { 6 | multipleSlots: true // 在组件定义时的选项中启用多slot支持 7 | }, 8 | /** 9 | * 组件的属性列表 10 | */ 11 | properties: { 12 | //关键字 13 | key:{ 14 | type: String, 15 | value: '' 16 | }, 17 | //滑动方向可选:left || right 18 | direction:{ 19 | type: String, 20 | value: 'left' 21 | }, 22 | //状态 23 | state:{ 24 | type: Boolean, 25 | value: false 26 | }, 27 | //移动步长(单位rpx) 28 | stepx:{ 29 | type: Number, 30 | value: 200 31 | } 32 | }, 33 | 34 | /** 35 | * 组件的初始数据 36 | */ 37 | data: { 38 | 39 | }, 40 | 41 | /** 42 | * 组件的方法列表 43 | */ 44 | methods: { 45 | 46 | //滑动开始 47 | inTouchStart(e) { 48 | const me = this; 49 | if (e.changedTouches.length > 0) { 50 | touchStart = e.changedTouches[0].pageX; 51 | } 52 | }, 53 | 54 | //滑动结束 55 | inTouchEnd(e) { 56 | const me = this; 57 | const getData = e.currentTarget.dataset; 58 | touchEnd = e.changedTouches[0].pageX; 59 | const { key, direction } = me.data; 60 | 61 | const parms = { state: me.data.state, key: key }; 62 | 63 | //重置 64 | function InReset(){ 65 | me.setData({ 66 | 'state': false 67 | }) 68 | me.triggerEvent('inreset', parms); 69 | } 70 | 71 | //左滑 72 | if (direction == 'left') { 73 | if (touchStart - touchEnd > 30) { 74 | me.triggerEvent('inleft', parms); 75 | } 76 | else { 77 | InReset(); 78 | } 79 | } 80 | //右滑 81 | else if (direction == 'right'){ 82 | if ( touchEnd - touchStart > 30) { 83 | me.triggerEvent('inright', parms); 84 | } 85 | else{ 86 | InReset(); 87 | } 88 | } 89 | }, 90 | 91 | } 92 | }) 93 | -------------------------------------------------------------------------------- /component/gesture/gesture.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /component/gesture/gesture.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /component/gesture/gesture.wxss: -------------------------------------------------------------------------------- 1 | /* component/gesture/gesture.wxss */ 2 | .slide-box{ 3 | overflow: hidden; 4 | } 5 | .slide-bar{ 6 | position: relative; 7 | transition: transform .2s ease-in-out; 8 | } 9 | .slide-bar.left .slide-right, 10 | .slide-bar.right .slide-left{ 11 | position: absolute; 12 | top: 0; 13 | height: 100%; 14 | } 15 | .slide-bar.left .slide-right{ 16 | right: 0; 17 | transform: translateX(100%); 18 | } 19 | .slide-bar.right .slide-left{ 20 | left: 0; 21 | transform: translateX(-100%); 22 | } -------------------------------------------------------------------------------- /component/grid/grid.js: -------------------------------------------------------------------------------- 1 | // component/grid/grid.js 2 | Component({ 3 | 4 | externalClasses: ['g-class'], 5 | 6 | relations: { 7 | '../col/col': { 8 | type: 'child', 9 | } 10 | }, 11 | 12 | /** 13 | * 组件的属性列表 14 | */ 15 | properties: { 16 | //对齐方式 tl、tc、tr 17 | align: { 18 | type: String, 19 | value: "tc" 20 | }, 21 | 22 | //可选:border 23 | mode: { 24 | type: String, 25 | value: '' 26 | } 27 | }, 28 | 29 | /** 30 | * 组件的初始数据 31 | */ 32 | data: { 33 | 34 | }, 35 | 36 | /** 37 | * 组件的方法列表 38 | */ 39 | methods: { 40 | 41 | } 42 | }) 43 | -------------------------------------------------------------------------------- /component/grid/grid.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /component/grid/grid.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /component/grid/grid.wxss: -------------------------------------------------------------------------------- 1 | /* component/grid/grid.wxss */ 2 | .g-grid{ 3 | position: relative; 4 | } 5 | .g-border::before{ 6 | content: ''; 7 | display: block; 8 | position: absolute; 9 | left: 0; 10 | top: 0; 11 | width: 100%; 12 | height: 1px; 13 | box-sizing: border-box; 14 | border-bottom:1px solid #ddd; 15 | transform: scaleY(.5); 16 | } 17 | .g-grid::after{ 18 | content:""; 19 | display:table; 20 | clear:both; 21 | } 22 | .g-grid.tc{ 23 | text-align: center 24 | } 25 | .g-grid.tr{ 26 | text-align: right 27 | } -------------------------------------------------------------------------------- /component/indexes-item/indexes-item.js: -------------------------------------------------------------------------------- 1 | // component/indexes-item/indexes-item.js 2 | Component({ 3 | 4 | externalClasses: ['g-class'], 5 | 6 | /** 7 | * 组件的属性列表 8 | */ 9 | properties: { 10 | name:{ 11 | type: String, 12 | value: '' 13 | } 14 | }, 15 | 16 | relations: { 17 | '../indexes/indexes': { 18 | type: 'parent' 19 | } 20 | }, 21 | 22 | /** 23 | * 组件的初始数据 24 | */ 25 | data: { 26 | top: 0, 27 | }, 28 | 29 | /** 30 | * 组件的方法列表 31 | */ 32 | methods: { 33 | updateDataChange() { 34 | const query = wx.createSelectorQuery().in(this); 35 | query.select('.g-indexes-item').boundingClientRect((res) => { 36 | this.setData({ 37 | top: res.top 38 | }) 39 | }).exec() 40 | } 41 | } 42 | }) 43 | -------------------------------------------------------------------------------- /component/indexes-item/indexes-item.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /component/indexes-item/indexes-item.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{name}} 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /component/indexes-item/indexes-item.wxss: -------------------------------------------------------------------------------- 1 | /* component/indexes-item/indexes-item.wxss */ 2 | .g-indexes-item-title{ 3 | height: 80rpx; 4 | line-height: 80rpx; 5 | padding:0 30rpx; 6 | } 7 | .g-indexes-item-box{ 8 | line-height: 88rpx; 9 | padding:0 30rpx; 10 | background-color: #fff; 11 | } -------------------------------------------------------------------------------- /component/indexes/indexes.js: -------------------------------------------------------------------------------- 1 | // component/indexes/indexes.js 2 | Component({ 3 | 4 | externalClasses: ['g-class'], 5 | 6 | /** 7 | * 组件的属性列表 8 | */ 9 | properties: { 10 | //索引数组 11 | listData:{ 12 | type: Object, 13 | value: [] 14 | }, 15 | }, 16 | 17 | relations: { 18 | '../indexes-item/indexes-item': { 19 | type: 'child', 20 | linked() { 21 | this.itemDataChange(); 22 | }, 23 | linkChanged() { 24 | this.itemDataChange(); 25 | }, 26 | unlinked() { 27 | this.itemDataChange(); 28 | } 29 | } 30 | }, 31 | 32 | /** 33 | * 组件的初始数据 34 | */ 35 | data: { 36 | scrollTop: 0, 37 | indexesDom: null, 38 | indexesActive: { 39 | state: false, 40 | value: '' 41 | }, 42 | indexesData: [] 43 | }, 44 | 45 | ready(){ 46 | this.inGetIndexesBox('.g-indexes-bar'); 47 | }, 48 | 49 | /** 50 | * 组件的方法列表 51 | */ 52 | methods: { 53 | //获取指定节点相关参数 54 | inGetQuery(obj, call) { 55 | const query = this.createSelectorQuery(); 56 | query.select(obj).boundingClientRect(); 57 | query.selectViewport().scrollOffset(); 58 | query.exec(function (res) { 59 | call(res[0]); 60 | }); 61 | }, 62 | 63 | //获取容器节点参数 64 | inGetIndexesBox(obj) { 65 | const me = this; 66 | me.inGetQuery(obj, res => { 67 | me.setData({ 68 | 'indexesDom': res 69 | }) 70 | //console.log(res) 71 | }) 72 | }, 73 | 74 | //获取字组件列表Data 75 | itemDataChange(){ 76 | const childItems = this.getRelationNodes('../indexes-item/indexes-item'); 77 | let indexesData = []; 78 | childItems.forEach(item=>{ 79 | indexesData.push(item.data.name); 80 | item.updateDataChange(); 81 | }) 82 | this.setData({ 83 | 'indexesData': indexesData 84 | }) 85 | }, 86 | 87 | //Touch Move 88 | inTouchMove(e) { 89 | if (!this.timeOut){ 90 | //避免频繁setData造成卡顿,控制50ms执行一次 91 | this.timeOut = setTimeout(()=>{ 92 | const { indexesData, indexesDom } = this.data; 93 | this.mY = e.touches[0].clientY - indexesDom.top; 94 | let idx = Math.round(this.mY / (indexesDom.height / indexesData.length)) - 1; 95 | if (idx > indexesData.length-1) idx = indexesData.length - 1; 96 | else if (idx < 0) idx = 0; 97 | this.setData({ 98 | 'indexesActive.state': true, 99 | 'indexesActive.value': indexesData[idx] 100 | }) 101 | 102 | //快捷区域内选中,震动一下 103 | if (this.mY >= 0 && this.mY <= indexesDom.height) { 104 | wx.vibrateShort(); 105 | } 106 | 107 | this.inSetScrollTop(idx); 108 | 109 | this.timeOut = undefined; 110 | 111 | this.triggerEvent('inmove', { index: idx, active: indexesData[idx] }); 112 | },50) 113 | } 114 | }, 115 | 116 | //设置滚动条 117 | inSetScrollTop(idx){ 118 | const childItems = this.getRelationNodes('../indexes-item/indexes-item'); 119 | this.setData({ 120 | 'scrollTop': childItems[idx].data.top 121 | }) 122 | }, 123 | 124 | //Touch End 125 | inTouchEnd(e){ 126 | setTimeout(() => { 127 | this.setData({ 128 | 'indexesActive.state': false 129 | }); 130 | }, 51) 131 | } 132 | 133 | // 134 | 135 | } 136 | }) 137 | -------------------------------------------------------------------------------- /component/indexes/indexes.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /component/indexes/indexes.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{item}} 6 | 7 | 8 | -------------------------------------------------------------------------------- /component/indexes/indexes.wxss: -------------------------------------------------------------------------------- 1 | /* component/indexes/indexes.wxss */ 2 | .scroll-view{ 3 | height: 100vh; 4 | } 5 | .g-indexes-bar{ 6 | position: fixed; 7 | z-index: 3; 8 | top: 50%; 9 | right: 10rpx; 10 | transform: translate(0, -50%); 11 | } 12 | .g-item-indexes{ 13 | width: 18px; 14 | height: 18px; 15 | color: #666; 16 | line-height: 18px; 17 | font-size: 24rpx; 18 | text-align: center; 19 | } 20 | .g-indexes-active{ 21 | position: fixed; 22 | z-index: 2; 23 | left: 50%; 24 | top: 50%; 25 | width: 140rpx; 26 | height: 140rpx; 27 | line-height: 140rpx; 28 | text-align: center; 29 | color: #fff; 30 | font-size: 60rpx; 31 | border-radius: 50%; 32 | transform: translate(-50%, -50%); 33 | background-color: rgba(0,0,0, .5); 34 | } -------------------------------------------------------------------------------- /component/input/input.js: -------------------------------------------------------------------------------- 1 | // component/input/input.js 2 | Component({ 3 | 4 | behaviors: ['wx://form-field'], 5 | 6 | externalClasses: ['g-class', 'h-class', 'b-class', 'i-class'], 7 | 8 | /** 9 | * 组件的属性列表 10 | */ 11 | properties: { 12 | 13 | //input标题 14 | title: { 15 | type: String, 16 | value: "" 17 | }, 18 | 19 | //可选: text、textarea、number、password 20 | type: { 21 | type: String, 22 | value: 'text' 23 | }, 24 | 25 | //默认值 26 | value: { 27 | type: String, 28 | value: '' 29 | }, 30 | 31 | //可选: radius 32 | mode: { 33 | type: String, 34 | value: '' 35 | }, 36 | 37 | //border-bottom 38 | isborder: { 39 | type: Boolean, 40 | value: true 41 | }, 42 | 43 | //提示文本 44 | placeholder: { 45 | type: String, 46 | value: '' 47 | }, 48 | 49 | //自定义提示文本样式 50 | placeholderstyle: { 51 | type: String, 52 | value: 'color:#b3b7ba;' 53 | }, 54 | 55 | //是否禁用 56 | disabled: { 57 | type: Boolean, 58 | value: false 59 | }, 60 | 61 | //自动聚焦 62 | focus: { 63 | type: Boolean, 64 | value: false 65 | }, 66 | 67 | //最大输入长度,默认-1(不限制) 68 | maxlength: { 69 | type: Number, 70 | value: -1 71 | }, 72 | 73 | //错误文本框 74 | error: { 75 | type: Boolean, 76 | value: false 77 | }, 78 | 79 | //对齐方式:tl居左、tc居中、tr居右 80 | align: { 81 | type: String, 82 | value: '' 83 | }, 84 | 85 | //键盘右下角按钮的文字,仅在type='text'时生效 86 | //可选值参考微信ipnut组件confirm-type属性 87 | confirmtype: { 88 | type: String, 89 | value: 'done' 90 | }, 91 | 92 | }, 93 | 94 | /** 95 | * 组件的方法列表 96 | */ 97 | methods: { 98 | inFocus(event) { 99 | this.triggerEvent('focus', event); 100 | }, 101 | inChange(event) { 102 | const { detail = {} } = event; 103 | const { value = '' } = detail; 104 | this.setData({ value }); 105 | this.triggerEvent('change', event); 106 | }, 107 | inBlue(event) { 108 | this.triggerEvent('blur', event); 109 | }, 110 | inConfirm(event) { 111 | this.triggerEvent('confirm', event); 112 | }, 113 | } 114 | }) 115 | -------------------------------------------------------------------------------- /component/input/input.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /component/input/input.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{title}} 4 | 5 |