HBuilderX

HBuilderX

极客开发工具
uni-app

uni-app

开发一次,多端覆盖
uniCloud

uniCloud

云开发平台
HTML5+

HTML5+

增强HTML5的功能体验
MUI

MUI

上万Star的前端框架

mui(准确的说是html5+)Android原生日历提醒插入案例踩坑经历

消息提醒 日历 安卓 原生分享 HTML5+
  • 缘起
    需要在app里弄个定时提醒功能
  • 过程
    在问答社区看到一个大佬分享的安卓插入日历提醒的按理
    点击这里过去看看???
  • 但是
    看得有点晕,很多代码都不知道在干嘛(毕竟不懂原生)
    开始的时候就原样复制了一遍代码,也没怎么看,心想着能把项目完成了再说
  • 后来发现
    没登录日历账号的手机不能设置提醒,反正就是各种报错
    好了,不说心路历程了
    直接上干货
    (html和引入date picker就省略了哈)
    (function($) {  
    var setcalendar = function() {  
        $.toast('功能加载中,请稍后', {  
            type: 'div',  
            duration: 1000  
        });  
    };  
    $.plusReady(function() {  
        var calanderURL = 'content://com.android.calendar/calendars',  
            ContentValues = plus.android.importClass("android.content.ContentValues"),  
            Uri = plus.android.importClass('android.net.Uri'),  
            Calendar = plus.android.importClass('java.util.Calendar'),  
            main = plus.android.runtimeMainActivity(),  
            userCursor = plus.android.invoke(main.getContentResolver(), 'query', Uri.parse(calanderURL), null, null, null, null),  
            userCursor_count = plus.android.invoke(userCursor, 'getCount'),  
            TimeZone = plus.android.importClass('java.util.TimeZone'),  
            TimeZone_str = plus.android.invoke(TimeZone.getDefault(), 'getID');  
        setcalendar = function(title, description, date_str) {  
            if(userCursor_count <= 0) {//如果没有日历账户  
                var account = new ContentValues(),  
                    buildUpon = plus.android.invoke(Uri.parse(calanderURL), 'buildUpon'),  
                    CalendarContract = plus.android.importClass('android.provider.CalendarContract');  
                plus.android.invoke(buildUpon, 'appendQueryParameter', CalendarContract.CALLER_IS_SYNCADAPTER, 'true');  
                plus.android.invoke(buildUpon, 'appendQueryParameter', 'account_name', 'someone@something.com');  
                plus.android.invoke(buildUpon, 'appendQueryParameter', 'account_type', 'com.android.exchange');  
                //设置账户信息  
                account.put('name', 'someone');  
                account.put('account_name', 'someone@something.com');  
                account.put('account_type', 'com.android.exchange');  
                account.put('calendar_displayName', 'someone_calendar');  
                account.put('visible', 1);  
                account.put('calendar_color', '-9206951');  
                account.put('calendar_access_level', '700');  
                account.put('sync_events', 1);  
                account.put('calendar_timezone', TimeZone_str);  
                account.put('ownerAccount', 'someone@something.com');  
                account.put('canOrganizerRespond', 0);  
                //保存账户信息  
                plus.android.invoke(main.getContentResolver(), 'insert', plus.android.invoke(buildUpon, 'build'), account);  
                //重新定义userCursor  
                userCursor = plus.android.invoke(main.getContentResolver(), 'query', Uri.parse(calanderURL), null, null, null, null);  
                //重新定义userCursor_count  
                userCursor_count++;  
            }  
            plus.android.invoke(userCursor, 'moveToLast');  
            var calId = plus.android.invoke(userCursor, 'getString', plus.android.invoke(userCursor, 'getColumnIndex', '_id')),  
                events = new ContentValues(),  
                mCalendar = Calendar.getInstance(),  
                date = date_str.split(/\s{1}|:|-/g);  
            plus.android.invoke(mCalendar, 'set', Calendar.YEAR, ~~date[0]);  
            plus.android.invoke(mCalendar, 'set', Calendar.MONTH, ((~~date[1]) - 1));  
            plus.android.invoke(mCalendar, 'set', Calendar.DATE, ~~date[2]);  
            plus.android.invoke(mCalendar, 'set', Calendar.HOUR_OF_DAY, ~~date[3]);  
            plus.android.invoke(mCalendar, 'set', Calendar.MINUTE, ~~date[4]);  
            var start = plus.android.invoke(plus.android.invoke(mCalendar, 'getTime'), 'getTime'),  
                  end = plus.android.invoke(plus.android.invoke(mCalendar, 'getTime'), 'getTime');  
            //设置日历事件  
            events.put('title', title);  
            events.put('description', description);  
            events.put('calendar_id', calId);  
            events.put('dtstart', start);  
            events.put('dtend', end);  
            events.put('hasAlarm', 1);  
            events.put('eventTimezone', TimeZone_str);  
            var newEvent = plus.android.invoke(main.getContentResolver(), 'insert', Uri.parse('content://com.android.calendar/events'), events);  
            var id = plus.android.invoke(newEvent, 'getLastPathSegment');  
            var values = new ContentValues();  
            values.put('event_id', id);  
            values.put('minutes', '5');  
            values.put('method', '1');  
            plus.android.invoke(main.getContentResolver(), 'insert', Uri.parse('content://com.android.calendar/reminders'), values);  
            $.toast('设置提醒成功');  
        }  
    });  
    $.ready(function() {  
        $('.mui-content').on('tap', 'button.mui-btn', function() {  
            var picker = new $.DtPicker();  
            picker.show(function(rs) {  
                setcalendar('测试提醒标题', '测试提醒内容', rs.text);  
                picker.dispose();  
            });  
        });  
    });  
    })(mui);
  • 最后说一句
  • 打包的时候记得勾选日历权限
  • 这个问题坑死我了
