wechat-miniprogram / computed Goto Github PK
View Code? Open in Web Editor NEW小程序自定义组件 computed / watch 扩展
License: MIT License
小程序自定义组件 computed / watch 扩展
License: MIT License
如果 data
的一个值是 object
, 从 computed
中定义的方法,传入的 data 获取该值,一直为 {}
。比如下面这样的例子:
data
中有一个 child
:
data: {
child: {
key: value
}
}
在 computed
方法中想要获取 data.child
,只会得到 {}
computed: {
computedChild (data) {
console.info(data.child)
return data.child
}
}
用 README 里提供的代码片段做了简单修改跑了下(定义了 data.c
,尝试从 computed
的函数中获取该 data.c
),如图 console
返回 {}
。
目前企业微信的版本库还是比较低, 基础库无法支持2.x的版本
在项目源码中使用 v4 无问题,在我这边由 npm 管理的外部组件库中同样会使用 computed behavior。
经过一系列对比测试后发现,一旦当前小程序页面引用了来自 miniprogram_npm 的外部组件并且该组件使用了 computed behavior 时,页面无法渲染并且无任何报错信息。
在升级至 v4 之前一直用使用的 v2,升级之前各方面工作正常。
更新一:新增 v3 作为测试项后发现 v2, v3 均不会导致页面无法渲染,只有 v4 不正常
更新二:v3 虽然可以使页面渲染,但是页面内部的某个 setData 无法触发视图更新,无报错,未知原因。所以我还是退到了 v2,退回后一切正常。
总结:v2, v3, v4 各自有着自己的 bug,但 v2 最为稳定(除了无法 track 到另外的自定义 behavior 里面的 data)
在含有computed计算属性的页面,第一次进入时都正常计算,如果马上返回,再次进入时,计算属性就无法计算,发现是behavis里的computedCache里缓存了在第一次打开页面时的computed属性值,但第二次进入时,页面的data会初始化,页面上的computed是没有值的,因此造成第二次及之后打开此页面computed属性无效的问题。
data:{
a:[{...},{...},{...}]
},
computed:{
b(data){
return data.a
}
}
这里的b会变成{0:{...},1:{...},2:{...}}
我看了文档是在自定义组件中使用的功能,这个功能可以在page页面中使用吗????
const getDataDefinition = function (data, properties) {
const ret = {}
Object.keys(data).forEach((key) => {
ret[key] = data[key]
})
if (properties) {
Object.keys(properties).forEach((key) => {
let value = null
const def = properties[key]
const typeIndex = TYPES.indexOf(def)
if (typeIndex >= 0) {
value = TYPE_DEFAULT_VALUES[typeIndex]
} else if (def.value) {
value = def.value
} else {
const typeIndex = TYPES.indexOf(def.type)
if (typeIndex >= 0) {
value = TYPE_DEFAULT_VALUES[typeIndex]
}
}
ret[key] = value
})
}
return ret
}
properties 是可以设置为null的 如果是null的时候 def.value 就会报错
计算属性再引用其他计算属性就会出现数据不一致的BUG
computed: {
store() {
if (this.data.cartItem) {
return this.data.cartItem.total - this.data.sales;
}
return 0;
},
maxCountLimit() {
if (this.data.cartItem) {
const {
limitByUser
} = this.data.cartItem;
// 重点在这里 这里我不用计算属性则没问题
const { userBuy ,store} = this.data;
// const store = this.data.cartItem.total - this.data.sales;
console.debug(store, this.data.cartItem.total, this.data.sales);
return limitByUser ? Math.min(store - limitByUser - userBuy, limitByUser - userBuy) : store;
}
return 1;
},
canPlus() {
if (this.data.cartItem) {
const {
count,
} = this.data.cartItem;
return count < this.data.maxCountLimit;
}
return false;
},
canMinus() {
if (this.data.cartItem) {
const {
count
} = this.data.cartItem;
return count > 1;
}
return false;
}
}
具体是这个用例:
https://github.com/wechat-miniprogram/computed/blob/master/test/index.test.js#L323
这里预期 expect(func2TriggeringCount).toBe(2)
, 请问是为什呢? 我自己看的话总感觉d
只被算了一次
我自己用ts实现了一遍, 现在在补测试用例, 这个用例一直返回只算了一次
谢谢
test('computed chains', () => {
let func1TriggeringCount = 0
let func2TriggeringCount = 0
const componentId = _.load({
template: '<view>{{a}}+{{b}}={{c}}, {{a}}+{{c}}={{d}}</view>',
behaviors: [computedBehavior],
data: {
a: 1,
b: 2,
},
computed: {
c(data) {
func1TriggeringCount++
return data.a + data.b
},
d(data) {
func2TriggeringCount++
return data.a + data.c
}
}
})
const component = _.render(componentId)
component.triggerLifeTime('attached')
expect(_.match(component.dom, '<wx-view>1+2=3, 1+3=4</wx-view>')).toBe(true)
expect(func1TriggeringCount).toBe(1)
expect(func2TriggeringCount).toBe(2)
...
})
自定义 behavior A 使用 computed behavior 后,page/component 再使用该 behavior A,computed data 不会在视图中渲染,
但是可以在 instance.data 里找到该 computed data, 也可以在 onReady 等方法中 log 出该 data
目前我自己试出来的指标不治本的解决方案有两个
2.在 behavior A 中的 onReady 方法里 this.setData({computedDataA: this.data.computedDataA})
npm install --save miniprogram-computed
安装:$ npm install --save miniprogram-computed
npm WARN saveError ENOENT: no such file or directory, open 'D:\work-code\codewx\xxx\package.json'
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN enoent ENOENT: no such file or directory, open 'D:\work-code\codewx\xxx\package.json'
npm WARN xxx No description
npm WARN xxx No repository field.
npm WARN xxx No README data
npm WARN xxx No license field.
+ [email protected]
added 1 package from 1 contributor and audited 1 package in 1.666s
found 0 vulnerabilities
构建npm,报错‘没有找到 node_modules 目录。’
不死心的用淘宝镜像源再安装一遍:cnpm install --save miniprogram-computed
,这回可以正常构建了,
继续打开右侧详情【使用npm模块】也可以
最后写代码编译报错:
VM2638:1 thirdScriptError
sdk uncaught third Error
module "components/pullup/miniprogram-computed" is not defined
Error: module "components/pullup/miniprogram-computed" is not defined
能告诉我这是为什么吗?
watch
和 computed
都无效
开发过程种发现computed可以根据纯数据字段计算出值,而watch则不能监测纯数据字段的变化。
比如
computed:{
a(data){
return data.b+'bar'
},
b(data){
return 'foo'
}
}
module "miniprogram_npm/miniprogram-computed/rfdc" is not defined
Error: module "miniprogram_npm/miniprogram-computed/rfdc" is not defined
at require (http://127.0.0.1:15699/appservice/__dev__/WAService.js:2:1609633)
at http://127.0.0.1:15699/appservice/__dev__/WAService.js:2:1609384
at Object. (http://127.0.0.1:15699/appservice/miniprogram_npm/miniprogram-computed/index.js:552:20)
at webpack_require (http://127.0.0.1:15699/appservice/miniprogram_npm/miniprogram-computed/index.js:61:23)
at Object. (http://127.0.0.1:15699/appservice/miniprogram_npm/miniprogram-computed/index.js:283:19)
at webpack_require (http://127.0.0.1:15699/appservice/miniprogram_npm/miniprogram-computed/index.js:61:23)
at Object. (http://127.0.0.1:15699/appservice/miniprogram_npm/miniprogram-computed/index.js:268:20)
at webpack_require (http://127.0.0.1:15699/appservice/miniprogram_npm/miniprogram-computed/index.js:61:23)
at http://127.0.0.1:15699/appservice/miniprogram_npm/miniprogram-computed/index.js:255:10
at http://127.0.0.1:15699/appservice/miniprogram_npm/miniprogram-computed/index.js:257:2
index.js
const computedBehavior = require('miniprogram-computed');
const testBehavior = require('./test.behavior');
Component({
behaviors: [testBehavior, computedBehavior],
data: {
},
computed: {
c(data) {
return data.a + data.b;
}
},
methods: {
}
})
test.behavior.js
module.exports = Behavior({
data: {
a: 1,
b: 2
}
})
这个时候 c 获取不到 data 值。是有什么特别的引用方式吗?
dataTracer.create方法会把数组对象都转成对象,这样导致计算属性里面,原本的数组都不能按数组逻辑来处理了
as miniprogram is supporting typescript, to be consistent, its better to provide this ts .d.ts file for this important module. what do you think?
test('computed property changes', () => {
let funcTriggeringCount = 0
const innerComponentId = _.load({
template: '<view>{{a}}+{{b}}={{c}}</view>',
behaviors: [computedBehavior],
properties: {
a: {
type: Number,
value: -1,
},
b: String,
},
computed: {
c(data) {
funcTriggeringCount++
return data.a + data.b
}
},
})
const outerComponentId = _.load({
usingComponents: {
inner: innerComponentId,
},
data: {
a: 1,
b: 2,
},
template: '<inner a="{{a}}" b="{{b}}"></inner>',
})
const component = _.render(outerComponentId)
expect(_.match(component.dom, '<inner><wx-view>1+2=3</wx-view></inner>')).toBe(true)
// 比较有疑问的是为什么这里是2
expect(funcTriggeringCount).toBe(2)
component.setData({a: 100, b: 200})
expect(_.match(component.dom, '<inner><wx-view>100+200=300</wx-view></inner>')).toBe(true)
expect(funcTriggeringCount).toBe(3)
})
如题
在开发者工具报can't call setData in computed getter function!
提示,请问是什么原因。
代码片段 https://developers.weixin.qq.com/s/zkJXLjmY7w5J
目前在低版本下面computed计算出来的属性会被忽略,造成部分功能无法正常使用
我发错repo了, 在这里重发一遍
复现例子:
https://developers.weixin.qq.com/s/hgT6RCmL7Fkm
accounts
是store里的一个数组
export const store = observable({
// 数据字段
numA: 4,
numB: 5,
accounts: [4, 5, 6],
add: action(function() {
this.accounts = [1, 2, 3]
}),
// actions
update: action(function () {
this.numA = this.numA + 1
this.numB = this.numA + 1
})
})
当启动的时候, 会报一个bug说
VM824:1 MiniProgramError
data.accounts.reduce is not a function
TypeError: data.accounts.reduce is not a function
at sum (http://127.0.0.1:63254/appservice/index/components/computed-example.js:17:28)
at http://127.0.0.1:63254/appservice/components/index.js:392:21
at Array.forEach (<anonymous>)
at Ge.created (http://127.0.0.1:63254/appservice/components/index.js:385:34)
at r.safeCallback (http://127.0.0.1:63254/appservice/__dev__/WAService.js:2:1775504)
at r.call (http://127.0.0.1:63254/appservice/__dev__/WAService.js:2:1775397)
at Function.M._advancedCreate (http://127.0.0.1:63254/appservice/__dev__/WAService.js:2:1823182)
at r.createComponent (http://127.0.0.1:63254/appservice/__dev__/WAService.js:2:1834383)
at e (http://127.0.0.1:63254/appservice/__dev__/WAService.js:2:1919566)
at e (http://127.0.0.1:63254/appservice/__dev__/WAService.js:2:1920093)
Component({
behaviors: [behaviorTest, storeBindingsBehavior, computedBehavior],
computed: {
sum(data) {
console.log(data.accounts)
return data.accounts.reduce((s, o) => s + o, 0)
},
},
data: {
a: 1,
b: 1,
},
storeBindings: {
store,
fields: ['numA', 'numB','accounts'],
actions: {
buttonTap: 'add'
},
},
methods: {
onTap() {
console.log(this.data.accounts[0], this.data.accounts.reduce((s, o) => s + o, 0))
this.buttonTap()
}
}
})
老哥,你的2.1.0版本没有build就发布了,构建的代码还是不支持** 通配符啊
由于computedCache在同一component类型间共享,当同一页面使用多个同一类型的component,且component的某个computed出现相同值时,会出现bug
解决方案如下:
因为eslint的原因 pr就不提了,贴出完整重构过的代码
// 计算 computed
const calcComputed = function () {
const data = this.data = this.data || {}
const computed = data._computed || {}
const computedKeys = Object.keys(computed)
const needUpdate = {}
for (let i = 0, len = computedKeys.length; i < len; i++) {
const key = computedKeys[i]
const getter = computed[key]
if (typeof getter === 'function') {
const value = getter.call(this)
this._computedCache = this._computedCache || {}
if (this._computedCache[key] !== value) {
needUpdate[key] = value
this._computedCache[key] = value
}
}
}
return needUpdate
}
module.exports = Behavior({
lifetimes: {
attached() {
this._originalSetData = this.setData
this.setData = this._setData
this.setData({})
}
},
definitionFilter(defFields) {
const computed = defFields.computed || {}
defFields.data = defFields.data || {}
defFields.data._computed = computed
defFields.methods = defFields.methods || {}
defFields.methods._setData = function (data, callback) {
const originalSetData = this._originalSetData
if (this._doingSetData) {
// eslint-disable-next-line no-console
console.warn('can\'t call setData in computed getter function!')
return
}
this._doingSetData = true
// TODO 过滤掉 data 中的 computed 字段
const dataKeys = Object.keys(data)
for (let i = 0, len = dataKeys.length; i < len; i++) {
const key = dataKeys[i]
if (computed[key]) delete data[key]
}
// 做 data 属性的 setData
originalSetData.call(this, data, callback)
// 计算 computed
const needUpdate = calcComputed.call(this)
// 做 computed 属性的 setData
originalSetData.call(this, needUpdate)
this._doingSetData = false
}
}
})
发现升级了新版本之后,原本Array.isArray的功能都不正常了。
demo 导入项目,根本打不开!!!!!!!!!!
properties: {
display: {
type: Boolean,
value: false,
observer(newVal, oldVal) {
console.log('newVal: ', newVal);
console.log('oldVal: ', oldVal);
}
}
},
computed: {
show() {
console.log('this.display: ', this.display);
return this.display ? '1' : '2';
}
},
当组件外部display变化时,computed计算属性值不会重新变化,是bug吗?
数组和对象还是会触发
你好,这个扩展很好,很多时候很需要计算属性,但在page上又办法引用这个扩展吗?
麻烦考虑下加入Typescript支持
如题,并且如果当前组件使用了computed,Behavior里使用的computed也同样会被覆盖?
observers: {
"**":function(){
//使用 setData 后不会被触发
}
}
在某些场景下,可能需要computed组件传入properties的值
1.0.0版以下同一个自定义组件可以使用store和computed,computed可以监听store注入的data。2.0.x版本莫名其妙地不会监听store注入的data,也会让westore的this.update函数报错。希望可以兼容更多的主流开发环境
大概问一下,computed,对性能影响大吗,有做对应的实验验证吗?
同一组件(有计算属性)在不同页面渲染时,后渲染的组件会导致之前组件的计算属性失效。是不是缓存覆盖了??
在VUE使用了computed,通过v-bind:style使用在H5有效,在微信开发工具无效
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.