
弹出 mui-modal 标题出现显示不正常的问题
<div id="transferModal" class="mui-modal">
<header class="mui-bar mui-bar-nav" style="background-color: #FFFFFF;border-bottom: 1px #F4F4F4 solid;">
<a class="mui-icon mui-pull-left" href="#transferModal">
<img src="../public/img/backArrow_gray19x19@3x.png" width="15" style="margin-left:3px;margin-top:4px;" />
</a>
<h1 class="mui-title">标题</h1>
</header>
<div class="mui-content" style="height: 100%;">
</div>
</div>
比如这个modal 弹出后,发现标题 header 直接没了。各种原因找了,发现加上样式:
.mui-modal header{overflow: hidden;}
就可以解决了。
<div id="transferModal" class="mui-modal">
<header class="mui-bar mui-bar-nav" style="background-color: #FFFFFF;border-bottom: 1px #F4F4F4 solid;">
<a class="mui-icon mui-pull-left" href="#transferModal">
<img src="../public/img/backArrow_gray19x19@3x.png" width="15" style="margin-left:3px;margin-top:4px;" />
</a>
<h1 class="mui-title">标题</h1>
</header>
<div class="mui-content" style="height: 100%;">
</div>
</div>
比如这个modal 弹出后,发现标题 header 直接没了。各种原因找了,发现加上样式:
.mui-modal header{overflow: hidden;}
就可以解决了。
收起阅读 »
用vue和mui整合开发的一个图片压缩服务示例
前言
这只是个人的经验总结和分享,并不是,也没时间做一个完整的教程。
分享的是我在实际项目开发中碰到的杂七杂八的问题,仅供参考。
一个简单的图片压缩工具
在线地址: 图片压缩工具-友间共享
在工作过程中,难免会碰到需要为同一个图片生成多种分辨率的情形,比如打包app之前需要准备好的各类图标,虽然简单,但是费点时间在所难免,就自己做了一个小工具,主要功能如下:
- 可以自定义处理后的图片的分辨率和压缩方式等,自定义的样式自动保存,下次可以重复使用。
- 一键上传图片,根据预设的样式批量生成处理结果,根据需要再自行下载
开发环境
- vue+mui+webpack+npm+macos
- 后台服务: 七牛云存储
运行环境
在线服务,可在支持h5的浏览器上运行,电脑,手机平板理论上都可以
在线地址: 图片压缩工具-友间共享
实现原理
其实很简单,就是先上传图片到七牛云服务
然后在页面上提供配置页面,保存用户配置的格式,然后把每个格式都转化成七牛的图片转化服务的格式化字符串,最后把这个字符串和图片的原地址合并成图片下载链接,就可以在点击链接时调用七牛的图片处理服务,按照我们设定的格式下载转化后的图片。
项目目录结构
** 详细目录结构介绍和开发环境部署参考 怎么搭建vue和Mui的多页面开发环境
主要代码
引入vue,mui等库
import LContext from 'lui/context.js'
import Vue from 'vue'
import 'babel-polyfill'
import Vuex from 'vuex'
import $ from './mui/mui.min'
require('../css/mui.min.css')
require('../css/icons-extra.css')
//require('../css/iconfont.css')
//require('../css/app.css')
require('../css/app.less')
window.Vue = Vue
window.Vuex = Vuex
window.$ = $
window.mui = $
require('./mui/mui.pullToRefresh')
require('./mui/mui.pullToRefresh.material')
//加载BASE64
require('exports-loader!./util/base64.js')
Vue.use(Vuex)
//import LoginDialog from 'app/Login'
if(process.env.NODE_ENV === 'production') {
Vue.config.productionTip = false
}
有点偷懒,部分变量其实是可以在环境配置时引入的,这里就先忽略了,反正效果也一样
其中的库可根据需要引入,因为是从我自己的架构上COPY下来的,有些文件和库在这个项目中是可以不用引入的。引用的路径和webpack环境配置有关,以下是我的配置
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: { //定义别名,简易方式,可以在require调用时缩短路径
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
"page$": resolve('src/js/page.js'),
'app': resolve('src/components/'),
'lui': resolve('src/js/lui/'),
'mui': resolve('src/js/mui/'),
'util': resolve('src/js/util/')
}
},
output.js代码
import Page from 'page'
import Uploader from 'lui/upload.js'
var formVue = new Vue({
el: '.mui-content',
data: {
src: '',
formats: [],
formatBuff: {
facs: 9,
scaleType: '按指定宽高值强行缩略,可能导致目标图片变形,width和height取值范围1-9999'
}, //当前正在编辑的图片类型
collapsePanels: {
scale: false
},
logined: false
},
computed: {
showScale: function() {
switch(this.formatBuff.facs) {
case 1:
return true;
case 2:
return true;
case 3:
return true;
default:
break;
}
return false;
},
showHeight: function() {
switch(this.formatBuff.facs) {
case 5:
return true;
case 7:
return true;
case 8:
return true;
case 9:
return true;
case 10:
return true;
case 11:
return true;
default:
break;
}
return false;
},
showWidth: function() {
switch(this.formatBuff.facs) {
case 4:
return true;
case 7:
return true;
case 8:
return true;
case 9:
return true;
case 10:
return true;
case 11:
return true;
default:
break;
}
return false
},
showArea: function() {
switch(this.formatBuff.facs) {
case 12:
return true;
default:
break;
}
return false;
},
showInput: function() {
if(this.formatBuff.facs > 0) {
return true
}
return false
},
srcUri: function() {
if(this.src) {
return LContext.fileServer + this.src + LContext.image.Thumbnail
}
return ''
},
srcThumbnail: function() {
if(this.src) {
return LContext.fileServer + this.src +
LContext.image.Thumbnail
}
return ''
},
isEdit: function() {
if(this.formatBuff.uid) {
return true
}
return false
},
saveBtnText: function() {
console.log(this.isEdit + ' edit')
if(this.isEdit) {
return '保存修改'
} else {
return '保存新建样式'
}
}
},
methods: {
downLoad: function(format) {
var _format = this.decodeFormat(format)
if(_format.length > 2) {
lpage.open(LContext.fileServer + this.src + '?imageMogr2' + _format, undefined, 'new')
} else {
lpage.alert('下载格式无效!')
}
},
downUrl: function(format) {
var _format = this.decodeFormat(format)
if(_format.length > 2) {
return LContext.fileServer + this.src + '?imageMogr2' + _format
} else {
return false
}
},
deleteFormat: function(format) {
for(var i = 0; i < this.formats.length; i++) {
if(this.formats[i].uid === format.uid) {
this.formats.splice(i, 1)
lpage.saveFormats()
}
}
},
setFacs: function(facs, event) {
// this.formatBuff.facs = parseInt(facs, 10)
Vue.set(this.formatBuff, 'facs', parseInt(facs, 10))
Vue.set(this.formatBuff, 'scaleType', event.currentTarget.innerText)
Vue.nextTick(function() {
this.closePanel('scale')
}.bind(this))
// console.log(JSON.stringify(this.formatBuff))
},
decodeFormat: function(format) {
//缩放
var formatStr = '/thumbnail/'
switch(format.facs) {
case 1:
formatStr += '!' + format.scale + 'p'
break;
case 2:
formatStr += '!' + format.scale + 'px'
break;
case 3:
formatStr += '!x' + format.scale + 'p'
break;
case 4:
formatStr += format.width + 'x'
break;
case 5:
formatStr += 'x' + format.height
break;
case 7:
formatStr += format.width + 'x' + format.height
break;
case 8:
formatStr += '!' + format.width + 'x' + format.height
break;
case 9:
formatStr += format.width + 'x' + format.height + '!'
break;
case 10:
formatStr += format.width + 'x' + format.height + '>'
break;
case 11:
formatStr += format.width + 'x' + format.height + '<'
break;
case 12:
formatStr += format.area + '@'
break;
default:
formatStr = ''
break;
}
//格式转换
if(format.suffix !== 'auto') {
formatStr += '/format/' + format.suffix
}
return formatStr
},
isActiveFacs: function(facs) {
if(this.formatBuff.facs === facs) {
return true
}
return false
},
panelActive: function(collapseList) {
return this.collapsePanels[collapseList]
},
togglePanel: function(collapseList) {
Vue.set(this.collapsePanels, collapseList, !this.collapsePanels[collapseList])
},
closePanel: function(collapseList) {
Vue.set(this.collapsePanels, collapseList, false)
},
submitNewFormat: function() {
var newFormat = {
uid: 'format_' + new Date().getTime(),
height: this.formatBuff.height,
width: this.formatBuff.width,
scale: this.formatBuff.scale,
area: this.formatBuff.area,
facs: this.formatBuff.facs,
desc: this.formatBuff.desc,
scaleType: this.formatBuff.scaleType,
suffix: this.formatBuff.suffix ? this.formatBuff.suffix : 'auto', //图片类型
quality: this.formatBuff.quality ? this.formatBuff.quality : 75 //图片质量
}
var change = false
if(this.formatBuff.uid) {
for(var i = 0; i < this.formats.length; i++) {
if(this.formats[i].uid === this.formatBuff.uid) {
newFormat.uid = this.formatBuff.uid
this.formatBuff.uid = undefined
Vue.set(this.formats, i, newFormat)
change = true
}
}
}!change && this.formats.push(newFormat)
lpage.saveFormats()
},
editFormat: function(format) {
Vue.set(this.formatBuff, 'uid', format.uid)
Vue.set(this.formatBuff, 'height', format.height)
Vue.set(this.formatBuff, 'width', format.width)
Vue.set(this.formatBuff, 'scale', format.scale)
Vue.set(this.formatBuff, 'area', format.area)
Vue.set(this.formatBuff, 'facs', format.facs)
Vue.set(this.formatBuff, 'desc', format.desc)
Vue.set(this.formatBuff, 'scaleType', format.scaleType)
Vue.set(this.formatBuff, 'suffix', format.suffix === 'auto' ? undefined : format.suffix)
Vue.set(this.formatBuff, 'quality', format.quality ? format.quality : 75)
}
}
})
var pcPage = {
initUI: function() {
this.initUploader()
},
initData: function() {
// this.user.isLogin(function(logined) {
// if(logined) {
// formVue.logined = true
lpage.getFormats()
// } else {
// formVue.logined = false
// lpage.user.login()
// }
// })
},
initUploader: function() {
new Uploader({
selector: 'image_uploader',
token: {
mode: 'imagescale',
image: { //图片
prefix: '/utils/imagescale/'
}
},
success: function(data) {
formVue.src = data.key
lpage.saveFormats()
}
}).init()
},
saveFormats: function() {
lpage.setItem('_myFormats', JSON.stringify(formVue.formats))
lpage.setItem('_lastSrc', formVue.src)
},
getFormats: function() {
var _fmt = lpage.getItem('_myFormats')
if(!_fmt) {
_fmt = [{
'uid': 'format_1504082048978',
'height': '2208',
'width': '1242',
'scale': '50',
'facs': 9,
'desc': '苹果IphoneApp审核用的截屏图片1242*2208',
'scaleType': '按指定宽高值强行缩略,可能导致目标图片变形,width和height取值范围1-9999\n',
'suffix': 'auto',
'quality': '100'
}, {
'uid': 'format_1504144877541',
'height': '2732',
'width': '2048',
'scale': '50',
'facs': 9,
'desc': '苹果IpadApp审核用的截屏图片2048*2732',
'scaleType': '按指定宽高值强行缩略,可能导致目标图片变形,width和height取值范围1-9999\n',
'suffix': 'auto',
'quality': '100'
}]
Vue.set(formVue, 'formats', _fmt)
} else
if(_fmt) {
try {
_fmt = JSON.parse(_fmt)
Vue.set(formVue, 'formats', _fmt)
} catch(e) {
//TODO handle the exception
console.log('err')
}
}
_fmt = lpage.getItem('_lastSrc')
if(_fmt) {
formVue.src = _fmt
}
}
}
Page.init({
pc: pcPage
})
output.html源码
<!DOCTYPE html>
<html class="feedback">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<title>友间共享-图片处理</title>
<style>
.mui-content .mui-table-view-radio .mui-table-view-cell>a:not(.mui-btn) {
text-align: left;
white-space: normal;
}
</style>
</head>
<body>
<header class="mui-bar mui-bar-nav">
<a class="mui-action-back mui-btn mui-btn-link mui-btn-nav mui-pull-left"><span class=" mui-icon mui-icon-left-nav "></span> </a>
<h1 class="mui-title">友间共享-图片处理</h1>
</header>
<div class="mui-content">
<p class="mui-content-padded">可将上传的图片一次性转化输出成多个指定高度/宽度的图片,每次上传文件会扣除一定数额的积分,积分可通过多种方式获取
<a l-href="https://www.betweenfriends.cn/view/mine/bonusrule.html">积分获取/使用规则</a>
</p>
<div class="mui-content-padded ">
<img :src="srcUri" style="max-width: 250px;" />
<div class="image-list">
<div class="image-item space">
<button type="button" class="mui-btn mui-btn-blue">点击上传</button>
<div class="file">
<form id="image_uploader"></form>
</div>
</div>
</div>
</div>
<p class="mui-content-padded">转换后的图片下载</p>
<ul class="mui-table-view">
<li v-for="format in formats" class="mui-table-view-cell mui-media">
<img class="mui-media-object mui-pull-left" :src="srcThumbnail">
<div class="mui-media-body">
<p>{{format.desc}}</p>
<button type="button" class="mui-btn mui-btn-link" @tap="deleteFormat(format)">删除样式</button>
<button type="button" class="mui-btn mui-btn-link" @tap="editFormat(format)">编辑样式</button>
<a class="mui-btn mui-btn-blue" :href="downUrl(format)" download="格式化图片">下载图片</a>
</div>
</li>
</ul>
<hr />
<p class="mui-content-padded" style="margin-top: 20px;">图片处理参数配置,可在此处新增图片样式</p>
<ul class="mui-table-view">
<li class="mui-table-view-cell mui-collapse" :class="{'mui-active':panelActive('scale')}" @tap="togglePanel('scale')">
<a class="mui-navigate-right">
缩放模式</a>
<ul class="mui-table-view mui-table-view-radio">
<li class="mui-table-view-cell" :class="{'mui-selected':isActiveFacs(9)}" @tap="setFacs(9,$event)">
<a class="mui-navigate-right">
按指定宽高值强行缩略,可能导致目标图片变形,width和height取值范围1-9999
</a>
</li>
<li class="mui-table-view-cell" :class="{'mui-selected':isActiveFacs(1)}" @tap="setFacs(1,$event)">
<a class="mui-navigate-right">
基于原图大小,按指定百分比缩放。Scale取值范围1-999
</a>
</li>
<li class="mui-table-view-cell" :class="{'mui-selected':isActiveFacs(2)}" @tap="setFacs(2,$event)">
<a class="mui-navigate-right">
以百分比形式指定目标图片宽度,高度不变。Scale取值范围1-999
</a>
</li>
<li class="mui-table-view-cell" :class="{'mui-selected':isActiveFacs(3)}" @tap="setFacs(3,$event)">
<a class="mui-navigate-right">
以百分比形式指定目标图片高度,宽度不变。Scale取值范围1-999
</a>
</li>
<li class="mui-table-view-cell" :class="{'mui-selected':isActiveFacs(4)}" @tap="setFacs(4,$event)">
<a class="mui-navigate-right">
指定目标图片宽度,高度等比缩放,Width取值范围1-9999
</a>
</li>
<li class="mui-table-view-cell" :class="{'mui-selected':isActiveFacs(5)}" @tap="setFacs(5,$event)">
<a class="mui-navigate-right">
指定目标图片高度,宽度等比缩放,Height取值范围1-9999
</a>
</li>
<li class="mui-table-view-cell" :class="{'mui-selected':isActiveFacs(7)}" @tap="setFacs(7,$event)">
<a class="mui-navigate-right">
等比缩放,比例值为宽缩放比和高缩放比的较小值,Width 和 Height 取值范围1-9999。 注意:宽缩放比:目标宽/原图宽 高缩放比:目标高/原图高
</a>
</li>
<li class="mui-table-view-cell" :class="{'mui-selected':isActiveFacs(8)}" @tap="setFacs(8,$event)">
<a class="mui-navigate-right">
等比缩放,比例值为宽缩放比和高缩放比的较大值,Width 和 Height 取值范围1-9999。 注意:宽缩放比:目标宽/原图宽 高缩放比:目标高/原图高
</a>
</li>
<li class="mui-table-view-cell" :class="{'mui-selected':isActiveFacs(10)}" @tap="setFacs(10,$event)">
<a class="mui-navigate-right">
等比缩小,比例值为宽缩放比和高缩放比的较小值。如果目标宽和高都大于原图宽和高,则不变,Width 和 Height 取值范围1-9999。 注意:宽缩放比:目标宽/原图宽 高缩放比:目标高/原图高;
</a>
</li>
<li class="mui-table-view-cell" :class="{'mui-selected':isActiveFacs(11)}" @tap="setFacs(11,$event)">
<a class="mui-navigate-right">
等比放大,比例值为宽缩放比和高缩放比的较小值。如果目标宽(高)小于原图宽(高),则不变,Width 和 Height 取值范围1-9999。 注意: 宽缩放比:目标宽/原图宽 高缩放比:目标高/原图高
</a>
</li>
<li class="mui-table-view-cell" :class="{'mui-selected':isActiveFacs(12)}" @tap="setFacs(12,$event)">
<a class="mui-navigate-right">
按原图高宽比例等比缩放,缩放后的像素数量不超过指定值,Area取值范围1-24999999
</a>
</li>
</ul>
</li>
</ul>
<p class="mui-content-padded" v-show="showInput">{{formatBuff.scaleType}}</p>
<form class="mui-input-group">
<div class="mui-input-row" v-show="showScale">
<label>缩放百分比</label>
<input type="number" v-model="formatBuff.scale" class="mui-input-clear" min="1" max="999" step="1" placeholder="取值1到999">
</div>
<div class="mui-input-row" v-show="showHeight">
<label>高度</label>
<input type="number" v-model="formatBuff.height" class="mui-input-clear" placeholder="高度,0表示根据宽度等比例缩放">
</div>
<div class="mui-input-row" v-show="showWidth">
<label>宽度</label>
<input type="number" v-model="formatBuff.width" class="mui-input-clear" placeholder="宽度,0表示根据高度等比例缩放">
</div>
<div class="mui-input-row" v-show="showArea">
<label>像素限制</label>
<input type="number" v-model="formatBuff.area" class="mui-input-clear" placeholder="只对jpg有效">
</div>
<div class="mui-input-row" v-show="showInput">
<label>图片质量</label>
<input type="number" v-model="formatBuff.quality" class="mui-input-clear" min="1" max="100" placeholder="从1到100,默认75">
</div>
<div class="mui-input-row" v-show="showInput">
<label>输出文件格式</label>
<input type="text" class="mui-input-clear" v-model="formatBuff.suffix" placeholder="默认为原图格式,如jpg,非法格式可能导致出错">
</div>
<div class="mui-input-row" v-show="showInput">
<label>格式说明</label>
<input type="text" class="mui-input-clear" v-model="formatBuff.desc" placeholder="格式说明,用途说明等,将作为该格式的备注显示">
</div>
<div class="mui-button-row">
<button type="button" class="mui-btn mui-btn-link " v-show="showInput&&isEdit" @tap="submitNewFormat">放弃修改</button>
<button type="button" class="mui-btn mui-btn-blue " v-show="showInput" @tap="submitNewFormat">{{saveBtnText}}</button>
</div>
</form>
</div>
<div class="mui-text-center" style="margin-top: 30px; bottom: 0px;width: 100%;">
© 2017 -
<a l-href="https://www.betweenfriends.cn"> 友间共享 </a>
<a l-href="https://blog.betweenfriends.cn/about"> 关于我们 </a> - 闽ICP备17012098号-1
</div>
</body>
</html>
代码解读
- 利用mui控制UI的布局和渲染展示
- vue负责绑定ui和后台数据,并跟踪数据变化
- Page是我自己定义的框架,源码就不方便分享了,简单的实现参考怎么实现一站式跨平台开发
原文地址:https://blog.betweenfriends.cn/post/crossdomaindev.html
前言
这只是个人的经验总结和分享,并不是,也没时间做一个完整的教程。
分享的是我在实际项目开发中碰到的杂七杂八的问题,仅供参考。
一个简单的图片压缩工具
在线地址: 图片压缩工具-友间共享
在工作过程中,难免会碰到需要为同一个图片生成多种分辨率的情形,比如打包app之前需要准备好的各类图标,虽然简单,但是费点时间在所难免,就自己做了一个小工具,主要功能如下:
- 可以自定义处理后的图片的分辨率和压缩方式等,自定义的样式自动保存,下次可以重复使用。
- 一键上传图片,根据预设的样式批量生成处理结果,根据需要再自行下载
开发环境
- vue+mui+webpack+npm+macos
- 后台服务: 七牛云存储
运行环境
在线服务,可在支持h5的浏览器上运行,电脑,手机平板理论上都可以
在线地址: 图片压缩工具-友间共享
实现原理
其实很简单,就是先上传图片到七牛云服务
然后在页面上提供配置页面,保存用户配置的格式,然后把每个格式都转化成七牛的图片转化服务的格式化字符串,最后把这个字符串和图片的原地址合并成图片下载链接,就可以在点击链接时调用七牛的图片处理服务,按照我们设定的格式下载转化后的图片。
项目目录结构
** 详细目录结构介绍和开发环境部署参考 怎么搭建vue和Mui的多页面开发环境
主要代码
引入vue,mui等库
import LContext from 'lui/context.js'
import Vue from 'vue'
import 'babel-polyfill'
import Vuex from 'vuex'
import $ from './mui/mui.min'
require('../css/mui.min.css')
require('../css/icons-extra.css')
//require('../css/iconfont.css')
//require('../css/app.css')
require('../css/app.less')
window.Vue = Vue
window.Vuex = Vuex
window.$ = $
window.mui = $
require('./mui/mui.pullToRefresh')
require('./mui/mui.pullToRefresh.material')
//加载BASE64
require('exports-loader!./util/base64.js')
Vue.use(Vuex)
//import LoginDialog from 'app/Login'
if(process.env.NODE_ENV === 'production') {
Vue.config.productionTip = false
}
有点偷懒,部分变量其实是可以在环境配置时引入的,这里就先忽略了,反正效果也一样
其中的库可根据需要引入,因为是从我自己的架构上COPY下来的,有些文件和库在这个项目中是可以不用引入的。引用的路径和webpack环境配置有关,以下是我的配置
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: { //定义别名,简易方式,可以在require调用时缩短路径
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
"page$": resolve('src/js/page.js'),
'app': resolve('src/components/'),
'lui': resolve('src/js/lui/'),
'mui': resolve('src/js/mui/'),
'util': resolve('src/js/util/')
}
},
output.js代码
import Page from 'page'
import Uploader from 'lui/upload.js'
var formVue = new Vue({
el: '.mui-content',
data: {
src: '',
formats: [],
formatBuff: {
facs: 9,
scaleType: '按指定宽高值强行缩略,可能导致目标图片变形,width和height取值范围1-9999'
}, //当前正在编辑的图片类型
collapsePanels: {
scale: false
},
logined: false
},
computed: {
showScale: function() {
switch(this.formatBuff.facs) {
case 1:
return true;
case 2:
return true;
case 3:
return true;
default:
break;
}
return false;
},
showHeight: function() {
switch(this.formatBuff.facs) {
case 5:
return true;
case 7:
return true;
case 8:
return true;
case 9:
return true;
case 10:
return true;
case 11:
return true;
default:
break;
}
return false;
},
showWidth: function() {
switch(this.formatBuff.facs) {
case 4:
return true;
case 7:
return true;
case 8:
return true;
case 9:
return true;
case 10:
return true;
case 11:
return true;
default:
break;
}
return false
},
showArea: function() {
switch(this.formatBuff.facs) {
case 12:
return true;
default:
break;
}
return false;
},
showInput: function() {
if(this.formatBuff.facs > 0) {
return true
}
return false
},
srcUri: function() {
if(this.src) {
return LContext.fileServer + this.src + LContext.image.Thumbnail
}
return ''
},
srcThumbnail: function() {
if(this.src) {
return LContext.fileServer + this.src +
LContext.image.Thumbnail
}
return ''
},
isEdit: function() {
if(this.formatBuff.uid) {
return true
}
return false
},
saveBtnText: function() {
console.log(this.isEdit + ' edit')
if(this.isEdit) {
return '保存修改'
} else {
return '保存新建样式'
}
}
},
methods: {
downLoad: function(format) {
var _format = this.decodeFormat(format)
if(_format.length > 2) {
lpage.open(LContext.fileServer + this.src + '?imageMogr2' + _format, undefined, 'new')
} else {
lpage.alert('下载格式无效!')
}
},
downUrl: function(format) {
var _format = this.decodeFormat(format)
if(_format.length > 2) {
return LContext.fileServer + this.src + '?imageMogr2' + _format
} else {
return false
}
},
deleteFormat: function(format) {
for(var i = 0; i < this.formats.length; i++) {
if(this.formats[i].uid === format.uid) {
this.formats.splice(i, 1)
lpage.saveFormats()
}
}
},
setFacs: function(facs, event) {
// this.formatBuff.facs = parseInt(facs, 10)
Vue.set(this.formatBuff, 'facs', parseInt(facs, 10))
Vue.set(this.formatBuff, 'scaleType', event.currentTarget.innerText)
Vue.nextTick(function() {
this.closePanel('scale')
}.bind(this))
// console.log(JSON.stringify(this.formatBuff))
},
decodeFormat: function(format) {
//缩放
var formatStr = '/thumbnail/'
switch(format.facs) {
case 1:
formatStr += '!' + format.scale + 'p'
break;
case 2:
formatStr += '!' + format.scale + 'px'
break;
case 3:
formatStr += '!x' + format.scale + 'p'
break;
case 4:
formatStr += format.width + 'x'
break;
case 5:
formatStr += 'x' + format.height
break;
case 7:
formatStr += format.width + 'x' + format.height
break;
case 8:
formatStr += '!' + format.width + 'x' + format.height
break;
case 9:
formatStr += format.width + 'x' + format.height + '!'
break;
case 10:
formatStr += format.width + 'x' + format.height + '>'
break;
case 11:
formatStr += format.width + 'x' + format.height + '<'
break;
case 12:
formatStr += format.area + '@'
break;
default:
formatStr = ''
break;
}
//格式转换
if(format.suffix !== 'auto') {
formatStr += '/format/' + format.suffix
}
return formatStr
},
isActiveFacs: function(facs) {
if(this.formatBuff.facs === facs) {
return true
}
return false
},
panelActive: function(collapseList) {
return this.collapsePanels[collapseList]
},
togglePanel: function(collapseList) {
Vue.set(this.collapsePanels, collapseList, !this.collapsePanels[collapseList])
},
closePanel: function(collapseList) {
Vue.set(this.collapsePanels, collapseList, false)
},
submitNewFormat: function() {
var newFormat = {
uid: 'format_' + new Date().getTime(),
height: this.formatBuff.height,
width: this.formatBuff.width,
scale: this.formatBuff.scale,
area: this.formatBuff.area,
facs: this.formatBuff.facs,
desc: this.formatBuff.desc,
scaleType: this.formatBuff.scaleType,
suffix: this.formatBuff.suffix ? this.formatBuff.suffix : 'auto', //图片类型
quality: this.formatBuff.quality ? this.formatBuff.quality : 75 //图片质量
}
var change = false
if(this.formatBuff.uid) {
for(var i = 0; i < this.formats.length; i++) {
if(this.formats[i].uid === this.formatBuff.uid) {
newFormat.uid = this.formatBuff.uid
this.formatBuff.uid = undefined
Vue.set(this.formats, i, newFormat)
change = true
}
}
}!change && this.formats.push(newFormat)
lpage.saveFormats()
},
editFormat: function(format) {
Vue.set(this.formatBuff, 'uid', format.uid)
Vue.set(this.formatBuff, 'height', format.height)
Vue.set(this.formatBuff, 'width', format.width)
Vue.set(this.formatBuff, 'scale', format.scale)
Vue.set(this.formatBuff, 'area', format.area)
Vue.set(this.formatBuff, 'facs', format.facs)
Vue.set(this.formatBuff, 'desc', format.desc)
Vue.set(this.formatBuff, 'scaleType', format.scaleType)
Vue.set(this.formatBuff, 'suffix', format.suffix === 'auto' ? undefined : format.suffix)
Vue.set(this.formatBuff, 'quality', format.quality ? format.quality : 75)
}
}
})
var pcPage = {
initUI: function() {
this.initUploader()
},
initData: function() {
// this.user.isLogin(function(logined) {
// if(logined) {
// formVue.logined = true
lpage.getFormats()
// } else {
// formVue.logined = false
// lpage.user.login()
// }
// })
},
initUploader: function() {
new Uploader({
selector: 'image_uploader',
token: {
mode: 'imagescale',
image: { //图片
prefix: '/utils/imagescale/'
}
},
success: function(data) {
formVue.src = data.key
lpage.saveFormats()
}
}).init()
},
saveFormats: function() {
lpage.setItem('_myFormats', JSON.stringify(formVue.formats))
lpage.setItem('_lastSrc', formVue.src)
},
getFormats: function() {
var _fmt = lpage.getItem('_myFormats')
if(!_fmt) {
_fmt = [{
'uid': 'format_1504082048978',
'height': '2208',
'width': '1242',
'scale': '50',
'facs': 9,
'desc': '苹果IphoneApp审核用的截屏图片1242*2208',
'scaleType': '按指定宽高值强行缩略,可能导致目标图片变形,width和height取值范围1-9999\n',
'suffix': 'auto',
'quality': '100'
}, {
'uid': 'format_1504144877541',
'height': '2732',
'width': '2048',
'scale': '50',
'facs': 9,
'desc': '苹果IpadApp审核用的截屏图片2048*2732',
'scaleType': '按指定宽高值强行缩略,可能导致目标图片变形,width和height取值范围1-9999\n',
'suffix': 'auto',
'quality': '100'
}]
Vue.set(formVue, 'formats', _fmt)
} else
if(_fmt) {
try {
_fmt = JSON.parse(_fmt)
Vue.set(formVue, 'formats', _fmt)
} catch(e) {
//TODO handle the exception
console.log('err')
}
}
_fmt = lpage.getItem('_lastSrc')
if(_fmt) {
formVue.src = _fmt
}
}
}
Page.init({
pc: pcPage
})
output.html源码
<!DOCTYPE html>
<html class="feedback">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1,user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<title>友间共享-图片处理</title>
<style>
.mui-content .mui-table-view-radio .mui-table-view-cell>a:not(.mui-btn) {
text-align: left;
white-space: normal;
}
</style>
</head>
<body>
<header class="mui-bar mui-bar-nav">
<a class="mui-action-back mui-btn mui-btn-link mui-btn-nav mui-pull-left"><span class=" mui-icon mui-icon-left-nav "></span> </a>
<h1 class="mui-title">友间共享-图片处理</h1>
</header>
<div class="mui-content">
<p class="mui-content-padded">可将上传的图片一次性转化输出成多个指定高度/宽度的图片,每次上传文件会扣除一定数额的积分,积分可通过多种方式获取
<a l-href="https://www.betweenfriends.cn/view/mine/bonusrule.html">积分获取/使用规则</a>
</p>
<div class="mui-content-padded ">
<img :src="srcUri" style="max-width: 250px;" />
<div class="image-list">
<div class="image-item space">
<button type="button" class="mui-btn mui-btn-blue">点击上传</button>
<div class="file">
<form id="image_uploader"></form>
</div>
</div>
</div>
</div>
<p class="mui-content-padded">转换后的图片下载</p>
<ul class="mui-table-view">
<li v-for="format in formats" class="mui-table-view-cell mui-media">
<img class="mui-media-object mui-pull-left" :src="srcThumbnail">
<div class="mui-media-body">
<p>{{format.desc}}</p>
<button type="button" class="mui-btn mui-btn-link" @tap="deleteFormat(format)">删除样式</button>
<button type="button" class="mui-btn mui-btn-link" @tap="editFormat(format)">编辑样式</button>
<a class="mui-btn mui-btn-blue" :href="downUrl(format)" download="格式化图片">下载图片</a>
</div>
</li>
</ul>
<hr />
<p class="mui-content-padded" style="margin-top: 20px;">图片处理参数配置,可在此处新增图片样式</p>
<ul class="mui-table-view">
<li class="mui-table-view-cell mui-collapse" :class="{'mui-active':panelActive('scale')}" @tap="togglePanel('scale')">
<a class="mui-navigate-right">
缩放模式</a>
<ul class="mui-table-view mui-table-view-radio">
<li class="mui-table-view-cell" :class="{'mui-selected':isActiveFacs(9)}" @tap="setFacs(9,$event)">
<a class="mui-navigate-right">
按指定宽高值强行缩略,可能导致目标图片变形,width和height取值范围1-9999
</a>
</li>
<li class="mui-table-view-cell" :class="{'mui-selected':isActiveFacs(1)}" @tap="setFacs(1,$event)">
<a class="mui-navigate-right">
基于原图大小,按指定百分比缩放。Scale取值范围1-999
</a>
</li>
<li class="mui-table-view-cell" :class="{'mui-selected':isActiveFacs(2)}" @tap="setFacs(2,$event)">
<a class="mui-navigate-right">
以百分比形式指定目标图片宽度,高度不变。Scale取值范围1-999
</a>
</li>
<li class="mui-table-view-cell" :class="{'mui-selected':isActiveFacs(3)}" @tap="setFacs(3,$event)">
<a class="mui-navigate-right">
以百分比形式指定目标图片高度,宽度不变。Scale取值范围1-999
</a>
</li>
<li class="mui-table-view-cell" :class="{'mui-selected':isActiveFacs(4)}" @tap="setFacs(4,$event)">
<a class="mui-navigate-right">
指定目标图片宽度,高度等比缩放,Width取值范围1-9999
</a>
</li>
<li class="mui-table-view-cell" :class="{'mui-selected':isActiveFacs(5)}" @tap="setFacs(5,$event)">
<a class="mui-navigate-right">
指定目标图片高度,宽度等比缩放,Height取值范围1-9999
</a>
</li>
<li class="mui-table-view-cell" :class="{'mui-selected':isActiveFacs(7)}" @tap="setFacs(7,$event)">
<a class="mui-navigate-right">
等比缩放,比例值为宽缩放比和高缩放比的较小值,Width 和 Height 取值范围1-9999。 注意:宽缩放比:目标宽/原图宽 高缩放比:目标高/原图高
</a>
</li>
<li class="mui-table-view-cell" :class="{'mui-selected':isActiveFacs(8)}" @tap="setFacs(8,$event)">
<a class="mui-navigate-right">
等比缩放,比例值为宽缩放比和高缩放比的较大值,Width 和 Height 取值范围1-9999。 注意:宽缩放比:目标宽/原图宽 高缩放比:目标高/原图高
</a>
</li>
<li class="mui-table-view-cell" :class="{'mui-selected':isActiveFacs(10)}" @tap="setFacs(10,$event)">
<a class="mui-navigate-right">
等比缩小,比例值为宽缩放比和高缩放比的较小值。如果目标宽和高都大于原图宽和高,则不变,Width 和 Height 取值范围1-9999。 注意:宽缩放比:目标宽/原图宽 高缩放比:目标高/原图高;
</a>
</li>
<li class="mui-table-view-cell" :class="{'mui-selected':isActiveFacs(11)}" @tap="setFacs(11,$event)">
<a class="mui-navigate-right">
等比放大,比例值为宽缩放比和高缩放比的较小值。如果目标宽(高)小于原图宽(高),则不变,Width 和 Height 取值范围1-9999。 注意: 宽缩放比:目标宽/原图宽 高缩放比:目标高/原图高
</a>
</li>
<li class="mui-table-view-cell" :class="{'mui-selected':isActiveFacs(12)}" @tap="setFacs(12,$event)">
<a class="mui-navigate-right">
按原图高宽比例等比缩放,缩放后的像素数量不超过指定值,Area取值范围1-24999999
</a>
</li>
</ul>
</li>
</ul>
<p class="mui-content-padded" v-show="showInput">{{formatBuff.scaleType}}</p>
<form class="mui-input-group">
<div class="mui-input-row" v-show="showScale">
<label>缩放百分比</label>
<input type="number" v-model="formatBuff.scale" class="mui-input-clear" min="1" max="999" step="1" placeholder="取值1到999">
</div>
<div class="mui-input-row" v-show="showHeight">
<label>高度</label>
<input type="number" v-model="formatBuff.height" class="mui-input-clear" placeholder="高度,0表示根据宽度等比例缩放">
</div>
<div class="mui-input-row" v-show="showWidth">
<label>宽度</label>
<input type="number" v-model="formatBuff.width" class="mui-input-clear" placeholder="宽度,0表示根据高度等比例缩放">
</div>
<div class="mui-input-row" v-show="showArea">
<label>像素限制</label>
<input type="number" v-model="formatBuff.area" class="mui-input-clear" placeholder="只对jpg有效">
</div>
<div class="mui-input-row" v-show="showInput">
<label>图片质量</label>
<input type="number" v-model="formatBuff.quality" class="mui-input-clear" min="1" max="100" placeholder="从1到100,默认75">
</div>
<div class="mui-input-row" v-show="showInput">
<label>输出文件格式</label>
<input type="text" class="mui-input-clear" v-model="formatBuff.suffix" placeholder="默认为原图格式,如jpg,非法格式可能导致出错">
</div>
<div class="mui-input-row" v-show="showInput">
<label>格式说明</label>
<input type="text" class="mui-input-clear" v-model="formatBuff.desc" placeholder="格式说明,用途说明等,将作为该格式的备注显示">
</div>
<div class="mui-button-row">
<button type="button" class="mui-btn mui-btn-link " v-show="showInput&&isEdit" @tap="submitNewFormat">放弃修改</button>
<button type="button" class="mui-btn mui-btn-blue " v-show="showInput" @tap="submitNewFormat">{{saveBtnText}}</button>
</div>
</form>
</div>
<div class="mui-text-center" style="margin-top: 30px; bottom: 0px;width: 100%;">
© 2017 -
<a l-href="https://www.betweenfriends.cn"> 友间共享 </a>
<a l-href="https://blog.betweenfriends.cn/about"> 关于我们 </a> - 闽ICP备17012098号-1
</div>
</body>
</html>
代码解读
- 利用mui控制UI的布局和渲染展示
- vue负责绑定ui和后台数据,并跟踪数据变化
- Page是我自己定义的框架,源码就不方便分享了,简单的实现参考怎么实现一站式跨平台开发
原文地址:https://blog.betweenfriends.cn/post/crossdomaindev.html
收起阅读 »
分享自动生成ios离线打包所需各种大小icon的gulp代码
离线打包时需要各种大小分辨率不同的启动图标,手动一个个制作太麻烦了。
经过我半天的研究,终于写出了可以自动生成各种所需启动图标的gulp代码,如下:
var gulp = require('gulp')
var imageResize = require('gulp-image-resize')
var rename = require('gulp-rename')
gulp.task('icon-ios', () => {
var sizes = [29, 40, 50, 57, 58, 72, 76, 80, 87, 100, 114, 120, 144, 152, 180]
sizes.forEach((size, index) => {
gulp.src('icon.png')
.pipe(imageResize({
width: size,
height: size,
corp: true
}))
.pipe(rename('icon'+size+'.png'))
.pipe(gulp.dest('dist'))
})
})
需要注意的是gulp-image-resize是需要额外安装两个依赖的,可以去官网查看:
gulp-image-resize
希望官方能把这段经验加到离线打包的文档里,防止后人走弯路
离线打包时需要各种大小分辨率不同的启动图标,手动一个个制作太麻烦了。
经过我半天的研究,终于写出了可以自动生成各种所需启动图标的gulp代码,如下:
var gulp = require('gulp')
var imageResize = require('gulp-image-resize')
var rename = require('gulp-rename')
gulp.task('icon-ios', () => {
var sizes = [29, 40, 50, 57, 58, 72, 76, 80, 87, 100, 114, 120, 144, 152, 180]
sizes.forEach((size, index) => {
gulp.src('icon.png')
.pipe(imageResize({
width: size,
height: size,
corp: true
}))
.pipe(rename('icon'+size+'.png'))
.pipe(gulp.dest('dist'))
})
})
需要注意的是gulp-image-resize是需要额外安装两个依赖的,可以去官网查看:
gulp-image-resize
希望官方能把这段经验加到离线打包的文档里,防止后人走弯路
收起阅读 »
怎么搭建vue和Mui的多页面开发环境
现在有很多的打包工具可以选择,grunt,gulp,webpack等等。vue官方建议是使用webpack,而且webpack相对其他打包工具的好处是代码动态编译,可以根据需要提取出公共部分的代码。因此我们也选择webpack作为打包工具。
目录结构
开发目录 src
- assets 静态资源,如图片等的保存
- css 样式文件,css,less等
- fonts 字体文件,根据需要添加自定义字体
- js js框架,公共部分代码,自定义组件等
5.view html页面文件,页面入口js文件
build 打包参数配置
主要用于对打包过程的控制
- webpack.base.conf.js 基础配置参数,开发和生成代码打包共用
- webpack.dev.conf.js 开发环境下的打包参数配置
- webpack.prod.conf.js 生产环境的打包参数配置
config 打包模式配置
主要是打包相关的基础参数配置,如文件存放目录,打包后的访问根目录,是否压缩等
assets 生产环境下的js/css/图片等文件保存路径
可在config中指定
view 生产环境下的页面文件Html保存路径
和src/view下的html文件一一对应
package.json 打包的环境依赖配置
使用方式
-
开发 npm run dev 开启本地web服务,方便调试页面和代码
-
生产环境打包 npm run build 将src下的代码打包到根目录下的 assets和view目录下
功能
-
支持vue开发的调试,支持webpack打包的调试和自动更新,不需要手动刷新代码
-
支持代码和语法检查,可在根目录的.eslintrc下配置检查规则
3.支持webpack的多页面(多入口)开发,相比单入口模式,逻辑更清楚
使用说明
1.view下的页面必须放在view的下级目录,比如view/index/index.html,同时每个页面文件必须搭配一个同名的js文件作为页面入口,比如view/index/index.js
2.可根据需要配置本地调试服务器的端口,默认8000,
在config/index下配置
3.可配置打包路径等,同样在config/index下配置
初始化说明
-
在根目录下执行 npm install (如果不是root用户的话,sudo npm install)
-
打包或者调试时,如果npm 命令提示错误,一般是某个模块未安装,可执行 npm install ***(模块名称) 安装相关模块
-
npm run dev (调试)
-
npm run build (正式打包)
下载完整目录
原文链接:https://blog.betweenfriends.cn/post/howtodevwithvueandmui.html
现在有很多的打包工具可以选择,grunt,gulp,webpack等等。vue官方建议是使用webpack,而且webpack相对其他打包工具的好处是代码动态编译,可以根据需要提取出公共部分的代码。因此我们也选择webpack作为打包工具。
目录结构
开发目录 src
- assets 静态资源,如图片等的保存
- css 样式文件,css,less等
- fonts 字体文件,根据需要添加自定义字体
- js js框架,公共部分代码,自定义组件等
5.view html页面文件,页面入口js文件
build 打包参数配置
主要用于对打包过程的控制
- webpack.base.conf.js 基础配置参数,开发和生成代码打包共用
- webpack.dev.conf.js 开发环境下的打包参数配置
- webpack.prod.conf.js 生产环境的打包参数配置
config 打包模式配置
主要是打包相关的基础参数配置,如文件存放目录,打包后的访问根目录,是否压缩等
assets 生产环境下的js/css/图片等文件保存路径
可在config中指定
view 生产环境下的页面文件Html保存路径
和src/view下的html文件一一对应
package.json 打包的环境依赖配置
使用方式
-
开发 npm run dev 开启本地web服务,方便调试页面和代码
-
生产环境打包 npm run build 将src下的代码打包到根目录下的 assets和view目录下
功能
-
支持vue开发的调试,支持webpack打包的调试和自动更新,不需要手动刷新代码
-
支持代码和语法检查,可在根目录的.eslintrc下配置检查规则
3.支持webpack的多页面(多入口)开发,相比单入口模式,逻辑更清楚
使用说明
1.view下的页面必须放在view的下级目录,比如view/index/index.html,同时每个页面文件必须搭配一个同名的js文件作为页面入口,比如view/index/index.js
2.可根据需要配置本地调试服务器的端口,默认8000,
在config/index下配置
3.可配置打包路径等,同样在config/index下配置
初始化说明
-
在根目录下执行 npm install (如果不是root用户的话,sudo npm install)
-
打包或者调试时,如果npm 命令提示错误,一般是某个模块未安装,可执行 npm install ***(模块名称) 安装相关模块
-
npm run dev (调试)
-
npm run build (正式打包)
下载完整目录
原文链接:https://blog.betweenfriends.cn/post/howtodevwithvueandmui.html
收起阅读 »
布局理念 - NView模板 - wap2app教程
布局容器
在NView模板中,<nview>标签是布局容器,其它控件都必须包裹在<nview>容器中;<nview>默认为块级元素(宽度为100%屏幕宽度),自上而下排列布局,现阶段必须声明nview的高度,不支持高度自适应。如下是一个示例
<nviews cachemaxage="86400">
<nview id="nview1" style="height:50px;backgroundColor:#56C1FF"></nview>
<nview id="nview2" style="height:100px;backgroundColor:#61D836"></nview>
<nview id="nview3" style="height:50px;backgroundColor:#EF5FA7"></nview>
</nviews>
如上代码布局效果如下(顶部自带原生标题栏):
除了默认的自上而下顺序布局,nview也支持绝对定位布局,如下示例中,将nview1设置为绝对定位,在窗口底部显示;
<nviews cachemaxage ="86400">
<nview id="nview1" style="position:absolute;bottom:0;height:50px;backgroundColor:#56C1FF"></nview>
<nview id="nview2" style="height:100px;backgroundColor:#61D836"></nview>
<nview id="nview3" style="height:50px;backgroundColor:#EF5FA7"></nview>
</nviews>
设置nview1为绝对定位后,运行示意图如下:
从运行结果可以看出,nview1设置为绝对定位后,脱离文档流自行定位;但nview2、nview3继续使用默认的自上而下的布局方式。
在nview布局容器下,可以嵌套imageslider、list、canvas、richtext四个子标签,子标签默认和nview容器具备相同的宽高;其中:
- imageslider/list是封装好的组件,标签及布局方式固定;
- canvas/richtext是布局控件,分别表示绝对布局/流式布局
接下来重点介绍 richtext/canvas两种布局控件
布局控件
先看如下代码,有两个nview,分别嵌套流式布局的richtext和绝对布局的canvas:
<nviews cachemaxage ="86400">
<nview id="nview_richtext" style="height:100px;backgroundColor:#56C1FF">
<richtext>
<font>Hello</font>
<font>World</font>
</richtext>
</nview>
<nview id="nview_canvas" style="height:100px;backgroundColor:#EF5FA7">
<canvas>
<font>Hello</font>
<font>World</font>
</canvas>
</nview>
</nviews>
运行结果如下:
从图中可以,richtext下的两个font流式排版,显示正常;但canvas下的两个font重叠在一起,这是因为canvas下的子标签默认为绝对定位,不进入文档流,多个子标签则会以多层的方式重叠排版;给canvas下子标签设置位置坐标即可正常布局,代码如下:
<nviews cachemaxage ="86400">
<nview id="nview_richtext" style="height:100px;backgroundColor:#56C1FF">
<richtext>
<font>Hello</font>
<font>World</font>
</richtext>
</nview>
<nview id="nview_canvas" style="height:100px;backgroundColor:#EF5FA7">
<canvas>
<!--设置坐标位置-->
<font style="left:5px;width:40px;">Hello</font>
<font style="left:45px;width:40px;">World</font>
</canvas>
</nview>
</nviews>
对应运行结果如下:
canvas绝对布局
canvas是绝对布局的容器标签,具有以下特点:
- 支持a、font、img、button、input、hr子标签
- 子标签全部绝对定位,需要声明标签相对父元素的相对坐标值
- 子标签大小由坐标固定,不会随着内容自动变化,若内容过长则自动裁剪(超出部分不可见)
如若nview标签下仅有一个canvas子标签,则canvas和nview默认具有相同的的大小/宽高信息。 如下是一个代码示例,演示canvas子标签如何定位:
<nviews cachemaxage ="86400">
<nview id="nview1" style="height:150px;background-color: #56C1FF;">
<canvas>
<font style="left:35px;top:35px;height:22px;align:left;font-size:17px;color:#ffffff">
这里是文字
</font>
<img src="_www/logo.png" style="top:60px;right:60px;width:60px;height:60px"/>
</canvas>
</nview>
<nview id="nview2" style="height:150px;background-color: #EF5FA7;">
<canvas>
<button style="left:50px;right:50px;top:70px;height:30px;background-color:rgba(0,0,0,0);border-color:#ffffff;color:#ffffff;">按钮</button>
</canvas>
</nview>
</nviews>
运行结果如下(为方便理解,标注了每个元素的坐标值,坐标值对应上面代码中的left/right/top等定义):
从上图可以看出:canvas布局控件下的元素,全部为精确定位,坐标值是相对于父容器的坐标(不是屏幕坐标)。
每个元素均需声明位置坐标
canvas布局控件下的每个子标签均需要声明坐标位置,否则每个标签将作为单独一层重叠绘制,如下是一个示例,创建两个nview,显示相同的元素,第一个不设置坐标位置,第二个设置坐标位置,示例代码如下:
<nviews cachemaxage ="86400">
<nview id="nview1" style="height:100px;background-color: #56C1FF;">
<canvas>
<!--未设置坐标位置-->
<font style="height:20px;align:left;color:#ffffff;font-size:17px;">作者:CHB</font>
<button style="width:50px;height:25px;background-color:#007aff;color:#ffffff;border-color:#007aff;">关注</button>
</canvas>
</nview>
<nview id="nview2" style="height:100px;background-color: #EF5FA7;">
<canvas>
<!--设置坐标位置-->
<font style="left:10px;top:10px;height:20px;align:left;color:#ffffff;font-size:17px;">作者:CHB</font>
<button style="left:100px;top:10px;width:50px;height:25px;background-color:#007aff;color:#ffffff;border-color:#007aff;">关注</button>
</canvas>
</nview>
</nviews>
运行结果如下:
因为每个元素均需要声明位置信息,因此canvas布局适合精确定位的场景,比如:居右显示;
逐层渲染,非流式
另一方面,canvas布局不适合可变长度的场景,如上示例中,若将"作者:CHB"替换为“作者:George R.R. Martin”,默认就会和右侧关注按钮重叠,代码如下:
<nviews cachemaxage ="86400">
<nview id="nview1" style="height:100px;background-color: #56C1FF;">
<canvas>
<font style="left:10px;top:10px;height:20px;align:left;color:#ffffff;font-size:17px;">作者:CHB</font>
<button style="left:100px;top:10px;width:50px;height:25px;background-color:#007aff;color:#ffffff;border-color:#007aff;">关注</button>
</canvas>
</nview>
<nview id="nview2" style="height:100px;background-color: #EF5FA7;">
<canvas>
<!--名字较长时,会重叠绘制-->
<font style="left:10px;top:10px;height:20px;align:left;color:#ffffff;font-size:17px;">作者:George R.R. Martin</font>
<button style="left:100px;top:10px;width:50px;height:25px;background-color:#007aff;color:#ffffff;border-color:#007aff;">关注</button>
</canvas>
</nview>
</nviews>
运行结果如下:
从上图可看出,关注按钮重叠在"George R.R. Martin”名字上方,这有如下两个原因:
- canvas下元素定位,类似于HTML5中的absolute定位,每个元素是按照坐标位置逐层绘制的,故关注按钮会和作者名字重叠,而不会像流式布局那样自动向右侧迁移;
- canvas下font标签默认宽度为100%,故可以将"George R.R. Martin”完整显示出来,而没有出现裁剪隐藏的情况;
richtext流式布局
richtext是流式布局的容器标签,有以下特点:
- 支持font、img、a、hr、br子标签;
- 各个子标签自左向右、自上向下流式排版;
- 子标签宽度和高度随内容自动变化,设置width/height属性无效(img标签例外),碰到较长文本时会自动换行;
- 支持通过空格( )来设置元素前后间距
- 设置位置坐标(left/top等)无效
如下是一个richtext示例:
<nviews cacheMaxAge="86400">
<nview id="nview_richtext" style="height:250px;background-color: #56C1FF;">
<richtext style="left:10px;right:10px;width:340px;top:10px">
<font style="font-size:23px;color:#ffffff;font-weight: bold;">这是一级标题,内容较长时会自动换行</font>
<br/><br/>
<img src="_www/logo.png" width="20px" height="20px"></img>
<font style="font-size: 17px;color:#ffffff"> 作者:CHB </font>
<font style="font-size: 15px;color:#ffffff">2017-09-04</font>
<br/>
<hr style="border-color:#EF5FA7"/>
<br/>
<font style="font-size:14px;color:#ffffff">原文链接:</font><a style="font-size:14px;color:#ffffff">http://www.example.com</a>
<br/><br/>
<font style="font-size:14px;color:#ffffff">下面是详细内容,文字较长时会自动进行换行,可变长度的文字推荐使用richtext布局控件...</font>
</richtext>
</nview>
</nviews>
如上代码中,头像信息、作者信息、发布时间是顺序编写的,最终自动从左到右绘制在一行,运行结果如下:
因为设置位置坐标无效,故无法实现精确定位,比如要求发布时间居右显示,则在richtext中无法实现;
两种布局适用场景
通过如上分析,可以理解两种布局适用的场景不同:
- 需要多个元素自左向右显示,元素长度不固定,则使用richtext
- 文本长度不确定,需要自动换行,则使用richtext
- 图文混排,则使用richtext
- 需要精确定位(如右侧对齐),则使用canvas
布局容器
在NView模板中,<nview>标签是布局容器,其它控件都必须包裹在<nview>容器中;<nview>默认为块级元素(宽度为100%屏幕宽度),自上而下排列布局,现阶段必须声明nview的高度,不支持高度自适应。如下是一个示例
<nviews cachemaxage="86400">
<nview id="nview1" style="height:50px;backgroundColor:#56C1FF"></nview>
<nview id="nview2" style="height:100px;backgroundColor:#61D836"></nview>
<nview id="nview3" style="height:50px;backgroundColor:#EF5FA7"></nview>
</nviews>
如上代码布局效果如下(顶部自带原生标题栏):
除了默认的自上而下顺序布局,nview也支持绝对定位布局,如下示例中,将nview1设置为绝对定位,在窗口底部显示;
<nviews cachemaxage ="86400">
<nview id="nview1" style="position:absolute;bottom:0;height:50px;backgroundColor:#56C1FF"></nview>
<nview id="nview2" style="height:100px;backgroundColor:#61D836"></nview>
<nview id="nview3" style="height:50px;backgroundColor:#EF5FA7"></nview>
</nviews>
设置nview1为绝对定位后,运行示意图如下:
从运行结果可以看出,nview1设置为绝对定位后,脱离文档流自行定位;但nview2、nview3继续使用默认的自上而下的布局方式。
在nview布局容器下,可以嵌套imageslider、list、canvas、richtext四个子标签,子标签默认和nview容器具备相同的宽高;其中:
- imageslider/list是封装好的组件,标签及布局方式固定;
- canvas/richtext是布局控件,分别表示绝对布局/流式布局
接下来重点介绍 richtext/canvas两种布局控件
布局控件
先看如下代码,有两个nview,分别嵌套流式布局的richtext和绝对布局的canvas:
<nviews cachemaxage ="86400">
<nview id="nview_richtext" style="height:100px;backgroundColor:#56C1FF">
<richtext>
<font>Hello</font>
<font>World</font>
</richtext>
</nview>
<nview id="nview_canvas" style="height:100px;backgroundColor:#EF5FA7">
<canvas>
<font>Hello</font>
<font>World</font>
</canvas>
</nview>
</nviews>
运行结果如下:
从图中可以,richtext下的两个font流式排版,显示正常;但canvas下的两个font重叠在一起,这是因为canvas下的子标签默认为绝对定位,不进入文档流,多个子标签则会以多层的方式重叠排版;给canvas下子标签设置位置坐标即可正常布局,代码如下:
<nviews cachemaxage ="86400">
<nview id="nview_richtext" style="height:100px;backgroundColor:#56C1FF">
<richtext>
<font>Hello</font>
<font>World</font>
</richtext>
</nview>
<nview id="nview_canvas" style="height:100px;backgroundColor:#EF5FA7">
<canvas>
<!--设置坐标位置-->
<font style="left:5px;width:40px;">Hello</font>
<font style="left:45px;width:40px;">World</font>
</canvas>
</nview>
</nviews>
对应运行结果如下:
canvas绝对布局
canvas是绝对布局的容器标签,具有以下特点:
- 支持a、font、img、button、input、hr子标签
- 子标签全部绝对定位,需要声明标签相对父元素的相对坐标值
- 子标签大小由坐标固定,不会随着内容自动变化,若内容过长则自动裁剪(超出部分不可见)
如若nview标签下仅有一个canvas子标签,则canvas和nview默认具有相同的的大小/宽高信息。 如下是一个代码示例,演示canvas子标签如何定位:
<nviews cachemaxage ="86400">
<nview id="nview1" style="height:150px;background-color: #56C1FF;">
<canvas>
<font style="left:35px;top:35px;height:22px;align:left;font-size:17px;color:#ffffff">
这里是文字
</font>
<img src="_www/logo.png" style="top:60px;right:60px;width:60px;height:60px"/>
</canvas>
</nview>
<nview id="nview2" style="height:150px;background-color: #EF5FA7;">
<canvas>
<button style="left:50px;right:50px;top:70px;height:30px;background-color:rgba(0,0,0,0);border-color:#ffffff;color:#ffffff;">按钮</button>
</canvas>
</nview>
</nviews>
运行结果如下(为方便理解,标注了每个元素的坐标值,坐标值对应上面代码中的left/right/top等定义):
从上图可以看出:canvas布局控件下的元素,全部为精确定位,坐标值是相对于父容器的坐标(不是屏幕坐标)。
每个元素均需声明位置坐标
canvas布局控件下的每个子标签均需要声明坐标位置,否则每个标签将作为单独一层重叠绘制,如下是一个示例,创建两个nview,显示相同的元素,第一个不设置坐标位置,第二个设置坐标位置,示例代码如下:
<nviews cachemaxage ="86400">
<nview id="nview1" style="height:100px;background-color: #56C1FF;">
<canvas>
<!--未设置坐标位置-->
<font style="height:20px;align:left;color:#ffffff;font-size:17px;">作者:CHB</font>
<button style="width:50px;height:25px;background-color:#007aff;color:#ffffff;border-color:#007aff;">关注</button>
</canvas>
</nview>
<nview id="nview2" style="height:100px;background-color: #EF5FA7;">
<canvas>
<!--设置坐标位置-->
<font style="left:10px;top:10px;height:20px;align:left;color:#ffffff;font-size:17px;">作者:CHB</font>
<button style="left:100px;top:10px;width:50px;height:25px;background-color:#007aff;color:#ffffff;border-color:#007aff;">关注</button>
</canvas>
</nview>
</nviews>
运行结果如下:
因为每个元素均需要声明位置信息,因此canvas布局适合精确定位的场景,比如:居右显示;
逐层渲染,非流式
另一方面,canvas布局不适合可变长度的场景,如上示例中,若将"作者:CHB"替换为“作者:George R.R. Martin”,默认就会和右侧关注按钮重叠,代码如下:
<nviews cachemaxage ="86400">
<nview id="nview1" style="height:100px;background-color: #56C1FF;">
<canvas>
<font style="left:10px;top:10px;height:20px;align:left;color:#ffffff;font-size:17px;">作者:CHB</font>
<button style="left:100px;top:10px;width:50px;height:25px;background-color:#007aff;color:#ffffff;border-color:#007aff;">关注</button>
</canvas>
</nview>
<nview id="nview2" style="height:100px;background-color: #EF5FA7;">
<canvas>
<!--名字较长时,会重叠绘制-->
<font style="left:10px;top:10px;height:20px;align:left;color:#ffffff;font-size:17px;">作者:George R.R. Martin</font>
<button style="left:100px;top:10px;width:50px;height:25px;background-color:#007aff;color:#ffffff;border-color:#007aff;">关注</button>
</canvas>
</nview>
</nviews>
运行结果如下:
从上图可看出,关注按钮重叠在"George R.R. Martin”名字上方,这有如下两个原因:
- canvas下元素定位,类似于HTML5中的absolute定位,每个元素是按照坐标位置逐层绘制的,故关注按钮会和作者名字重叠,而不会像流式布局那样自动向右侧迁移;
- canvas下font标签默认宽度为100%,故可以将"George R.R. Martin”完整显示出来,而没有出现裁剪隐藏的情况;
richtext流式布局
richtext是流式布局的容器标签,有以下特点:
- 支持font、img、a、hr、br子标签;
- 各个子标签自左向右、自上向下流式排版;
- 子标签宽度和高度随内容自动变化,设置width/height属性无效(img标签例外),碰到较长文本时会自动换行;
- 支持通过空格( )来设置元素前后间距
- 设置位置坐标(left/top等)无效
如下是一个richtext示例:
<nviews cacheMaxAge="86400">
<nview id="nview_richtext" style="height:250px;background-color: #56C1FF;">
<richtext style="left:10px;right:10px;width:340px;top:10px">
<font style="font-size:23px;color:#ffffff;font-weight: bold;">这是一级标题,内容较长时会自动换行</font>
<br/><br/>
<img src="_www/logo.png" width="20px" height="20px"></img>
<font style="font-size: 17px;color:#ffffff"> 作者:CHB </font>
<font style="font-size: 15px;color:#ffffff">2017-09-04</font>
<br/>
<hr style="border-color:#EF5FA7"/>
<br/>
<font style="font-size:14px;color:#ffffff">原文链接:</font><a style="font-size:14px;color:#ffffff">http://www.example.com</a>
<br/><br/>
<font style="font-size:14px;color:#ffffff">下面是详细内容,文字较长时会自动进行换行,可变长度的文字推荐使用richtext布局控件...</font>
</richtext>
</nview>
</nviews>
如上代码中,头像信息、作者信息、发布时间是顺序编写的,最终自动从左到右绘制在一行,运行结果如下:
因为设置位置坐标无效,故无法实现精确定位,比如要求发布时间居右显示,则在richtext中无法实现;
两种布局适用场景
通过如上分析,可以理解两种布局适用的场景不同:
- 需要多个元素自左向右显示,元素长度不固定,则使用richtext
- 文本长度不确定,需要自动换行,则使用richtext
- 图文混排,则使用richtext
- 需要精确定位(如右侧对齐),则使用canvas