继续阅读 »
  • 缘起
    需要在app里弄个定时提醒功能
  • 过程
    在问答社区看到一个大佬分享的安卓插入日历提醒的按理
    点击这里过去看看???
  • 但是
    看得有点晕,很多代码都不知道在干嘛(毕竟不懂原生)
    开始的时候就原样复制了一遍代码,也没怎么看,心想着能把项目完成了再说
  • 后来发现
    没登录日历账号的手机不能设置提醒,反正就是各种报错
    好了,不说心路历程了
    直接上干货
    (html和引入date picker就省略了哈)
    (function($) {  
    var setcalendar = function() {  
        $.toast('功能加载中,请稍后', {  
            type: 'div',  
            duration: 1000  
        });  
    };  
    $.plusReady(function() {  
        var calanderURL = 'content://com.android.calendar/calendars',  
            ContentValues = plus.android.importClass("android.content.ContentValues"),  
            Uri = plus.android.importClass('android.net.Uri'),  
            Calendar = plus.android.importClass('java.util.Calendar'),  
            main = plus.android.runtimeMainActivity(),  
            userCursor = plus.android.invoke(main.getContentResolver(), 'query', Uri.parse(calanderURL), null, null, null, null),  
            userCursor_count = plus.android.invoke(userCursor, 'getCount'),  
            TimeZone = plus.android.importClass('java.util.TimeZone'),  
            TimeZone_str = plus.android.invoke(TimeZone.getDefault(), 'getID');  
        setcalendar = function(title, description, date_str) {  
            if(userCursor_count <= 0) {//如果没有日历账户  
                var account = new ContentValues(),  
                    buildUpon = plus.android.invoke(Uri.parse(calanderURL), 'buildUpon'),  
                    CalendarContract = plus.android.importClass('android.provider.CalendarContract');  
                plus.android.invoke(buildUpon, 'appendQueryParameter', CalendarContract.CALLER_IS_SYNCADAPTER, 'true');  
                plus.android.invoke(buildUpon, 'appendQueryParameter', 'account_name', 'someone@something.com');  
                plus.android.invoke(buildUpon, 'appendQueryParameter', 'account_type', 'com.android.exchange');  
                //设置账户信息  
                account.put('name', 'someone');  
                account.put('account_name', 'someone@something.com');  
                account.put('account_type', 'com.android.exchange');  
                account.put('calendar_displayName', 'someone_calendar');  
                account.put('visible', 1);  
                account.put('calendar_color', '-9206951');  
                account.put('calendar_access_level', '700');  
                account.put('sync_events', 1);  
                account.put('calendar_timezone', TimeZone_str);  
                account.put('ownerAccount', 'someone@something.com');  
                account.put('canOrganizerRespond', 0);  
                //保存账户信息  
                plus.android.invoke(main.getContentResolver(), 'insert', plus.android.invoke(buildUpon, 'build'), account);  
                //重新定义userCursor  
                userCursor = plus.android.invoke(main.getContentResolver(), 'query', Uri.parse(calanderURL), null, null, null, null);  
                //重新定义userCursor_count  
                userCursor_count++;  
            }  
            plus.android.invoke(userCursor, 'moveToLast');  
            var calId = plus.android.invoke(userCursor, 'getString', plus.android.invoke(userCursor, 'getColumnIndex', '_id')),  
                events = new ContentValues(),  
                mCalendar = Calendar.getInstance(),  
                date = date_str.split(/\s{1}|:|-/g);  
            plus.android.invoke(mCalendar, 'set', Calendar.YEAR, ~~date[0]);  
            plus.android.invoke(mCalendar, 'set', Calendar.MONTH, ((~~date[1]) - 1));  
            plus.android.invoke(mCalendar, 'set', Calendar.DATE, ~~date[2]);  
            plus.android.invoke(mCalendar, 'set', Calendar.HOUR_OF_DAY, ~~date[3]);  
            plus.android.invoke(mCalendar, 'set', Calendar.MINUTE, ~~date[4]);  
            var start = plus.android.invoke(plus.android.invoke(mCalendar, 'getTime'), 'getTime'),  
                  end = plus.android.invoke(plus.android.invoke(mCalendar, 'getTime'), 'getTime');  
            //设置日历事件  
            events.put('title', title);  
            events.put('description', description);  
            events.put('calendar_id', calId);  
            events.put('dtstart', start);  
            events.put('dtend', end);  
            events.put('hasAlarm', 1);  
            events.put('eventTimezone', TimeZone_str);  
            var newEvent = plus.android.invoke(main.getContentResolver(), 'insert', Uri.parse('content://com.android.calendar/events'), events);  
            var id = plus.android.invoke(newEvent, 'getLastPathSegment');  
            var values = new ContentValues();  
            values.put('event_id', id);  
            values.put('minutes', '5');  
            values.put('method', '1');  
            plus.android.invoke(main.getContentResolver(), 'insert', Uri.parse('content://com.android.calendar/reminders'), values);  
            $.toast('设置提醒成功');  
        }  
    });  
    $.ready(function() {  
        $('.mui-content').on('tap', 'button.mui-btn', function() {  
            var picker = new $.DtPicker();  
            picker.show(function(rs) {  
                setcalendar('测试提醒标题', '测试提醒内容', rs.text);  
                picker.dispose();  
            });  
        });  
    });  
    })(mui);
  • 最后说一句
  • 打包的时候记得勾选日历权限
  • 这个问题坑死我了
