一、效果展示
二、项目结构图以及用到的模块
三、主要功能
1、下拉刷新上啦加载更多(mescroll.js)
2、点赞评论
3、导航背景透明渐变效果
4、图像预览(UIPhotoViewer)
5、图像压缩
6、定位附近地点(aMap)
7、图像批量上传
四、功能点详解
1、下拉刷新和上拉加载我用的是 mescroll.js (自带图像懒加载,官方网站有详细使用说明文档) 实现的思路是自定义下啦样式,当下拉的时候图像不停旋转同时向下移动,几秒后向上移动消失在顶部。
下拉刷新效果需要自定义,更改下拉刷新的布局容器样式
warpClass: 'refresh' 。
<div class="refresh"></div> //下拉刷新容器 css 样式如下
.refresh { position: fixed; top: 0; width: 100% }
<div class="laoding"><img src="../res/icon.png" class="img"></div>旋转动画
效果 css 样式如下
.laoding { position: fixed; top: -1.5rem; left: 2rem; width: 1.5rem; height: 1.5rem; z-index: 1; } .to_bottom { -webkit-animation: to_bottom 2s; animation: to_bottom 2s; } .laoding .img { width: 1.3rem; height: 1.3rem; animation: rotating 0.2s linear infinite; -webkit-animation: rotating 0.2s infinite; } @keyframes to_bottom { 0% { top: -4rem; } 4% { top: 3rem; } 8% { top: 4rem; } 10% { top: 5rem; } 50% { top: 5rem; } 75% { top: 5rem; } 100% { top: -1.5rem; } } @keyframes rotating { to { transform: rotate(1turn); } }
2、点赞评论这个功能主要是样式的设计难度很小但是需要注意当屏幕滚动时需要隐藏评论框以及相关按钮。
3、导航背景透明渐变效果
实现的思路是结合 mescroll.js滚动监听滚动区域距离顶部的高度该表导航栏背景和文字以及状态栏的文字颜色
具体代码如下
<header> <div class="status-bar"></div> <div class="nav"> <div class="back"><i class="iconfont icon"></i></div> <div class="nav-title"></div> <div class="camera" onclick="add()"><i class="iconfont icon"></i></div> </div> </header> if (h < 60) { StatusBar('light', 'rgba(255, 255, 255, 0)'); hui('header').css({ 'background': "rgba(255,255,255,0.0" + h + ")" }) hui('header').css({ 'box-shadow': "1px 3px 4px rgba(0, 0, 0, 0)" }) hui(".icon").css({ "color": "#ffffff" }); hui(".nav-title").html(''); } else if (h >= 60 && h <= 100) { StatusBar('dark', 'rgba(255,255,255,0)'); hui('header').css({ 'background': "rgba(255,255,255,0.0" + h + ")" }) hui('header').css({ 'box-shadow': "1px 3px 4px rgba(0, 0, 0, 0)" }) hui(".icon").css({ "color": "#000" }); hui(".nav-title").html('朋友圈'); } else if (h >= 100) { StatusBar('dark', 'rgba(255,255,255,0)'); hui('header').css({ 'background': "#ffffff" }) hui('header').css({ 'box-shadow': "1px 3px 4px rgba(0, 0, 0, 0.05)" }) hui(".icon").css({ "color": "#000" }); hui(".nav-title").html('朋友圈'); }
4、图像预览(UIPhotoViewer)
photoswipe.js 效果更好但是不支持图像长安功能。UIPhotoViewer 实现起来比较简单现,但是要模仿微信那种效果需要创建一个网页 viewer-dot.Html 来实现滚动效果
当图像预览发生左右滚动时发送一个广播事件告诉viewer-dot.Html 当图像预览模块关闭时也关闭viewer-dot.Html页面
apiready = function () { api.addEventListener({ name: 'change_dot' }, function (ret, err) { init(ret.value.index,ret.value.nub) }) init(api.pageParam.index,api.pageParam.nub) }; function init(on_index,dot_number) { var html = ''; for (var i = 0; i < dot_number; i++) { if (i == on_index) { html += '<div class="dot active"></div>'; } else { html += '<div class="dot"></div>'; } } hui('.list').html(html); }
5、图像压缩
图像压缩可以用 compactPicture,压缩后图像清晰、体积小。封装了一个 js 函数实现图像压缩 compress_img()。
function compress_img(path, obj, callback) { var img = new Image(); img.src = path; img.onload = function () { var that = this; var w = that.width, h = that.height, scale = w / h; w = obj.width || w; h = obj.height || (w / scale); var quality = 0.7 var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); var anw = document.createAttribute("width"); anw.nodeValue = w; var anh = document.createAttribute("height"); anh.nodeValue = h; canvas.setAttributeNode(anw); canvas.setAttributeNode(anh); ctx.drawImage(that, 0, 0, w, h); if (obj.quality && obj.quality <= 1 && obj.quality > 0) { quality = obj.quality; } var base64 = canvas.toDataURL('image/jpeg', quality); callback(base64); } }
图像压缩前需要指定图像宽度,如果设为固定值所有图像压缩后宽度一样,这肯定不行。所以需要根据图片的宽度高度灵活设置压缩后的宽度。imageFilter 模块可以获取图像宽高。
var imageFilter = api.require('imageFilter'); imageFilter.getAttr({ path: pic }, function (ret, err) { if (ret.status) { if (ret.width > ret.height) { if (ret.width > 1000) { imgw = 1200} else if (ret.width < 1000 && ret.width > 700) { imgw = 800} else if (ret.width < 700 && ret.width > 500) { imgw = 600} else {imgw = 400} } else { if (ret.height > 3000) {imgw = 990} else if (ret.height < 3000 && ret.height > 1600) {imgw = 900} else if (ret.height < 1600 && ret.height > 1000) {imgw = 800} else if (ret.height < 1000 && ret.height > 600) {imgw = 550} else if (ret.height < 600 && ret.height > 400) {imgw = 350} else {imgw = 200} }
但是压缩后返回的是 base64 批量上传二进制流不方便,所以利用 trans 模块将 base64 转成 jpg 然后再批量上传。
compress_img(pic, { width: imgw }, function (base) { var imgName = randomString(8) + '.jpg'; var imgPath = "fs://picture/moments/" var base64Str = base.replace('data:image/jpeg;base64,', ''); var trans = api.require('trans'); trans.saveImage({ base64Str: base64Str, imgPath: imgPath, imgName: imgName }, function (ret, err) { if (ret.status) { var path = api.fsDir + "/picture/moments/" + imgName; vm.pics.push(path); } }); });
6、定位附近地点(aMap)
使用该模块需要获取定位权限,同时还要执行 updateMapViewPrivacy、updateSearchPrivacy,否则地图和搜索接口都无效。
function open_map() { var ret = api.hasPermission({ list: ['location'] }); if (ret[0].granted) { api.openWin({ name: 'map-view', url: 'map-view.html', }); } else { api.requestPermission({ list: ['location'], }, function (res) { if (res.list[0].granted) { api.openWin({ name: 'map-view', url: 'map-view.html', }); } else { api.toast({ msg: '无手机定位权限' }) } }); } }
利用 searchNearby 接口显示附件地点,详细可以参考:https://developer.yonyou.com/portal.php?mod=view&aid=21
7、图像批量上传
实现思路:图像压缩后将图像地址保存在 pics 数组里面,再用 ajax 以表单方式提交文件
api.ajax({ url: 'https://www.yy-im.cn/api/moments/add', method: 'post', data: { files: { "pic[]": vm.pics } } }, function (ret, err) { });