tencent / westore Goto Github PK
View Code? Open in Web Editor NEW小程序项目分层架构
小程序项目分层架构
请问有代码示例吗?
另外想请教怎么在小程序加载的时候就注入store
可以用将setData的方法promisify然后promise.all所有update产生的setData,但是可能对性能的影响较大。我改了以后会测一下,如果性能还行会发一个pull request。
a.js
export default {
data: {
numa: 1,
numb: 2
},
getA() {
console.log('a');
}
}
b.js
export default {
data: {
numc: 3,
numd: 4
},
getA() {
console.log('b');
}
}
store.js
import a from './a.js'
import b from './b.js'
const commonData = {
commona: 'common'
}
function storeMixin(options) {
let result = {
data: commonData ,
}
for (let k in options) {
let value = options[k];
if (value.data) {
result.data[k] = value.data
delete value.data
}
Object.assign(result, value)
}
return result;
}
export default storeMixin({a, b})
根据page划分store, 不过函数名字就不能重复了
globalData如果不在组件和页面声明data依赖,在绑定视图初始显示会有问题,而且更改globalData的值时候还需要手动update()一次?
this.store.data.globalPropTest = 'aaaa'
this.update()
比如
data: {
arr: []
}
create(store,{
data: {
arr: null
}
})
当arr添加元素后退出该页面,再进来之前添加的元素还在,不会重置为初始值
这是正常现象吗
ps:我知道arr放在页面的data中就行了,可我想用diff,只放页面data中更新时就不会经过diff了
一点都不低调。
1、『Please using store.method to set method prop of data!
』需要如何处理哈
我在组件里,如果没有设置pure:true
会出现这个提示,不知道有什么影响也不知道如何解决哈
2、还是不明白 pure:true
的区别
我只明白,true
的时候,data
不会合并
仍可以修改this.store.data.xxx
却不能调用this.store.func()
,调用某个store里的函数
3、组件里如果在lifetimes
写ready
生命周期的处理事件,不能够获取this.store
的值
但是如果把ready
拿到外面写就可以获取this.store
4、有一个很神奇的情况
页面获取数据,然后赋值
this.store.data["goodsList"] = [];
然后跳转到别的页面,在后退的时候,出现
但是如果使用setData
就不会有这样情况
这个情况,我发现复习场景是
页面A(有赋值data)=> redirectTo到页面B => redirectTo到页面A => 报错
但是如果是
页面A(有赋值data)=> navigateTo到页面B => redirectTo到页面A
就没问题
我最近发现小程序es6转译支持 Proxy,那么可不可以用Proxy来代理 Page的data属性?
直接在onload函数中这样写
this.data = new Proxy(this.data, {
get: (target, key, proxy) => {
console.log("get")
return target[key]
},
set: (target, key, value, proxy) => {
this.update({
[key]: value
})
return Reflect.set(target, key, value, proxy)
}
})
so
this.msg= "hello"
就可以更新数据.而不用反复的调用发放,至于又没有什么问题 我暂时还没看
我目前的理解是:无论是用 setdata 还是 update,最后在虚拟 dom 里面,都要把整个页面生成出来,再跟前一刻的状态来 diff,最后更新为新视图(react.js 是如此),所以即使 setdata diff 了一下,那些相同的数据被 pass,但最后是否都要重新 render 整个page 在虚拟 dom 里面??
还有一个很重要的问题是,这个很重要!!在表单组件里面,比如 switch 的 value 属性,即使每次 setdata 的时候,值是一样的,但都需要重新更新switch的状态的。场景是:switch 初始值为 true,用户手动改变了 switch 为 false,然后点击另外的按钮使得 switch 重置为默认 true,这个时候,在 this.update 来看,前后两次的值都为 true,就不会更新页面了
。。。。比较懒。。
//报错
that.store.data.themeColor = theme;
that.update();
//不报错
setTimeout(function () {
that.store.data.themeColor = theme;
that.update();
}, 10000)
var arr = [1,2,3];
observe(arr, function() {console.log("change")});
arr[3] = 2;
var obj = {a:1,b:2};
observe(obj, function() {console.log("change")});
obj.c = 3;
如果直接使用未定义的键的操作相关的监测事件未触发,如果在实际使用中要一直避免访问到未定义的键,那使用起来需很谨慎
polymer的observerjs通过暴露一个Platform.performMicrotaskCheckpoint()
接口手动刷新,其余的方案采用定时器机制检查
Array.prototype.size = function (length) {
this.length = length;
}
希望再页面中可以 用this.data.my_info = xxx 的方式修改 而不是 this.store.data.myinfo
this.update == store.update ?在页面中使用哪个好 还是一样的
observe.add = function(obj, prop, value) { obj[prop] = null; var $observer = obj.$observer; $observer.watch(obj, prop); obj[prop] = value; }
这样改完,再使用observe.add(obj,newAttr,vlaue);就会在observe(obj,function(){})的回调中触发了。
使用场景:
例如用户信息(userInfo),信息这个基本上每个页面都用的到
而目前使用的是局部更新,就必须要在每个页面的data里再输入一次,有点繁琐
解决方案:
支持局部更新下
定义全局的data和函数
非页面调用store.update()没用了。
蓝廋。
我试过使用onChange,但是不知道要怎么写 有DEMO吗?
一直想用这样的插件,但是考虑到浏览器的支持情况,希望可以有个说明
原有小程序如果想迁移的话 工作量会不会比较庞大 页面大概有 15个左右 不算组件的
有没有考虑优化 , 做出类似vuex的体验
举个栗子
pageA
Page({
data: {
a:1,
b: 2,
.....
z: ''
}
})
但是其实 只有 一两个属性是需要跨页面传输的(例如z),其他的都只是本页面使用,那么 如果这种情况 要采用westore 是不是必须所有属性都写到store (即使采用 分模块来加载,模块里面也都一一对应写好吧)
可能我表述的不是很清楚, 最终想表达的是 就是能不能只有写在store的属性时 才会被覆盖,其他的当前页面没有的,就不用覆盖。
var obj = {
a: 1,
b: 2
};
observe(obj, 'a', function (name, value, old) {
console.log(name + "__" + value+"__"+old);
});
observe.set(obj, 'c', 2, true); // 并不会触发回调函数
解决方法:可将源码改成如下
observe.set = function(obj, prop,value,exec) {
if(!exec){
obj[prop] = value;
}
var $observer = obj.$observer;
$observer.watch(obj, prop);
$observer.propertyChangedHandler.forEach(function(handler) {
handler.eventPropArr.push(prop);
})
if(exec){
obj[prop] = value;
}
};
不过这个有待商议哈
以下不可行
var cache = [];
observe(cache, function (name, value, old) {
console.log(name + '__' + value + '__' + old);
});
cache = [1]
这样可行:
var cache = {
NoticeCache: []
}
observe(cache, function (name, value, old) {
console.log(name + '__' + value + '__' + old);
});
cache.NoticeCache = [1, 2, 3];
fullName:function(){}什么时候会去执行
小程序重启耗时过久,请确认业务逻辑中是否有复杂运算,或者死循环
这是微信开发者工具报的提示
在使用observejs时为了跟原生的Object.observe 兼容,我写了如下代码
objectObserve = Object.observe || function (obj, fun){
observe(obj, function (name, value, oldValue) {
fun && fun([{
type: 'update',
name: name,
oldValue: oldValue
}]);
})
};
结果发现fun回调会被执行多次,目前我的办法是加一个定时器,100ms内只允许执行一次,这样可以解决多次触发的问题,但不太理解为什么会有触发多次的问题?
export default {
data: {
a: 1,
// 有效
show() {
return this.a === 1
},
b: {
// 无效
show() {
return this.a === 1
}
}
}
}
使用westore-plugin中的两个文件create-plug.js,diff.js
在开发全页插件的时候,页面不能正常执行。尝试使用普通开发模式中的两个文件就可以正常运行。
而且我看示例中好几种模式的create.js/diff.js都不太一样,使用上有什么区别的?
diff算法会把两个对象做比对,如果是增改是没问题的,但是如果是删除操作,diff算法就没法抓出被删除的元素了。
页面声明了data但是没有用,一定要在storejs 声明data吗`//index.js
//获取应用实例
import store from '../../store'
import create from '../../utils/create'
var app = getApp()
const http = require('wehttp')
create(store,{
data: {
islogin: false,
offline: false,
remind: '加载中',
cores: [
[{
id: 'kb',
name: '课表查询',
disabled: false,
teacher_disabled: false,
offline_disabled: false
},
/**{ id: 'cj', name: '成绩查询', disabled: false, teacher_disabled: true, offline_disabled: false },
{ id: 'ks', name: '考试安排', disabled: false, teacher_disabled: false, offline_disabled: false },
{ id: 'kjs', name: '空教室', disabled: false, teacher_disabled: false, offline_disabled: true },
{ id: 'xs', name: '学生查询', disabled: false, teacher_disabled: false, offline_disabled: true },
{ id: 'ykt', name: '一卡通', disabled: false, teacher_disabled: false, offline_disabled: false },
{ id: 'jy', name: '借阅信息', disabled: false, teacher_disabled: false, offline_disabled: false },
{ id: 'xf', name: '学费信息', disabled: false, teacher_disabled: true, offline_disabled: false },
{ id: 'sdf', name: '电费查询', disabled: false, teacher_disabled: true, offline_disabled: false },
{ id: 'bx', name: '物业报修', disabled: false, teacher_disabled: false, offline_disabled: true }
],[
/**{ id: 'cet', name: '四六级', disabled: false, teacher_disabled: true, offline_disabled: true},
{ id: 'fw', name: "志愿活动", disabled: false, teacher_disabled: true, offline_disabled: false}**/
]
],
card: {
'kb': {
show: false,
time_list: [{
begin: '8:00',
end: '8:45'
},
{
begin: '8:55',
end: '9:40'
},
{
begin: '10:05',
end: '10:50'
},
{
begin: '11:00',
end: '11:45'
},
{
begin: '14:00',
end: '14:45'
},
{
begin: '14:55',
end: '15:40'
},
{
begin: '16:05',
end: '16:50'
},
{
begin: '17:00',
end: '17:45'
},
{
begin: '19:00',
end: '19:45'
},
{
begin: '19:55',
end: '20:40'
},
{
begin: '20:50',
end: '21:35'
},
{
begin: '21:45',
end: '22:30'
}
],
data: {}
},
'ykt': {
show: false,
data: {
'last_time': '',
'balance': 0,
'cost_status': false,
'today_cost': {
value: [],
total: 0
}
}
},
'jy': {
show: false,
data: {}
},
'sdf': {
show: false,
data: {
'room': '',
'record_time': '',
'cost': 0,
'spend': 0
}
}
},
user: {},
disabledItemTap: false //点击了不可用的页面
},
//分享
onShareAppMessage: function () {
return {
title: 'We重邮',
desc: '碎片化、一站式、一体化校园移动门户',
path: '/pages/index/index'
};
},
//下拉更新
onPullDownRefresh: function () {
if (app._user.is_bind) {
this.getCardData();
} else {
wx.stopPullDownRefresh();
}
},
checkbind(userID) {
},
onShow: function () {
//this.update()
//var that = this
//this.store.data.cores = {}
var _this = this;
var that = this;
// console.log("onshow")
var res = app.islogin()
if (res != false) {
that.setData({
islogin: true,
})
//判断是否绑定
res.then((res) => {
console.log(res.data.is_bind)
if (res.data.is_bind == false) {
_this.setData({
'remind': '未绑定',
});
} else {
_this.setData({
'remind': '加载中',
student_ID: res.data.student_ID,
student_Password: res.data.student_Password
});
//清空数据
_this.setData({
user: app.globalData.userinfo,
'card.kb.show': false,
'card.ykt.show': false,
'card.jy.show': false,
'card.sdf.show': false
});
_this.getCardData();
}
})
}
//离线模式重新登录
if (_this.data.offline) {
_this.login();
return false;
}
function isEmptyObject(obj) {
for (var key in obj) {
return false;
}
return true;
}
function isEqualObject(obj1, obj2) {
if (JSON.stringify(obj1) != JSON.stringify(obj2)) {
return false;
}
return true;
}
var l_user = _this.data.user, //本页用户数据
g_user = app._user; //全局用户数据
//排除第一次加载页面的情况(全局用户数据未加载完整 或 本页用户数据与全局用户数据相等)
if (isEmptyObject(l_user) || !g_user.openid || isEqualObject(l_user.we, g_user.we)) {
return false;
}
//全局用户数据和本页用户数据不一致时,重新获取卡片数据
if (!isEqualObject(l_user.we, g_user.we)) {
//判断绑定状态
if (!g_user.is_bind) {
_this.setData({
'remind': '未绑定'
});
} else {
_this.setData({
'remind': '加载中'
});
//清空数据
_this.setData({
user: app._user,
'card.kb.show': false,
'card.ykt.show': false,
'card.jy.show': false,
'card.sdf.show': false
});
_this.getCardData();
}
}
},
onLoad: function () {
this.login();
if (this.data.user = {}) {
console.log("没登录")
}
},
userInfoHandler(data) {
var that = this
wx.BaaS.handleUserInfo(data).then(res => {
// res 包含用户完整信息,详见下方描述
that.setData({
islogin: true,
})
app.globalData.userinfo = res
console.log(res)
that.getCardData();
}, res => {
// res 有两种情况:用户拒绝授权,res 包含基本用户信息:id、openid、unionid;其他类型的错误,如网络断开、请求超时等,将返回 Error 对象(详情见下方注解)
})
},
login: function () {
var _this = this;
console.log(app.islogin())
//如果有缓存,则提前加载缓存
// 微信用户登录小程序
},
response: function (status) {
var _this = this;
if (status) {
if (status != '离线缓存模式') {
//错误
_this.setData({
'remind': status
});
return;
} else {
//离线缓存模式
_this.setData({
offline: true
});
}
}
_this.setData({
user: app._user
});
//判断绑定状态
if (!app._user.is_bind) {
_this.setData({
'remind': '未绑定'
});
} else {
_this.setData({
'remind': '加载中'
});
_this.getCardData();
}
},
disabled_item: function () {
var _this = this;
if (!_this.data.disabledItemTap) {
_this.setData({
disabledItemTap: true
});
setTimeout(function () {
_this.setData({
disabledItemTap: false
});
}, 2000);
}
},
//课表渲染
kbRender(info) {
if (info) {
var classlist = info
} else {
var classlist = wx.getStorageInfoSync('kb_today')
}
//console.log(classlist)
var _this = this
_this.setData({
'card.kb.data': classlist,
'card.kb.show': true,
'card.kb.nothing': !classlist.length,
'remind': ''
});
},
//获取当前时间
getCurrentWeekday() {
var myDate = new Date();
return myDate.getDay();
},
getCardData: function () {
var _this = this;
var student_ID = _this.data.student_ID
var student_Password = _this.data.student_Password
//判断并读取缓存
if (wx.getStorageSync('kb_today')) {
_this.kbRender(wx.getStorageSync('kb_today'));
}
if (app.globalData.ykt) {
yktRender(app.cache.ykt);
}
if (app.globalData.sdf) {
sdfRender(app.cache.sdf);
}
if (app.globalData.jy) {
jyRender(app.cache.jy);
}
if (_this.data.offline) {
return;
}
// wx.showNavigationBarLoading();
http.request('https://coes-stud.must.edu.mo/coes/login.do', 'get', {
'userid': student_ID,
'password': student_Password
}, res => {
console.log("res",res)
http.request('https://coes-stud.must.edu.mo/coes/AcademicRecordsForm.do?intake=1809&formAction=Timetable', 'post', {
'userid': student_ID,
'password': student_Password
}, {
success: res => {
console.log(res.statusCode)
if (res.statusCode == 200) {
var txt = res.data.toString()
var info = ''
var classlist = []
var classlist_all = []
var nowweek = _this.getCurrentWeekday()
//str = '';
var patt = /timetable\.add\('(\d+)',[\n\s]+'(\d+:\d+)',[\n\s]+'(\d+:\d+)',[\n\s]+'(\w+)',[\n\s]+'([^']+)',[\n\s]+'(\w+)',[\n\s]+'(\w+)',[\n\s]+'([^']+)',[\n\s]+'([^']+)'\+'\s+-\s+'\+[\n\s]+'([^']+)'\);/g;
while (info = patt.exec(txt)) {
console.log(info)
var tempinfo = {
"week": info[1],
"when": info[2],
"end": info[3],
"what": info[5],
"where": info[7]
}
classlist_all.push(info)
if (tempinfo.week == nowweek) {
classlist.push(tempinfo)
}
}
//console.log(classlist)
//保存课表缓存
app.saveCache('kb', classlist_all);
app.saveCache('kb_today', classlist);
_this.kbRender(classlist);
} else {
//app.removeCache('kb');
}
}
// _this.setData({ list: classlist})
//_this.kbRender(classlist)
})
})
//获取课表数据
//var kb_data = classlist
if (app._user.teacher) {
kb_data.type = 'teacher';
}
/**var loadsum = 0; //正在请求连接数
loadsum++; //新增正在请求连接
wx.request({
url: app._server + '/api/get_kebiao.php',
method: 'POST',
data: app.key(kb_data),
complete: function() {
loadsum--; //减少正在请求连接
if (!loadsum) {
if (_this.data.remind == '加载中') {
_this.setData({
remind: '首页暂无展示'
});
}
wx.hideNavigationBarLoading();
wx.stopPullDownRefresh();
}
}
});**/
/**一卡通渲染
function yktRender(list) {
if (list.length > 0) {
var last = list[0],
last_time = last.time.split(' ')[0],
now_time = app.util.formatTime(new Date()).split(' ')[0];
//筛选并计算当日消费(一卡通数据有一定延迟,无法成功获取到今日数据,主页卡片通常不能展示)
for (var i = 0, today_cost = [], cost_total = 0; i < list.length; i++) {
if (list[i].time.split(' ')[0] == now_time && list[i].cost.indexOf('-') == 0) {
var cost_value = Math.abs(parseInt(list[i].cost));
today_cost.push(cost_value);
cost_total += cost_value;
}
}
if (today_cost.length) {
_this.setData({
'card.ykt.data.today_cost.value': today_cost,
'card.ykt.data.today_cost.total': cost_total,
'card.ykt.data.cost_status': true
});
}
_this.setData({
'card.ykt.data.last_time': last_time,
'card.ykt.data.balance': parseFloat(last.balance),
'card.ykt.show': true,
'remind': ''
});
}
}
//获取一卡通数据
loadsum++; //新增正在请求连接
wx.request({
url: app._server + '/api/get_yktcost.php',
method: 'POST',
data: app.key({
yktID: app._user.we.ykth
}),
success: function(res) {
if (res.data && res.data.status === 200) {
var list = res.data.data;
if (list) {
//保存一卡通缓存
app.saveCache('ykt', list);
yktRender(list);
}
} else {
app.removeCache('ykt');
}
},
complete: function() {
loadsum--; //减少正在请求连接
if (!loadsum) {
if (_this.data.remind) {
_this.setData({
remind: '首页暂无展示'
});
}
wx.hideNavigationBarLoading();
wx.stopPullDownRefresh();
}
}
});
//水电费渲染
function sdfRender(info) {
_this.setData({
'card.sdf.data.room': info.room.split('-').join('栋'),
'card.sdf.data.record_time': info.record_time.split(' ')[0].split('/').join('-'),
'card.sdf.data.cost': info.elec_cost,
'card.sdf.data.spend': info.elec_spend,
'card.sdf.show': true,
'remind': ''
});
}
if (!!app._user.we.room && !!app._user.we.build) {
//获取水电费数据
loadsum++; //新增正在请求连接
wx.request({
url: app._server + '/api/get_elec.php',
method: 'POST',
data: app.key({
buildingNo: app._user.we.build,
floor: app._user.we.room.slice(0, 1),
room: parseInt(app._user.we.room.slice(1))
}),
success: function(res) {
if (res.data && res.data.status === 200) {
var info = res.data.data;
if (info) {
//保存水电费缓存
app.saveCache('sdf', info);
sdfRender(info);
}
} else {
app.removeCache('sdf');
}
},
complete: function() {
loadsum--; //减少正在请求连接
if (!loadsum) {
if (_this.data.remind) {
_this.setData({
remind: '首页暂无展示'
});
}
wx.hideNavigationBarLoading();
wx.stopPullDownRefresh();
}
}
});
}
//借阅信息渲染
function jyRender(info) {
if (parseInt(info.books_num) && info.book_list && info.book_list.length) {
var nowTime = new Date().getTime();
info.book_list.map(function(e) {
var oDate = e.yhrq.split('-'),
oTime = new Date(oDate[0], oDate[1] - 1, oDate[2]).getTime();
e.timing = parseInt((oTime - nowTime) / 1000 / 60 / 60 / 24);
return e;
});
_this.setData({
'card.jy.data': info,
'card.jy.show': true,
'remind': ''
});
}
}
//获取借阅信息
loadsum++; //新增正在请求连接
wx.request({
url: app._server + "/api/get_books.php",
method: 'POST',
data: app.key({
ykth: app._user.we.ykth
}),
success: function(res) {
if (res.data && res.data.status === 200) {
var info = res.data.data;
if (info) {
//保存借阅缓存
app.saveCache('jy', info);
jyRender(info);
}
} else {
app.removeCache('jy');
}
},
complete: function() {
loadsum--; //减少正在请求连接
if (!loadsum) {
if (_this.data.remind) {
_this.setData({
remind: '首页暂无展示'
});
}
wx.hideNavigationBarLoading();
wx.stopPullDownRefresh();
}
}
});**/
}
});`
1,在非页面,非组件内update store,store的数据只能同步到路由栈已存在的页面
2,打开新的页面 store的内容无法同步到新页面
关于问题出现的原因,create时候合并的data 是直接执行的,
那么在create执行之后,在页面被加入路由之前,这段时间的store的更新在 打开新页面的时候是无法相应更新的,这真的是很难受
可否提供使用原生 setData 和 westore 的性能比较数据?这样比较直观理解westore 的性能优异
如果Page是用Component创建的,引入store时,create.js会报错,因为没法获取this.page.store。这个能兼容还是我们只能用Page的写法创建page?
Disclaimer: This is a bot
It looks like your repo is trending. The github_trending_videos Instgram account automatically shows the demo gifs of trending repos in Github.
Your README doesn't seem to have any demo gifs. Add one and the next time the parser runs it will pick it up and post it on its Instagram feed. If you don't want to just close this issue we won't bother you again.
我发现如果只有一部分使用westore创建的页面和组件,在运行时会出现一些错误。可以这样使用吗?如果可以,这样使用的时候有没有什么注意事项?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.