收起阅读 »

分享一个图片在线缩放压缩工具

图片加工 图片压缩

功能
使用场景
工具入口
功能
上次图片,可自动生成多种分辨率、大小的图片
可自由的增加、删除和修改要生成的图片的分辨率和大小
设置的图片生成分辨率和大小可重复使用,只需上传不同的图片,即可针对当前图片生成配置好的图片分辨率和样式
多种压缩方式可以选择,操作简便

alt
使用场景
在平时的工作中,经常会碰到需要对同一张图片生成多种分辨率,特别是需要对好多图片都生成同样的分辨率的时候,就需要重复无数次傻瓜的操作。

针对这种情况,使用可配置的图片批量缩放处理工具,可以极大的提高工作效率,特别是对于不熟悉各类图片处理软件的朋友来说,会有较大帮助。

友间共享-图片处理工具

本文链接:https://blog.betweenfriends.cn/post/onlinecompressimage.html

继续阅读 »

功能
使用场景
工具入口
功能
上次图片,可自动生成多种分辨率、大小的图片
可自由的增加、删除和修改要生成的图片的分辨率和大小
设置的图片生成分辨率和大小可重复使用,只需上传不同的图片,即可针对当前图片生成配置好的图片分辨率和样式
多种压缩方式可以选择,操作简便

alt
使用场景
在平时的工作中,经常会碰到需要对同一张图片生成多种分辨率,特别是需要对好多图片都生成同样的分辨率的时候,就需要重复无数次傻瓜的操作。

针对这种情况,使用可配置的图片批量缩放处理工具,可以极大的提高工作效率,特别是对于不熟悉各类图片处理软件的朋友来说,会有较大帮助。

友间共享-图片处理工具

本文链接:https://blog.betweenfriends.cn/post/onlinecompressimage.html

收起阅读 »

原生轮播示例(slider-native)

HTML5+ mui ImageSlider

native模式的图片轮播是的subNViews属性配置而成的,目前支持循环播放、点击预览、双指放大功能,不支持自动轮播;可以通过5+API手动添加图片、获取当前图片轮播控件显示的图片索引值、设置图片轮播控件的图片;native模式的图片轮播适用于展示商品详情的场景,下面是效果图:

实现方案

创建webview时,配置subnview节点即可,代码如下:

var webview = plus.webview.create("slider-native.html", "slider-native", {  
    titleNView:{//配置标题  
        'backgroundColor': '#f7f7f7',//导航栏背景色  
        'titleText': 'slider(native模式)',//导航栏标题  
        'titleColor': '#000000',//文字颜色  
        autoBackButton: true//自动绘制返回箭头  
    },  
    subNViews:[{ //配置图片轮播  
        id: 'slider-native',  
        type: 'ImageSlider',  
        styles: {//这里的left和top是控制控件的位置;Width和height控制控件大小  
            left: 0,  
            top: 0,  
            width:'100%',  
            height: '200px',  
            position: 'static',//static正常定位随窗口滚动,absolute时不随页面滚动  
            type:'transparent',//透明渐变样式标题栏,可以使slider通顶,更加美观  
            loop: true,//是否循环播放  
            images: [{//图片路径和图片大小  
                src: '_www/images/yuantiao.jpg',  
                width: '100%'  
            }, {  
                src: '_www/images/shuijiao.jpg',  
                width: '100%'  
            }, {  
                src: '_www/images/muwu.jpg',  
                width: '100%'  
            }, {  
                src: '_www/images/cbd.jpg',  
                width: '100%'  
            }]  
        }  
    }]  
});  
webview.show("slide-in-right", 300);//显示webview

原生图片轮播(ImageSlider)相关5+api地址:http://www.html5plus.org/doc/zh_cn/nativeobj.html#plus.nativeObj.ImageSlider

体验及源码

下载最新版Hello MUI可体验效果:Hello MUI首页--> gallery slider(图片轮播) --> 默认样式(native模式)。
native模式的图片轮播是在创建webview的时候一同创建的,所以想要在hello mui的源码中找相关代码,不能在slider-native.html里面找,得在index.html中创建slider-native.html的位置查找。
附件是本示例所用代码。

继续阅读 »

native模式的图片轮播是的subNViews属性配置而成的,目前支持循环播放、点击预览、双指放大功能,不支持自动轮播;可以通过5+API手动添加图片、获取当前图片轮播控件显示的图片索引值、设置图片轮播控件的图片;native模式的图片轮播适用于展示商品详情的场景,下面是效果图:

实现方案

创建webview时,配置subnview节点即可,代码如下:

var webview = plus.webview.create("slider-native.html", "slider-native", {  
    titleNView:{//配置标题  
        'backgroundColor': '#f7f7f7',//导航栏背景色  
        'titleText': 'slider(native模式)',//导航栏标题  
        'titleColor': '#000000',//文字颜色  
        autoBackButton: true//自动绘制返回箭头  
    },  
    subNViews:[{ //配置图片轮播  
        id: 'slider-native',  
        type: 'ImageSlider',  
        styles: {//这里的left和top是控制控件的位置;Width和height控制控件大小  
            left: 0,  
            top: 0,  
            width:'100%',  
            height: '200px',  
            position: 'static',//static正常定位随窗口滚动,absolute时不随页面滚动  
            type:'transparent',//透明渐变样式标题栏,可以使slider通顶,更加美观  
            loop: true,//是否循环播放  
            images: [{//图片路径和图片大小  
                src: '_www/images/yuantiao.jpg',  
                width: '100%'  
            }, {  
                src: '_www/images/shuijiao.jpg',  
                width: '100%'  
            }, {  
                src: '_www/images/muwu.jpg',  
                width: '100%'  
            }, {  
                src: '_www/images/cbd.jpg',  
                width: '100%'  
            }]  
        }  
    }]  
});  
webview.show("slide-in-right", 300);//显示webview

原生图片轮播(ImageSlider)相关5+api地址:http://www.html5plus.org/doc/zh_cn/nativeobj.html#plus.nativeObj.ImageSlider

体验及源码

下载最新版Hello MUI可体验效果:Hello MUI首页--> gallery slider(图片轮播) --> 默认样式(native模式)。
native模式的图片轮播是在创建webview的时候一同创建的,所以想要在hello mui的源码中找相关代码,不能在slider-native.html里面找,得在index.html中创建slider-native.html的位置查找。
附件是本示例所用代码。

收起阅读 »

【交流分享】拍照、相册图片基本无损压缩上传示例

技术分享 图片压缩