mui两种预加载详解和爬坑
官方文档上的解释如下:
方式一:通过mui.init方法中的preloadPages参数进行配置.
mui.init({
preloadPages:[
{
url:prelaod-page-url,
id:preload-page-id,
styles:{},//窗口参数
extras:{},//自定义扩展参数
subpages:[{},{}]//预加载页面的子页面
}
],
preloadLimit:5//预加载窗口数量限制(一旦超出,先进先出)默认不限制
});
方式二:通过mui.preload方法预加载.
var page = mui.preload({
url:new-page-url,
id:new-page-id,//默认使用当前页面的url作为id
styles:{},//窗口参数
extras:{}//自定义扩展参数
});
方式一多页面加载问题如下

方式二preload需要放在plusready里面,解决如下
官方文档上的解释如下:
方式一:通过mui.init方法中的preloadPages参数进行配置.
mui.init({
preloadPages:[
{
url:prelaod-page-url,
id:preload-page-id,
styles:{},//窗口参数
extras:{},//自定义扩展参数
subpages:[{},{}]//预加载页面的子页面
}
],
preloadLimit:5//预加载窗口数量限制(一旦超出,先进先出)默认不限制
});
方式二:通过mui.preload方法预加载.
var page = mui.preload({
url:new-page-url,
id:new-page-id,//默认使用当前页面的url作为id
styles:{},//窗口参数
extras:{}//自定义扩展参数
});
方式一多页面加载问题如下
方式二preload需要放在plusready里面,解决如下
收起阅读 »

