这个uniapp的api和组件太像小程序了有没有
这个api和组件太像小程序了有没有
不过还是比较喜欢的,没有更多额外学习成本
这个api和组件太像小程序了有没有
不过还是比较喜欢的,没有更多额外学习成本
2020承接外包,长期有效,uniapp、web、php、微信
经济不景气,全栈程序员接外包补贴房贷。
可接uniapp、网站,微信小程序、logo海报、等平面设计(有团队),付费解决问题。
不管有没有需求欢迎qq微信骚扰。
qq:50401716
微信:
5+案例(资讯,淘宝客,即时聊天):
https://m3w.cn/aihanfu
https://m3w.cn/dsg
一些案例图片:
网站及设计案例请加qq微信查看~
经济不景气,全栈程序员接外包补贴房贷。
可接uniapp、网站,微信小程序、logo海报、等平面设计(有团队),付费解决问题。
不管有没有需求欢迎qq微信骚扰。
qq:50401716
微信:
5+案例(资讯,淘宝客,即时聊天):
https://m3w.cn/aihanfu
https://m3w.cn/dsg
一些案例图片:
网站及设计案例请加qq微信查看~
收起阅读 »小程序开发费用,2018年的小程序开发费用
现在常见的郑州小程序开发方式主要有以下三种,小程序开发费用通常是根据功能需求以及开发难度等因素决定,目前来说只有一个大致的价格区间,很多投资者在询问价格时,无法得到明确答复就是因为这些原因,而定制开发的小程序所需费用是三种开发方式中比较贵的。下面来详细的跟大家分析一下各种开发方式所对应的小程序开发区别吧。
1、定制类小程序开发
这类小程序所需的开发费用一般在一万以上,因为定制开发类的小程序可以满足企业自身的个性化需求的功能,从事这类定制类小程序开发公司通常会由产品经理、核心技术人员等团队成员和客户详细沟通需求,然后提供相应的报价和解决方案,定制类小程序在完成开发后,功能使用往往比较贴合客户需求。
2、模板开发方式
小程序开发公司一般要会根据不同的行业分类开发出一些固定的模板,一个模板同时可以卖给成千上万的客户,这种开发方式对于开发商来说利润很高,对用户而言所付出的成本也相对于低,但是这种开发方式弊端,就是无法修改模板,只是把小程序按年租售,同时也会存在部分功能无法实现又承载过多一些多余功能的情况,这类小程序的售后服务通常也不完善。
3、开发各类常用模板的开发公司
这类公司主要是开发一些常用的功能模板,与模板类不同的是,客户可以根据自己的需求来选择不同的功能进行组合,价格相对也会高一些,一般在几千到一万元以内,这类开发小程序虽然有一定的选择性,但功能并不能完全实现个性化定制。
小程序开发需要多少费用?这是所有企业和个体商家关注的焦点,首先无论是哪一类型的小程序,开发费用都相对较低,但是不同类型的小程序根据用户的功能需求的不同,会导致开发费用有所差异,一般价格区间在几千到几万之间,小程序的开发费用是可以根据其开发方式推算出大概的预算方案,所以具体还是要跟开发公司协商才行。
本文由专业的郑州小程序开发(http://www.appsaa.com)燚轩科技整理发布,如需转载请注明出处。
现在常见的郑州小程序开发方式主要有以下三种,小程序开发费用通常是根据功能需求以及开发难度等因素决定,目前来说只有一个大致的价格区间,很多投资者在询问价格时,无法得到明确答复就是因为这些原因,而定制开发的小程序所需费用是三种开发方式中比较贵的。下面来详细的跟大家分析一下各种开发方式所对应的小程序开发区别吧。
1、定制类小程序开发
这类小程序所需的开发费用一般在一万以上,因为定制开发类的小程序可以满足企业自身的个性化需求的功能,从事这类定制类小程序开发公司通常会由产品经理、核心技术人员等团队成员和客户详细沟通需求,然后提供相应的报价和解决方案,定制类小程序在完成开发后,功能使用往往比较贴合客户需求。
2、模板开发方式
小程序开发公司一般要会根据不同的行业分类开发出一些固定的模板,一个模板同时可以卖给成千上万的客户,这种开发方式对于开发商来说利润很高,对用户而言所付出的成本也相对于低,但是这种开发方式弊端,就是无法修改模板,只是把小程序按年租售,同时也会存在部分功能无法实现又承载过多一些多余功能的情况,这类小程序的售后服务通常也不完善。
3、开发各类常用模板的开发公司
这类公司主要是开发一些常用的功能模板,与模板类不同的是,客户可以根据自己的需求来选择不同的功能进行组合,价格相对也会高一些,一般在几千到一万元以内,这类开发小程序虽然有一定的选择性,但功能并不能完全实现个性化定制。
小程序开发需要多少费用?这是所有企业和个体商家关注的焦点,首先无论是哪一类型的小程序,开发费用都相对较低,但是不同类型的小程序根据用户的功能需求的不同,会导致开发费用有所差异,一般价格区间在几千到几万之间,小程序的开发费用是可以根据其开发方式推算出大概的预算方案,所以具体还是要跟开发公司协商才行。
本文由专业的郑州小程序开发(http://www.appsaa.com)燚轩科技整理发布,如需转载请注明出处。
收起阅读 »Anroid 6.0 动态权限申请代码分享
/*
正常权限,无需动态申请:
ACCESS_LOCATION_EXTRA_COMMANDS
ACCESS_NETWORK_STATE
ACCESS_NOTIFICATION_POLICY
ACCESS_WIFI_STATE
BLUETOOTH
BLUETOOTH_ADMIN
BROADCAST_STICKY
CHANGE_NETWORK_STATE
CHANGE_WIFI_MULTICAST_STATE
CHANGE_WIFI_STATE
DISABLE_KEYGUARD
EXPAND_STATUS_BAR
GET_PACKAGE_SIZE
INSTALL_SHORTCUT
INTERNET
KILL_BACKGROUND_PROCESSES
MODIFY_AUDIO_SETTINGS
NFC
READ_SYNC_SETTINGS
READ_SYNC_STATS
RECEIVE_BOOT_COMPLETED
REORDER_TASKS
REQUEST_INSTALL_PACKAGES
SET_ALARM
SET_TIME_ZONE
SET_WALLPAPER
SET_WALLPAPER_HINTS
TRANSMIT_IR
UNINSTALL_SHORTCUT
USE_FINGERPRINT
VIBRATE
WAKE_LOCK
WRITE_SYNC_SETTINGS
2)危险权限,需要动态申请:
group:android.permission-group.STORAGE
READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE
group:android.permission-group.CONTACTS
WRITE_CONTACTS
GET_ACCOUNTS
READ_CONTACTS
group:android.permission-group.PHONE
READ_CALL_LOG
READ_PHONE_STATE
CALL_PHONE
WRITE_CALL_LOG
USE_SIP
PROCESS_OUTGOING_CALLS
com.android.voicemail.permission.ADD_VOICEMAIL
group:android.permission-group.CALENDAR
READ_CALENDAR
WRITE_CALENDAR
group:android.permission-group.CAMERA
CAMERA
group:android.permissiongroup.SENSORS
BODY_SENSORS
group:android.permission-group.LOCATION
ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
group:android.permission-group.MICROPHONE
RECORD_AUDIO
group:android.permission-group.SMS
READ_SMS
RECEIVE_WAP_PUSH
RECEIVE_MMS
RECEIVE_SMS
SEND_SMS
READ_CELL_BROADCASTS
*/
/**
* Me:
* cnscn <214363570@qq.com>
*
* 参考:
* https://blog.csdn.net/lvyoujt/article/details/52826556
* https://developer.android.com/reference/android/Manifest.permission
* https://developer.android.com/reference/android/os/Build.VERSION
*/
function plusReady() {
var Build = plus.android.importClass("android.os.Build");
var Manifest = plus.android.importClass("android.Manifest");
var MainActivity = plus.android.runtimeMainActivity();
//var context=main.getApplicationContext(); //未用到,在此仅供参考
var ArrPermissions = [
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA
];
function PermissionCheck(permission) {
if (Build.VERSION.SDK_INT >= 23) {
if (MainActivity.checkSelfPermission(permission) == -1) {
return false;
}
}
return true;
}
function PermissionChecks(Arr) {
var HasPermission = true;
for (var index in Arr) {
var permission = Arr[index];
//如果此处没有权限,则是用户拒绝了
if (!PermissionCheck(permission)) {
HasPermission = false;
break;
}
}
return HasPermission;
}
function PermissionRequest(Arr) {
var REQUEST_CODE_CONTACT = 101;
if (Build.VERSION.SDK_INT >= 23) {
MainActivity.requestPermissions(Arr, REQUEST_CODE_CONTACT);
}
}
//如果没有权限,则申请
if (!PermissionChecks(ArrPermissions)) {
PermissionRequest(ArrPermissions);
} else { //如果拥有权限,那么干点啥吧^_^
//.......
}
}
if (window.plus) {
plusReady();
} else {
document.addEventListener('plusready', plusReady, false);
}
/*
正常权限,无需动态申请:
ACCESS_LOCATION_EXTRA_COMMANDS
ACCESS_NETWORK_STATE
ACCESS_NOTIFICATION_POLICY
ACCESS_WIFI_STATE
BLUETOOTH
BLUETOOTH_ADMIN
BROADCAST_STICKY
CHANGE_NETWORK_STATE
CHANGE_WIFI_MULTICAST_STATE
CHANGE_WIFI_STATE
DISABLE_KEYGUARD
EXPAND_STATUS_BAR
GET_PACKAGE_SIZE
INSTALL_SHORTCUT
INTERNET
KILL_BACKGROUND_PROCESSES
MODIFY_AUDIO_SETTINGS
NFC
READ_SYNC_SETTINGS
READ_SYNC_STATS
RECEIVE_BOOT_COMPLETED
REORDER_TASKS
REQUEST_INSTALL_PACKAGES
SET_ALARM
SET_TIME_ZONE
SET_WALLPAPER
SET_WALLPAPER_HINTS
TRANSMIT_IR
UNINSTALL_SHORTCUT
USE_FINGERPRINT
VIBRATE
WAKE_LOCK
WRITE_SYNC_SETTINGS
2)危险权限,需要动态申请:
group:android.permission-group.STORAGE
READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE
group:android.permission-group.CONTACTS
WRITE_CONTACTS
GET_ACCOUNTS
READ_CONTACTS
group:android.permission-group.PHONE
READ_CALL_LOG
READ_PHONE_STATE
CALL_PHONE
WRITE_CALL_LOG
USE_SIP
PROCESS_OUTGOING_CALLS
com.android.voicemail.permission.ADD_VOICEMAIL
group:android.permission-group.CALENDAR
READ_CALENDAR
WRITE_CALENDAR
group:android.permission-group.CAMERA
CAMERA
group:android.permissiongroup.SENSORS
BODY_SENSORS
group:android.permission-group.LOCATION
ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
group:android.permission-group.MICROPHONE
RECORD_AUDIO
group:android.permission-group.SMS
READ_SMS
RECEIVE_WAP_PUSH
RECEIVE_MMS
RECEIVE_SMS
SEND_SMS
READ_CELL_BROADCASTS
*/
/**
* Me:
* cnscn <214363570@qq.com>
*
* 参考:
* https://blog.csdn.net/lvyoujt/article/details/52826556
* https://developer.android.com/reference/android/Manifest.permission
* https://developer.android.com/reference/android/os/Build.VERSION
*/
function plusReady() {
var Build = plus.android.importClass("android.os.Build");
var Manifest = plus.android.importClass("android.Manifest");
var MainActivity = plus.android.runtimeMainActivity();
//var context=main.getApplicationContext(); //未用到,在此仅供参考
var ArrPermissions = [
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA
];
function PermissionCheck(permission) {
if (Build.VERSION.SDK_INT >= 23) {
if (MainActivity.checkSelfPermission(permission) == -1) {
return false;
}
}
return true;
}
function PermissionChecks(Arr) {
var HasPermission = true;
for (var index in Arr) {
var permission = Arr[index];
//如果此处没有权限,则是用户拒绝了
if (!PermissionCheck(permission)) {
HasPermission = false;
break;
}
}
return HasPermission;
}
function PermissionRequest(Arr) {
var REQUEST_CODE_CONTACT = 101;
if (Build.VERSION.SDK_INT >= 23) {
MainActivity.requestPermissions(Arr, REQUEST_CODE_CONTACT);
}
}
//如果没有权限,则申请
if (!PermissionChecks(ArrPermissions)) {
PermissionRequest(ArrPermissions);
} else { //如果拥有权限,那么干点啥吧^_^
//.......
}
}
if (window.plus) {
plusReady();
} else {
document.addEventListener('plusready', plusReady, false);
}
收起阅读 »
小程序开发之插件功能的有效实现方法
我们在做小程序开发时,比如说在编辑器里里面编辑了一段内容,输出网页版只需要htmlspecialchars_decode()函数就可以搞定了,但是输出小程序就并不是那么简单了,必须要使用wxParse插件才能完成。下面跟大家分享一下导入插件的使用方法:
在wxml中引入,代码如下:
{{title}}
在wcss中引入,代码如下:
@import "/wxParse/wxParse.wxss";
.title{
/ border:solid #000 1rpx; /
width: 100% ;
text-align: center;
background-color: #fff;
font-size: 30rpx;
height:80rpx;
line-height: 80rpx;
}
.content{
/ border:solid #000 1rpx; /
width: 100% ;
margin-top:20rpx;
height: 100%;
background-color: #fff;
font-size: 25rpx;
padding:20rpx;
}
在js中引入,代码如下:
// pages/helpcontent/helpcontent.js
var WxParse = require('../../wxParse/wxParse.js');
Page({
/**
- 页面的初始数据
*/
data: {
},
/**
- 生命周期函数--监听页面加载
*/
onLoad: function (options) {
var that=this
wx.request({
url: 'https://www.appsaa.com', //仅为示例,并非真实的接口地址
header: {
'content-type': 'application/json'
},
success: function (res) {
console.log(res.data.title)
that.setData({
title: res.data.title,//第一个data为固定用法,第二个data是json中的data
infos: WxParse.wxParse('infos', 'html', res.data.infos, that, 5)
})
}
})
}
那么到这里就结束了,大家现在可以尝试一下了,如果还是存在有不理解或者不清楚的地方,都是可以留言咨询我们的。
本文由专业的郑州小程序开发公司燚轩科技整理发布,原创不易,如需转载请注明出处。
我们在做小程序开发时,比如说在编辑器里里面编辑了一段内容,输出网页版只需要htmlspecialchars_decode()函数就可以搞定了,但是输出小程序就并不是那么简单了,必须要使用wxParse插件才能完成。下面跟大家分享一下导入插件的使用方法:
在wxml中引入,代码如下:
{{title}}
在wcss中引入,代码如下:
@import "/wxParse/wxParse.wxss";
.title{
/ border:solid #000 1rpx; /
width: 100% ;
text-align: center;
background-color: #fff;
font-size: 30rpx;
height:80rpx;
line-height: 80rpx;
}
.content{
/ border:solid #000 1rpx; /
width: 100% ;
margin-top:20rpx;
height: 100%;
background-color: #fff;
font-size: 25rpx;
padding:20rpx;
}
在js中引入,代码如下:
// pages/helpcontent/helpcontent.js
var WxParse = require('../../wxParse/wxParse.js');
Page({
/**
- 页面的初始数据
*/
data: {
},
/**
- 生命周期函数--监听页面加载
*/
onLoad: function (options) {
var that=this
wx.request({
url: 'https://www.appsaa.com', //仅为示例,并非真实的接口地址
header: {
'content-type': 'application/json'
},
success: function (res) {
console.log(res.data.title)
that.setData({
title: res.data.title,//第一个data为固定用法,第二个data是json中的data
infos: WxParse.wxParse('infos', 'html', res.data.infos, that, 5)
})
}
})
}
那么到这里就结束了,大家现在可以尝试一下了,如果还是存在有不理解或者不清楚的地方,都是可以留言咨询我们的。
本文由专业的郑州小程序开发公司燚轩科技整理发布,原创不易,如需转载请注明出处。
收起阅读 »mui 如何禁用下拉刷新
down: {
height: '50px',
range: '80px',
contentdown: "下拉可以刷新", //可选,在下拉可刷新状态时,下拉刷新控件上显示的标题内容
contentover: "释放立即刷新", //可选,在释放可刷新状态时,下拉刷新控件上显示的标题内容
contentrefresh: "正在刷新...", //可选,正在刷新状态时,下拉刷新控件上显示的标题内容
//style: "circle",
color: '#f78000',
callback: downFn // 下拉执行函数
},
注释 //style: "circle",
这个方法安卓可以 ios还是有下拉的样式
可以全部注释,或者不加
down: {
height: '50px',
range: '80px',
contentdown: "下拉可以刷新", //可选,在下拉可刷新状态时,下拉刷新控件上显示的标题内容
contentover: "释放立即刷新", //可选,在释放可刷新状态时,下拉刷新控件上显示的标题内容
contentrefresh: "正在刷新...", //可选,正在刷新状态时,下拉刷新控件上显示的标题内容
//style: "circle",
color: '#f78000',
callback: downFn // 下拉执行函数
},
注释 //style: "circle",
这个方法安卓可以 ios还是有下拉的样式
可以全部注释,或者不加
小程序开发如何实现视频或音频自定义可拖拽进度条
程序原生组件的音频播放时并没有进度条的显示,而此次在我们所接的项目中,鉴于原生的视频进度条样式太丑,产品要求做一个可拖拽的进度条满足需求。视频和音频提供的api大致是相似的,可以根据以下代码修改为与音频相关的进度条。
wxml的结构如下:
<video id="myVideo" src="http://wxsnsdy.tc.qq.com/105/20210/snsdyvideodownload?filekey=30280201010421301f0201690402534804102ca905ce620b1241b726bc41dcff44e00204012882540400&bizid=1023&hy=SH&fileparam=302c020101042530230204136ffd93020457e3c4ff02024ef202031e8d7f02030f42400204045a320a0201000400" enable-danmu danmu-btn controls="{{false}}" autoplay='{{true}}' bindtimeupdate="videoUpdate" objectFit="fill"></video>
<view class='process-container'>
<image src='{{playStates ? "../../assets/image/pause_icon.png" : "../../assets/image/play_icon.png"}}' class='video-controls-icon' bindtap='videoOpreation'></image>
<view class='slider-container'>
<slider bindchange="sliderChange" bindchanging="sliderChanging" step="1" value="{{sliderValue}}" backgroundColor="#A8A8A8" activeColor="#FFEE83" block-color="#FFEE83" />
</view>
</view>
data中初始化了sliderValue, updateState, playStates几个变量。
data: {
sliderValue: 0, //控制进度条slider的值,
updateState: false, //防止视频播放过程中导致的拖拽失效
playStates: true //控制播放 & 暂停按钮的显示
},
onReady: function () {
this.videoContext = wx.createVideoContext('myVideo');
this.setData({
updateState: true
})
},
videoUpdate在播放进度变化时触发,触发频率 250ms 一次。event.detail = {currentTime, duration},currentTime表示当前时间,duration表示总时长,都以秒为单位
videoUpdate(e) {
if (this.data.updateState) { //判断拖拽完成后才触发更新,避免拖拽失效
let sliderValue = e.detail.currentTime / e.detail.duration * 100;
this.setData({
sliderValue,
duration: e.detail.duration
})
}
},
进度条可拖拽并指定视频跳转到相应的位置
sliderChanging(e) {
this.setData({
updateState: false //拖拽过程中,不允许更新进度条
})
},
sliderChange(e) {
if (this.data.duration) {
this.videoContext.seek(e.detail.value / 100 * this.data.duration); //完成拖动后,计算对应时间并跳转到指定位置
this.setData({
sliderValue: e.detail.value,
updateState: true //完成拖动后允许更新滚动条
})
}
},
暂停/播放视频
videoOpreation() {
this.data.playStates ? this.videoContext.pause() : this.videoContext.play();
this.setData({
playStates: !this.data.playStates
})
}
总结:slider的最大值为100, step的值最小为1,这会导致视频或音频播放时间过长的时候,slider滑块移动速度很慢,拖拽移动的时间间隔较大,用户体验差。如果还是有不理解的地方,可以留言咨询。
本文由专业的郑州小程序开发公司燚轩科技整理发布,如需转载请注明出处。
程序原生组件的音频播放时并没有进度条的显示,而此次在我们所接的项目中,鉴于原生的视频进度条样式太丑,产品要求做一个可拖拽的进度条满足需求。视频和音频提供的api大致是相似的,可以根据以下代码修改为与音频相关的进度条。
wxml的结构如下:
<video id="myVideo" src="http://wxsnsdy.tc.qq.com/105/20210/snsdyvideodownload?filekey=30280201010421301f0201690402534804102ca905ce620b1241b726bc41dcff44e00204012882540400&bizid=1023&hy=SH&fileparam=302c020101042530230204136ffd93020457e3c4ff02024ef202031e8d7f02030f42400204045a320a0201000400" enable-danmu danmu-btn controls="{{false}}" autoplay='{{true}}' bindtimeupdate="videoUpdate" objectFit="fill"></video>
<view class='process-container'>
<image src='{{playStates ? "../../assets/image/pause_icon.png" : "../../assets/image/play_icon.png"}}' class='video-controls-icon' bindtap='videoOpreation'></image>
<view class='slider-container'>
<slider bindchange="sliderChange" bindchanging="sliderChanging" step="1" value="{{sliderValue}}" backgroundColor="#A8A8A8" activeColor="#FFEE83" block-color="#FFEE83" />
</view>
</view>
data中初始化了sliderValue, updateState, playStates几个变量。
data: {
sliderValue: 0, //控制进度条slider的值,
updateState: false, //防止视频播放过程中导致的拖拽失效
playStates: true //控制播放 & 暂停按钮的显示
},
onReady: function () {
this.videoContext = wx.createVideoContext('myVideo');
this.setData({
updateState: true
})
},
videoUpdate在播放进度变化时触发,触发频率 250ms 一次。event.detail = {currentTime, duration},currentTime表示当前时间,duration表示总时长,都以秒为单位
videoUpdate(e) {
if (this.data.updateState) { //判断拖拽完成后才触发更新,避免拖拽失效
let sliderValue = e.detail.currentTime / e.detail.duration * 100;
this.setData({
sliderValue,
duration: e.detail.duration
})
}
},
进度条可拖拽并指定视频跳转到相应的位置
sliderChanging(e) {
this.setData({
updateState: false //拖拽过程中,不允许更新进度条
})
},
sliderChange(e) {
if (this.data.duration) {
this.videoContext.seek(e.detail.value / 100 * this.data.duration); //完成拖动后,计算对应时间并跳转到指定位置
this.setData({
sliderValue: e.detail.value,
updateState: true //完成拖动后允许更新滚动条
})
}
},
暂停/播放视频
videoOpreation() {
this.data.playStates ? this.videoContext.pause() : this.videoContext.play();
this.setData({
playStates: !this.data.playStates
})
}
总结:slider的最大值为100, step的值最小为1,这会导致视频或音频播放时间过长的时候,slider滑块移动速度很慢,拖拽移动的时间间隔较大,用户体验差。如果还是有不理解的地方,可以留言咨询。
本文由专业的郑州小程序开发公司燚轩科技整理发布,如需转载请注明出处。
收起阅读 »doodoo.js配置教程
Doodoo.js -- 中文最佳实践Node.js Web快速开发框架。支持Koa.js, Express.js中间件,支持模块化,插件,钩子机制,可以直接在项目里使用 ES6/7(Generator Function, Class, Async & Await)等特性 https://www.doodooke.com
配置
doodoo配置.env 文件位于项目根目录下,作为全局默认环境配置文件。
# 应用配置
APP_ROOT=app
APP_PORT=3000
APP_HOST=127.0.0.1
# MYSQL数据库链接
MYSQL=false
MYSQL_HOST=127.0.0.1
MYSQL_USER=root
MYSQL_PASSWORD=root
MYSQL_DATABASE=doodoo
MYSQL_PORT=3306
MYSQL_CHARSET=utf8mb4
# MONGODB数据库链接
MONGOOSE=false
MONGOOSE_URI=mongodb://127.0.0.1:27017/doodoo
# REDIS链接
REDIS=false
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PREFIX=doodoo:
# 静态资源服务
STATIC_DIR=www
STATIC_MAXAGE=30 * 24 * 60 * 60
STATIC_DYNAMIC=true
支持根据不同环境加载不同的配置文件(自定义文件配置将覆盖全局默认环境配置)
# 创建docker.env文件
touch docker.env
# 自定义docker环境启动
NODE_ENV=docker node app.js Doodoo.js -- 中文最佳实践Node.js Web快速开发框架。支持Koa.js, Express.js中间件,支持模块化,插件,钩子机制,可以直接在项目里使用 ES6/7(Generator Function, Class, Async & Await)等特性 https://www.doodooke.com
配置
doodoo配置.env 文件位于项目根目录下,作为全局默认环境配置文件。
# 应用配置
APP_ROOT=app
APP_PORT=3000
APP_HOST=127.0.0.1
# MYSQL数据库链接
MYSQL=false
MYSQL_HOST=127.0.0.1
MYSQL_USER=root
MYSQL_PASSWORD=root
MYSQL_DATABASE=doodoo
MYSQL_PORT=3306
MYSQL_CHARSET=utf8mb4
# MONGODB数据库链接
MONGOOSE=false
MONGOOSE_URI=mongodb://127.0.0.1:27017/doodoo
# REDIS链接
REDIS=false
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PREFIX=doodoo:
# 静态资源服务
STATIC_DIR=www
STATIC_MAXAGE=30 * 24 * 60 * 60
STATIC_DYNAMIC=true
支持根据不同环境加载不同的配置文件(自定义文件配置将覆盖全局默认环境配置)
# 创建docker.env文件
touch docker.env
# 自定义docker环境启动
NODE_ENV=docker node app.js 收起阅读 »
doodoo.js快速入门教程
快速入门
我们通过3步演示如何快速创建一个doodoo项目
第一步
# 创建doodoo-demo目录
mkdir doodoo-demo && cd doodoo-demo
# 初始化npm
npm init -y
# 安装doodoo.js
yarn add doodooke/doodoo.js
# 创建app.js
touch app.js
接下来我们将以下代码copy到app.js
const Doodoo = require("doodoo.js");
const app = new Doodoo();
app.start();
第二步
# 创建app/hello/controller目录
mkdir -p app/hello/controller && cd app/hello/controller
# 创建test.js文件
touch test.js
接下来我们将以下代码copy到test.js
module.exports = class extends doodoo.Controller {
async _initialize() {
// 控制器初始化
console.log("_initialize");
}
async _before() {
// 控制器前置
console.log("_before");
}
async _before_index() {
// 方法前置
console.log("_before_index");
}
async index() {
console.log("index");
this.success("Hello Doodoo.js");
}
async _after_index() {
// 方法后置
console.log("_after_index");
}
async _after() {
// 控制器后置
console.log("_after");
}
};
第三步
进入doodoo-demo根目录
cd ../../../
启动项目
node app.js
通过命令行可以看到如下信息表示启动成功
[doodoo] Version: 1.0.3
[doodoo] Website: 127.0.0.1
[doodoo] Nodejs Version: v10.10.0
[doodoo] Nodejs Platform: darwin x64
[doodoo] Server Enviroment: development
[doodoo] Server Startup Time: 36ms
[doodoo] Server Current Time: 2018-10-09 20:26:40
[doodoo] Server Running At: http://127.0.0.1:3000
通过浏览器访问以下链接可以看到如下提示
http://127.0.0.1:3000/hello/test/index
{
errmsg: "ok",
errcode: 0,
data: "Hello Doodoo.js"
}
源码
按照传统,所有课程源代码基于 MIT 开源,托管于 GitHub :https://github.com/doodooke/doodoo-demo
快速入门
我们通过3步演示如何快速创建一个doodoo项目
第一步
# 创建doodoo-demo目录
mkdir doodoo-demo && cd doodoo-demo
# 初始化npm
npm init -y
# 安装doodoo.js
yarn add doodooke/doodoo.js
# 创建app.js
touch app.js
接下来我们将以下代码copy到app.js
const Doodoo = require("doodoo.js");
const app = new Doodoo();
app.start();
第二步
# 创建app/hello/controller目录
mkdir -p app/hello/controller && cd app/hello/controller
# 创建test.js文件
touch test.js
接下来我们将以下代码copy到test.js
module.exports = class extends doodoo.Controller {
async _initialize() {
// 控制器初始化
console.log("_initialize");
}
async _before() {
// 控制器前置
console.log("_before");
}
async _before_index() {
// 方法前置
console.log("_before_index");
}
async index() {
console.log("index");
this.success("Hello Doodoo.js");
}
async _after_index() {
// 方法后置
console.log("_after_index");
}
async _after() {
// 控制器后置
console.log("_after");
}
};
第三步
进入doodoo-demo根目录
cd ../../../
启动项目
node app.js
通过命令行可以看到如下信息表示启动成功
[doodoo] Version: 1.0.3
[doodoo] Website: 127.0.0.1
[doodoo] Nodejs Version: v10.10.0
[doodoo] Nodejs Platform: darwin x64
[doodoo] Server Enviroment: development
[doodoo] Server Startup Time: 36ms
[doodoo] Server Current Time: 2018-10-09 20:26:40
[doodoo] Server Running At: http://127.0.0.1:3000
通过浏览器访问以下链接可以看到如下提示
http://127.0.0.1:3000/hello/test/index
{
errmsg: "ok",
errcode: 0,
data: "Hello Doodoo.js"
}
源码
按照传统,所有课程源代码基于 MIT 开源,托管于 GitHub :https://github.com/doodooke/doodoo-demo
在web-view加载的本地及远程HTML中调用uni的API及网页和vue页面通讯
uni-app的web-view组件,支持加载远程网页,在app环境下,还支持加载本地HTML页面。
在web-view加载页面中,会涉及wx、plus、uni等对象的使用。
- 在小程序下使用wx的api,需要引入微信提供的https://res.wx.qq.com/open/js/jweixin-1.4.0.js。
- 在app下默认有plus对象,不需要引入js文件。
- 不管是在小程序下还是在app下,使用uni的api,需要引入https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.0.1.52.js
本文会详述在webview里的uni对象的使用方式,以及和vue页面的通讯方式。
HBuilderX 1.0.0 版本开始,uni-app 支持在 web-view 中调用 uni 的 API。
引用依赖的文件
在 web-view 加载的 HTML 中调用 uni 的 API,需要在 HTML 中引用必要的 JS-SDK。
<!-- 微信 JS-SDK 如果不需要兼容小程序,则无需引用此 JS 文件。 -->
<script type="text/javascript" src="//res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
<!-- uni 的 SDK,必须引用。 -->
<script type="text/javascript" src="//js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.0.1.52.js"></script>
Tips
- 这些 JS 文件是在 web-view 加载的那个 HTML 文件中引用的,而不是 uni-app 项目中的文件。
- 如果不考虑微信小程序,则无需引入微信的 JS-SDK。
- 两个文件同时引入时,注意引入的顺序,微信的需要在前。
调用的时机
在引用依赖的文件后,需要在 HTML 中监听 UniAppJSBridgeReady 事件触发后,才能安全调用 uni 的 API。
document.addEventListener('UniAppJSBridgeReady', function() {
uni.getEnv(function(res) {
console.log('当前环境:' + JSON.stringify(res));
});
});
页面跳转
支持调用所有的 uni 路由方法,可以实现从 HTML 重新跳转回应用内的页面。
在 UniAppJSBridgeReady 后,调用路由方法跳转到应用内的页面。
document.addEventListener('UniAppJSBridgeReady', function() {
document.querySelector('.btn-list').addEventListener('click', function(evt) {
var target = evt.target;
if (target.tagName === 'BUTTON') {
var action = target.getAttribute('data-action');
if(action === 'navigateTo') {
uni.navigateTo({
url: '/pages/component/button/button'
});
}
}
});
});
发送消息
可以通过 uni.postMessage 在 HTML 中向应用发送消息。要实现此功能,需要完成以下两步工作。
监听 web-view 的 message 事件
监听 web-view 组件的 message 事件,然后在事件回调的 event.detail.data 中接收传递过来的消息。
<template>
<view>
<web-view src="http://192.168.1.1:3000/test.html" @message="handleMessage"></web-view>
</view>
</template>
<script>
export default {
methods: {
handleMessage(evt) {
console.log('接收到的消息:' + JSON.stringify(evt.detail.data));
}
}
}
</script>
从 HTML 向应用发送消息
uni.postMessage 中的参数格式,必须是 data: {}。也就是说,传递的消息信息必须在 data 这个对象中。
document.addEventListener('UniAppJSBridgeReady', function() {
uni.postMessage({
data: {
action: 'postMessage'
}
});
});
每次执行 postMessage 后,传递的消息会以数组的形式存放。因此,在 web-view 的 message 事件回调中,接收到的 event.detail.data 的值是一个数组。
获取当前环境信息
HTML 在不同的环境下,可能需要执行不同的操作或传递不同的消息。可以通过 uni.getEnv() 方法,来获取当前的环境信息。
document.addEventListener('UniAppJSBridgeReady', function() {
uni.getEnv(function(res) {
if (res.plus) {
console.log('当前环境为【5+App】');
} else if (res.miniprogram) {
console.log('当前环境为【微信小程序】');
}
});
});
本地 HTML
自 HBuilderX v1.1.0 起,在 5+App 平台下 web-view 支持加载应用内的 HTML 资源。
本地的 HTML 资源,必须存放在规定的目录下,即 uni-app 项目->hybrid->html 目录。
├─common
├─components
├─hybrid
│ └─html
│ test.html
├─pages
├─static
│ App.vue
│ main.js
│ manifest.json
│ pages.json
与 html 文件相关的 css、js 等本地资源,同样放在这个 hybrid->html 目录下。
这个hybrid目录不会被编译器编译,所以这里的不能放vue文件,而其他目录也不能放本地HTML文件。
未来hybrid目录还会支持其他语言在uni-app的中的混合使用。
注意:在本地 HTML 中引入网络资源时,必须补全协议。比如:https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.0.1.52.js
运行体验
示例中 web-view 加载的是一个本机的测试地址,这个测试 HTML 见附件。
-
加载网络地址的话,需要在本机启动一个服务将此 HTML 放进去,然后修改 hello uni-app 中的 web-view 例子的 src 地址为可访问的局域网地址。
-
如果是加载本地 HTML 的话,就直接新建目录将此 HTML 放进去,然后修改 web-view 的 src 为 /hybrid/html/test.html 即可。
-
参考文档:web-view
web-view组件在app中的窗体关系和plus.webview操作方式
uni-app的vue页面本身是一个webview,vue页面里的web-view组件,其实是一个子webview。
但一个vue页面不能放多个web-view组件,这个组件默认是全屏的(不会覆盖原生头和原生导航)。
使用plus代码获得当前webview的对象后(参考此文https://ask.dcloud.net.cn/article/35036),再获取子webview,其实也可以得到web-view组件所对应的plus的webview对象,进而再使用plus.webview的丰富api。
获取子webview时注意时机,获取方法执行太早可能获取不到。
uni-app的web-view组件,支持加载远程网页,在app环境下,还支持加载本地HTML页面。
在web-view加载页面中,会涉及wx、plus、uni等对象的使用。
- 在小程序下使用wx的api,需要引入微信提供的https://res.wx.qq.com/open/js/jweixin-1.4.0.js。
- 在app下默认有plus对象,不需要引入js文件。
- 不管是在小程序下还是在app下,使用uni的api,需要引入https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.0.1.52.js
本文会详述在webview里的uni对象的使用方式,以及和vue页面的通讯方式。
HBuilderX 1.0.0 版本开始,uni-app 支持在 web-view 中调用 uni 的 API。
引用依赖的文件
在 web-view 加载的 HTML 中调用 uni 的 API,需要在 HTML 中引用必要的 JS-SDK。
<!-- 微信 JS-SDK 如果不需要兼容小程序,则无需引用此 JS 文件。 -->
<script type="text/javascript" src="//res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
<!-- uni 的 SDK,必须引用。 -->
<script type="text/javascript" src="//js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.0.1.52.js"></script>
Tips
- 这些 JS 文件是在 web-view 加载的那个 HTML 文件中引用的,而不是 uni-app 项目中的文件。
- 如果不考虑微信小程序,则无需引入微信的 JS-SDK。
- 两个文件同时引入时,注意引入的顺序,微信的需要在前。
调用的时机
在引用依赖的文件后,需要在 HTML 中监听 UniAppJSBridgeReady 事件触发后,才能安全调用 uni 的 API。
document.addEventListener('UniAppJSBridgeReady', function() {
uni.getEnv(function(res) {
console.log('当前环境:' + JSON.stringify(res));
});
});
页面跳转
支持调用所有的 uni 路由方法,可以实现从 HTML 重新跳转回应用内的页面。
在 UniAppJSBridgeReady 后,调用路由方法跳转到应用内的页面。
document.addEventListener('UniAppJSBridgeReady', function() {
document.querySelector('.btn-list').addEventListener('click', function(evt) {
var target = evt.target;
if (target.tagName === 'BUTTON') {
var action = target.getAttribute('data-action');
if(action === 'navigateTo') {
uni.navigateTo({
url: '/pages/component/button/button'
});
}
}
});
});
发送消息
可以通过 uni.postMessage 在 HTML 中向应用发送消息。要实现此功能,需要完成以下两步工作。
监听 web-view 的 message 事件
监听 web-view 组件的 message 事件,然后在事件回调的 event.detail.data 中接收传递过来的消息。
<template>
<view>
<web-view src="http://192.168.1.1:3000/test.html" @message="handleMessage"></web-view>
</view>
</template>
<script>
export default {
methods: {
handleMessage(evt) {
console.log('接收到的消息:' + JSON.stringify(evt.detail.data));
}
}
}
</script>
从 HTML 向应用发送消息
uni.postMessage 中的参数格式,必须是 data: {}。也就是说,传递的消息信息必须在 data 这个对象中。
document.addEventListener('UniAppJSBridgeReady', function() {
uni.postMessage({
data: {
action: 'postMessage'
}
});
});
每次执行 postMessage 后,传递的消息会以数组的形式存放。因此,在 web-view 的 message 事件回调中,接收到的 event.detail.data 的值是一个数组。
获取当前环境信息
HTML 在不同的环境下,可能需要执行不同的操作或传递不同的消息。可以通过 uni.getEnv() 方法,来获取当前的环境信息。
document.addEventListener('UniAppJSBridgeReady', function() {
uni.getEnv(function(res) {
if (res.plus) {
console.log('当前环境为【5+App】');
} else if (res.miniprogram) {
console.log('当前环境为【微信小程序】');
}
});
});
本地 HTML
自 HBuilderX v1.1.0 起,在 5+App 平台下 web-view 支持加载应用内的 HTML 资源。
本地的 HTML 资源,必须存放在规定的目录下,即 uni-app 项目->hybrid->html 目录。
├─common
├─components
├─hybrid
│ └─html
│ test.html
├─pages
├─static
│ App.vue
│ main.js
│ manifest.json
│ pages.json
与 html 文件相关的 css、js 等本地资源,同样放在这个 hybrid->html 目录下。
这个hybrid目录不会被编译器编译,所以这里的不能放vue文件,而其他目录也不能放本地HTML文件。
未来hybrid目录还会支持其他语言在uni-app的中的混合使用。
注意:在本地 HTML 中引入网络资源时,必须补全协议。比如:https://js.cdn.aliyun.dcloud.net.cn/dev/uni-app/uni.webview.0.1.52.js
运行体验
示例中 web-view 加载的是一个本机的测试地址,这个测试 HTML 见附件。
-
加载网络地址的话,需要在本机启动一个服务将此 HTML 放进去,然后修改 hello uni-app 中的 web-view 例子的 src 地址为可访问的局域网地址。
-
如果是加载本地 HTML 的话,就直接新建目录将此 HTML 放进去,然后修改 web-view 的 src 为 /hybrid/html/test.html 即可。
-
参考文档:web-view
web-view组件在app中的窗体关系和plus.webview操作方式
uni-app的vue页面本身是一个webview,vue页面里的web-view组件,其实是一个子webview。
但一个vue页面不能放多个web-view组件,这个组件默认是全屏的(不会覆盖原生头和原生导航)。
使用plus代码获得当前webview的对象后(参考此文https://ask.dcloud.net.cn/article/35036),再获取子webview,其实也可以得到web-view组件所对应的plus的webview对象,进而再使用plus.webview的丰富api。
获取子webview时注意时机,获取方法执行太早可能获取不到。