经常看到有人说拍照上传图片闪退等等等问题,做个了个小实例,用了两年了,几十个客户的APP在用,没遇到过反馈拍照有问题的,需要的自己测试下你的手机能不能用,能用就copy吧,不能用就拉倒了,哈哈。

扫码测试:

apk,源码 戳附件 ☟☟☟☟☟☟☟☟

继续阅读 »

经常看到有人说拍照上传图片闪退等等等问题,做个了个小实例,用了两年了,几十个客户的APP在用,没遇到过反馈拍照有问题的,需要的自己测试下你的手机能不能用,能用就copy吧,不能用就拉倒了,哈哈。

扫码测试:

apk,源码 戳附件 ☟☟☟☟☟☟☟☟

收起阅读 »

如何实现搜索框的历史记录功能?

搜索

菜鸟刚学,不是很懂,请大神指教!
类似百度那种搜索历史。

菜鸟刚学,不是很懂,请大神指教!
类似百度那种搜索历史。

【上海】【张江】【高薪】诚招一个熟悉MUI的前端大牛加入我们!

招聘

岗位职责:
1、对前端应用进行开发,带领混合开发MUI团队完成的相关工作;
2、本着以用户为核心的设计理念,对页面进行优化,使用户操作更趋于人性化;
3、支持部门产品维护和新产品的开发,负责产品前端优化。

任职资格:
1、大专及以上学历,3年及以上工作经验;
2、熟悉MUI混合开发,熟悉W3C标准及规范,熟悉XHTML、DIV、CSS等页面技术;
3、熟悉JavaScript和AJAX技术原理,熟悉原生JavaScript;
4、熟悉MUI;
5、对用户体验、交互操作流程、及用户需求有深刻理解,能够深刻理解Web标准,在可用性、可访问性、浏览器兼容性等方面有实践经验;
6、对Web技术专研有强烈兴趣;
7、具有强烈的责任心、工作热情和求知上进欲望,有解决问题、钻研新技术的兴趣和能力;
8、具有自律精神和团队合作精神。

此信息至2017年11月前有效
邮件:16434146@qq.com

继续阅读 »

岗位职责:
1、对前端应用进行开发,带领混合开发MUI团队完成的相关工作;
2、本着以用户为核心的设计理念,对页面进行优化,使用户操作更趋于人性化;
3、支持部门产品维护和新产品的开发,负责产品前端优化。

任职资格:
1、大专及以上学历,3年及以上工作经验;
2、熟悉MUI混合开发,熟悉W3C标准及规范,熟悉XHTML、DIV、CSS等页面技术;
3、熟悉JavaScript和AJAX技术原理,熟悉原生JavaScript;
4、熟悉MUI;
5、对用户体验、交互操作流程、及用户需求有深刻理解,能够深刻理解Web标准,在可用性、可访问性、浏览器兼容性等方面有实践经验;
6、对Web技术专研有强烈兴趣;
7、具有强烈的责任心、工作热情和求知上进欲望,有解决问题、钻研新技术的兴趣和能力;
8、具有自律精神和团队合作精神。

此信息至2017年11月前有效
邮件:16434146@qq.com

收起阅读 »

自动收起键盘、防止输入内容后进行其他操作又弹出键盘

技术分享 软键盘
//自动收起键盘,条件判断收起  
inputEl.addEventListener('keyup', function() {  
    if(this.value.length>=11){   //输入11位手机号自动收起键盘  
        this.blur();  
    }  
});

经常遇到输入完收起键盘再点提交,键盘又弹出来了,那是因为上次操作的表单元素没有失去焦点

var focus=document.querySelector(':focus');  
focus&&focus.blur();  

//或  
document.activeElement.blur();
继续阅读 »
//自动收起键盘,条件判断收起  
inputEl.addEventListener('keyup', function() {  
    if(this.value.length>=11){   //输入11位手机号自动收起键盘  
        this.blur();  
    }  
});

经常遇到输入完收起键盘再点提交,键盘又弹出来了,那是因为上次操作的表单元素没有失去焦点

var focus=document.querySelector(':focus');  
focus&&focus.blur();  

//或  
document.activeElement.blur();
收起阅读 »

【分享】【开源】优雅的H5下拉刷新。零依赖,高性能,多主题,易拓展

原生js 框架 开源 技术分享 源码分享 上拉加载 下拉刷新 HTML5


minirefresh-优雅的H5下拉刷新