刚看到的一篇关于手机设置禁止横屏的解决方案,值得收藏!!!
解决横屏问题:
(转载)
真机运行时,manifest并不会实时生效,要打包才生效。
横屏有3个层级:
- 手机禁止横屏
- 手机允许横屏,但manifest禁止横屏
- 手机允许横屏、manifest允许横屏,但页面代码禁止横屏。
js里控制:
//仅支持横屏显示
plus.screen.lockOrientation("landscape-primary");
//仅支持横屏反方向显示
plus.screen.lockOrientation('landscape-secondary');
//仅支持竖屏显示
plus.screen.lockOrientation("portrait-primary");
//仅支持竖屏反方向显示
plus.screen.lockOrientation("portrait-secondary");
或(该方式未经测试)
// 锁定屏幕为竖屏模式,不能设备如何旋转,屏幕都不会切换到横屏模式。
window.screen.lockOrientation([“portrait-primary”,“portrait-secondary”]);
// 锁定屏幕为横屏模式,无能设备如何旋转,屏幕都不会切换到竖屏模式。
window.screen.lockOrientation([“landscape-primary”,“landscape-secondary”]);
// 取消屏幕的锁屏,屏幕回到原始状态,
window.screen.unlockOrientation();
manifest.json里控制:
"orientation": [
"portrait-primary",
"portrait-secondary"
]
该文转载地址:http://ask.dcloud.net.cn/article/522
解决横屏问题:
(转载)
真机运行时,manifest并不会实时生效,要打包才生效。
横屏有3个层级:
- 手机禁止横屏
- 手机允许横屏,但manifest禁止横屏
- 手机允许横屏、manifest允许横屏,但页面代码禁止横屏。
js里控制:
//仅支持横屏显示
plus.screen.lockOrientation("landscape-primary");
//仅支持横屏反方向显示
plus.screen.lockOrientation('landscape-secondary');
//仅支持竖屏显示
plus.screen.lockOrientation("portrait-primary");
//仅支持竖屏反方向显示
plus.screen.lockOrientation("portrait-secondary");
或(该方式未经测试)
// 锁定屏幕为竖屏模式,不能设备如何旋转,屏幕都不会切换到横屏模式。
window.screen.lockOrientation([“portrait-primary”,“portrait-secondary”]);
// 锁定屏幕为横屏模式,无能设备如何旋转,屏幕都不会切换到竖屏模式。
window.screen.lockOrientation([“landscape-primary”,“landscape-secondary”]);
// 取消屏幕的锁屏,屏幕回到原始状态,
window.screen.unlockOrientation();
manifest.json里控制:
"orientation": [
"portrait-primary",
"portrait-secondary"
]
该文转载地址:http://ask.dcloud.net.cn/article/522

承接MUI App,软件开发,微信开发
腾印网络致力于中小企业电商服务,软件开发,系统开发,提供一站式整体解决方案。
服务范围包括:网站建设,APP开发,微信开发,软件定制,系统定制 等
服务产品
PC端:网站建设,行业网站,电商平台
移动端:手机网站,手机APP
微信开发:微官网,微商城,公众号,小程序
系统开发:直播系统,点播系统,进销存系统 等
成功案例:电商类、视频类、在线教育类、生活服务类、游戏下载类等APP
QQ:1776609688
腾印网络致力于中小企业电商服务,软件开发,系统开发,提供一站式整体解决方案。
服务范围包括:网站建设,APP开发,微信开发,软件定制,系统定制 等
服务产品
PC端:网站建设,行业网站,电商平台
移动端:手机网站,手机APP
微信开发:微官网,微商城,公众号,小程序
系统开发:直播系统,点播系统,进销存系统 等
成功案例:电商类、视频类、在线教育类、生活服务类、游戏下载类等APP
QQ:1776609688
收起阅读 »
mui(准确的说是html5+)Android原生日历提醒插入案例踩坑经历
- 缘起
需要在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);
- 最后说一句
- 打包的时候记得勾选日历权限
- 这个问题坑死我了

分享一个图片在线缩放压缩工具
功能
使用场景
工具入口
功能
上次图片,可自动生成多种分辨率、大小的图片
可自由的增加、删除和修改要生成的图片的分辨率和大小
设置的图片生成分辨率和大小可重复使用,只需上传不同的图片,即可针对当前图片生成配置好的图片分辨率和样式
多种压缩方式可以选择,操作简便
使用场景
在平时的工作中,经常会碰到需要对同一张图片生成多种分辨率,特别是需要对好多图片都生成同样的分辨率的时候,就需要重复无数次傻瓜的操作。
针对这种情况,使用可配置的图片批量缩放处理工具,可以极大的提高工作效率,特别是对于不熟悉各类图片处理软件的朋友来说,会有较大帮助。
本文链接:https://blog.betweenfriends.cn/post/onlinecompressimage.html
功能
使用场景
工具入口
功能
上次图片,可自动生成多种分辨率、大小的图片
可自由的增加、删除和修改要生成的图片的分辨率和大小
设置的图片生成分辨率和大小可重复使用,只需上传不同的图片,即可针对当前图片生成配置好的图片分辨率和样式
多种压缩方式可以选择,操作简便
使用场景
在平时的工作中,经常会碰到需要对同一张图片生成多种分辨率,特别是需要对好多图片都生成同样的分辨率的时候,就需要重复无数次傻瓜的操作。
针对这种情况,使用可配置的图片批量缩放处理工具,可以极大的提高工作效率,特别是对于不熟悉各类图片处理软件的朋友来说,会有较大帮助。
本文链接:https://blog.betweenfriends.cn/post/onlinecompressimage.html
收起阅读 »
原生轮播示例(slider-native)
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的位置查找。
附件是本示例所用代码。