特点

  • 零依赖(原生JS实现,不依赖于任何库)

  • 多平台支持。一套代码,多端运行,支持Android,iOS,主流浏览器

  • 丰富的主题,官方提供多种主题(包括默认,applet-仿小程序,drawer3d-3d抽屉效果,taobao-仿淘宝等)

  • 高性能。动画采用css3+硬件加速,在主流手机上流畅运行

  • 良好的兼容性。支持和各种Scroll的嵌套(包括mui-scroll,IScroll,Swipe等),支持Vue环境下的使用

  • 易拓展,三层架构,专门抽取UI层面,方便实现各种的主题,实现一套主题非常方便,而且几乎可以实现任何的效果

  • 优雅的API和源码,API设计科学,简单,源码严谨,所有源码通过ESlint检测

  • 完善的文档与示例,提供完善的showcase,以及文档

源码

https://github.com/minirefresh/minirefresh

https://www.npmjs.com/package/minirefresh

官网与文档

https://minirefresh.github.io/

效果

基础示例

1. 【基础新闻列表】最基本的下拉刷新使用

2. 【多列表单容器】每次切换菜单时刷新容器

3. 【多列表多容器】多个列表都有一个Minirefresh对象

4. 【Vue支持】支持Vue下的使用

嵌套示例

1. 【Mui-Slider】内部嵌套图片轮播

2. 【Mui-Scroll】嵌套在Mui-Scroll中

3. 【Swipe】嵌套在Swipe中

主题示例

1. 【applet】仿微信小程序主题

2. 【taobao】仿淘宝刷新主题

3. 【drawer3d】3D抽屉效果主题

4. 【drawer-slider】滑动抽屉效果主题

showcase

可以直接在线体验效果

https://minirefresh.github.io/minirefresh/examples/

贡献

minirefresh需要你!

来为项目添砖加瓦,新的Idea,新的主题,重大Bug发现,新的设计资源(如图标,官网设计等)

都可以通过IssuePR的方式提交!

贡献被采纳后会加入贡献者名单,如果有杰出贡献(如持续贡献),可以加入Manager小组,共同开发维护MiniRefresh

有共同参与项目意愿的,可以申请成为Member,成为Minirefresh真正的主人!

更多参考:https://minirefresh.github.io/minirefresh-doc/site/contribute/howtocontributor.html

讨论

注意,申请加入群时请添加验证信息,例如:minirefresh使用遇到问题等等

最后关于灵感与参考

核心架构是参考的我自己以前的项目 https://github.com/dailc/pulltorefresh-h5-iscroll,只不过把依赖IScroll换成了原生JS与CSS3实现,并且完全的重构与优化

做这个项目的灵感与原动力是受 https://github.com/mescroll/mescroll 启发,但是由于那个项目里的代码不符合我的个人风格,一些主题拓展也没有达到我的要求,因此我自己重新写了一个项目而不是基于mescroll拓展

还有就是写这个项目也是对自己的一种锻炼,里面包含了

  • JS与CSS3的熟练运用,并进行合理架构
  • ESlint严格的代码检测
  • Gulp 自动构建
  • Karma+Mocha单元测试(待完善)
  • Circleci,Codecov,Sauce等自动集成与测试网址,
  • Gitbook构建API与教程文档
  • Hexo构建官方网站(待完善)
  • 域名备案,CDN加速等(待完善)
  • Npm发布与Github项目团队

当然了,迫于一些原因,没有用全新的ES6或TS写,而是用的ES5严格模式。

另外,这个项目是托管在Github的minirefresh组织上的,希望有更多的人能参与,成为组织的一员,共同维护,毕竟在不断的分享交流中才能进步更快...

继续阅读 »


minirefresh-优雅的H5下拉刷新

特点

  • 零依赖(原生JS实现,不依赖于任何库)

  • 多平台支持。一套代码,多端运行,支持Android,iOS,主流浏览器

  • 丰富的主题,官方提供多种主题(包括默认,applet-仿小程序,drawer3d-3d抽屉效果,taobao-仿淘宝等)

  • 高性能。动画采用css3+硬件加速,在主流手机上流畅运行

  • 良好的兼容性。支持和各种Scroll的嵌套(包括mui-scroll,IScroll,Swipe等),支持Vue环境下的使用

  • 易拓展,三层架构,专门抽取UI层面,方便实现各种的主题,实现一套主题非常方便,而且几乎可以实现任何的效果

  • 优雅的API和源码,API设计科学,简单,源码严谨,所有源码通过ESlint检测

  • 完善的文档与示例,提供完善的showcase,以及文档

源码

https://github.com/minirefresh/minirefresh

https://www.npmjs.com/package/minirefresh

官网与文档

https://minirefresh.github.io/

效果

基础示例

1. 【基础新闻列表】最基本的下拉刷新使用

2. 【多列表单容器】每次切换菜单时刷新容器

3. 【多列表多容器】多个列表都有一个Minirefresh对象

4. 【Vue支持】支持Vue下的使用

嵌套示例

1. 【Mui-Slider】内部嵌套图片轮播

2. 【Mui-Scroll】嵌套在Mui-Scroll中

3. 【Swipe】嵌套在Swipe中

主题示例

1. 【applet】仿微信小程序主题

2. 【taobao】仿淘宝刷新主题

3. 【drawer3d】3D抽屉效果主题

4. 【drawer-slider】滑动抽屉效果主题

showcase

可以直接在线体验效果

https://minirefresh.github.io/minirefresh/examples/

贡献

minirefresh需要你!

来为项目添砖加瓦,新的Idea,新的主题,重大Bug发现,新的设计资源(如图标,官网设计等)

都可以通过IssuePR的方式提交!

贡献被采纳后会加入贡献者名单,如果有杰出贡献(如持续贡献),可以加入Manager小组,共同开发维护MiniRefresh

有共同参与项目意愿的,可以申请成为Member,成为Minirefresh真正的主人!

更多参考:https://minirefresh.github.io/minirefresh-doc/site/contribute/howtocontributor.html

讨论

注意,申请加入群时请添加验证信息,例如:minirefresh使用遇到问题等等

最后关于灵感与参考

核心架构是参考的我自己以前的项目 https://github.com/dailc/pulltorefresh-h5-iscroll,只不过把依赖IScroll换成了原生JS与CSS3实现,并且完全的重构与优化

做这个项目的灵感与原动力是受 https://github.com/mescroll/mescroll 启发,但是由于那个项目里的代码不符合我的个人风格,一些主题拓展也没有达到我的要求,因此我自己重新写了一个项目而不是基于mescroll拓展

还有就是写这个项目也是对自己的一种锻炼,里面包含了

  • JS与CSS3的熟练运用,并进行合理架构
  • ESlint严格的代码检测
  • Gulp 自动构建
  • Karma+Mocha单元测试(待完善)
  • Circleci,Codecov,Sauce等自动集成与测试网址,
  • Gitbook构建API与教程文档
  • Hexo构建官方网站(待完善)
  • 域名备案,CDN加速等(待完善)
  • Npm发布与Github项目团队

当然了,迫于一些原因,没有用全新的ES6或TS写,而是用的ES5严格模式。

另外,这个项目是托管在Github的minirefresh组织上的,希望有更多的人能参与,成为组织的一员,共同维护,毕竟在不断的分享交流中才能进步更快...

收起阅读 »

关于webview嵌入web项目打包APP,android物理返回按钮的处理

  1. 首先我项目中没有用到mui.js,只是壳打包web项目和调用了h5+的支付
  2. 注册h5+的返回按钮事件 plus.key.addEventListener('backbutton',backListener,false);
  3. 事件中判断是不是在首页,然后进行处理
  4. w是创建的webview
  5. 目前实现到首页提示再按一次退出程序,和一级页面的返回,二级页面会只能返回一级,谁有好的解决方案望探讨

var first=null;
function backListener(){
//首次按键,提示‘再按一次退出应用’
if(w!=null){
var u=w.getURL();
if(u.lastIndexOf("welcome/index.htm")>0||u.lastIndexOf("ziyuan/index.htm")>0||u.lastIndexOf("xuqiu/index.htm")>0||u.lastIndexOf("paimai/index.htm")>0){
if (!first) {
console.log(u);
first = new Date().getTime();
plus.nativeUI.toast('再按一次退出程序');
setTimeout(function() {
first = null;
}, 1000);
} else {
if (new Date().getTime() - first < 1000) {
plus.runtime.quit();
}
}
}else{
w.canBack(function(e){
if(e.canBack){
w.back();
}else{
w.loadURL(weburl+'/welcome/index.htm');
}
});
w.canForward(function(e){
if(e.canForward){
w.forward();
}
});
}
}
}

继续阅读 »
  1. 首先我项目中没有用到mui.js,只是壳打包web项目和调用了h5+的支付
  2. 注册h5+的返回按钮事件 plus.key.addEventListener('backbutton',backListener,false);
  3. 事件中判断是不是在首页,然后进行处理
  4. w是创建的webview
  5. 目前实现到首页提示再按一次退出程序,和一级页面的返回,二级页面会只能返回一级,谁有好的解决方案望探讨

var first=null;
function backListener(){
//首次按键,提示‘再按一次退出应用’
if(w!=null){
var u=w.getURL();
if(u.lastIndexOf("welcome/index.htm")>0||u.lastIndexOf("ziyuan/index.htm")>0||u.lastIndexOf("xuqiu/index.htm")>0||u.lastIndexOf("paimai/index.htm")>0){
if (!first) {
console.log(u);
first = new Date().getTime();
plus.nativeUI.toast('再按一次退出程序');
setTimeout(function() {
first = null;
}, 1000);
} else {
if (new Date().getTime() - first < 1000) {
plus.runtime.quit();
}
}
}else{
w.canBack(function(e){
if(e.canBack){
w.back();
}else{
w.loadURL(weburl+'/welcome/index.htm');
}
});
w.canForward(function(e){
if(e.canForward){
w.forward();
}
});
}
}
}

收起阅读 »

APP的webview中拦截资源API可以进行大的优化

移动APP

H5+里的那个拦截资源实在不好用啊,可以参考chrome插件的拦截。chrome的拦截只需要一个API,而不是像webview分拦截监听各种限制。
然后它可以分为多个阶段,如请求开始可以修改协议头,请求完成可以修改内容,重定向或则忽略都可以在回调中来实现。

所以来此提出建议,当然肯定涉及到很多方面,如果可以的话还是希望官方抽出些时间来优化下

继续阅读 »

H5+里的那个拦截资源实在不好用啊,可以参考chrome插件的拦截。chrome的拦截只需要一个API,而不是像webview分拦截监听各种限制。
然后它可以分为多个阶段,如请求开始可以修改协议头,请求完成可以修改内容,重定向或则忽略都可以在回调中来实现。

所以来此提出建议,当然肯定涉及到很多方面,如果可以的话还是希望官方抽出些时间来优化下

收起阅读 »

多级PopPicke用setSelectedValuer设置默认值二三级不生效问题

用下面这个方法设置,结果发现只有第一级菜单设置成功了,后面两级压根就没执行。

// 设定省初始值  
                cityPicker.pickers[0].setSelectedValue(100000, 0, function() {  
                    // 设定市初始值  
                    cityPicker.pickers[1].setSelectedValue(101000, 0, function() {  
                        // 设定区初始值  
                        cityPicker.pickers[2].setSelectedValue(101001);  
                    });  
                });

查看mui.picker源代码发现:

Picker.prototype.setSelectedValue = function(value, duration, callback) {  
        var self = this;  
        for (var index in self.items) {  
            var item = self.items[index];  
            if (item.value == value) {  
                self.setSelectedIndex(index, duration, callback);  
                return;  
            }  
        }  
    };

for循环中是个return,结束了循环不再往下执行,换成break即可。

继续阅读 »

用下面这个方法设置,结果发现只有第一级菜单设置成功了,后面两级压根就没执行。

// 设定省初始值  
                cityPicker.pickers[0].setSelectedValue(100000, 0, function() {  
                    // 设定市初始值  
                    cityPicker.pickers[1].setSelectedValue(101000, 0, function() {  
                        // 设定区初始值  
                        cityPicker.pickers[2].setSelectedValue(101001);  
                    });  
                });

查看mui.picker源代码发现:

Picker.prototype.setSelectedValue = function(value, duration, callback) {  
        var self = this;  
        for (var index in self.items) {  
            var item = self.items[index];  
            if (item.value == value) {  
                self.setSelectedIndex(index, duration, callback);  
                return;  
            }  
        }  
    };

for循环中是个return,结束了循环不再往下执行,换成break即可。

收起阅读 »

官方文档中h5+中的share组件实例代码有拼写错误

function shareAction(){
var s = shares[0];
if ( !s.authenticated ) {
s.authorize( functioin(){
console.log("认证完成!");
}, function(e){
console.log("未进行认证");
} )
}
}
上面是官方代码,将function写成了functioin

继续阅读 »

function shareAction(){
var s = shares[0];
if ( !s.authenticated ) {
s.authorize( functioin(){
console.log("认证完成!");
}, function(e){
console.log("未进行认证");
} )
}
}
上面是官方代码,将function写成了functioin

收起阅读 »