Every piece of all creatures in this freezing world, are racing for freedom.
微信小程序固定元素位置的两种形式
一种是页面json不变, 使用css属性position: fixed;,同时规定css属性 top bottom left right. 第二种是可以在页面的json文件中写: "disableScroll": true, 然后再元素上使用css属性position: absolute;,再规定css属性top bottom left right. 这种方式是结合recycle-view来用的, 原因太久不太记得了, 似乎因为Recycle-view的一些特性导致position:fixed不能正常固定或页面不能正常滚动.
微信小程序的页面如何知道是从哪儿进入的?
进入一个页面有几种方式: navigateTo,navigateBack, 熄屏再显示(从其他应用切换回来也是类似). GPT给的建议是通过app.globalData存储全局变量来判断, 或者用storage存储判断, 感觉都不优雅, 把单个页面问题的解决扩展到了全局去了. 但目前还没有其他好办法, 因为navigateBack和熄屏再显示都是触发onHide,所以无法区分. GPT还给了一个幻觉建议, 说onShow会带形参进来,判断形参就可以, 但事实上onShow不会带任何形参 通过navigateTo,navigateBack从其他页面导航到这个页面, 通常都需要更新页面数据. 因为上一页导航过来, 这一页的数据还没有生成过; 从下一页返回, 可能在下一页对数据做了更新.
因为CSS的flex每次用的时候总是忘记, 这儿总结一下: 将flex理解为一个画框(父元素)里面的元素(子元素)的排列. 父元素设置整体遵从的规则, 子元素设置个别规则. 总体规格包括: flex-direction: 确定主轴方向. 元素是沿着主轴方向依次放置的. 交叉轴(副轴)即主轴的垂直轴, 确定一行主轴放不下的元素,下一行放的方向. flex-wrap: 元素在主轴放不下, 要不要回车放在下一行. justify-content: 确定元素主轴排列, 以及元素间距 align-items: 确定副轴的元素排列 align-content: 确定wrap后多行的元素怎么放置,以及行间距等.
银行送了10元京东E卡,进了京东APP完全找不到绑定的地方, 搜索兰搜索京东E卡也只是给了一堆的卖E卡的连接. 说是付款的时候京东自营商品可用, 然后下了好几个单,专门找京东自营,充话费,京东超市和京喜自营买纸巾,付款的时候都没有选择E卡的界面. 找了一圈只好问机器客服, 这才找到绑卡的地方: 我的钱包-点击查看全部-礼品卡,此时注意不要点那个大大的京东E卡图标, 而要点击绑定新卡! 然后输入卡的密码, 只用输入密码, 而不用输入卡号, 虽然给了卡号但并没有什么用. 然后, 我去找下单但没有付款的链接, 还是不能选择! 接着下新单, 也没有选E卡的地方! 我勒个去, 赶快百度找下经验, 发现百度经验这个下单支付界面怎么和我不一样? 终于发现了, 原来从购物车购买,点击去结算才有这个选礼品卡(京东卡/E卡)订单界面, 这个订单界面选择地址, 查看订单详情,选择开票等等. 从商品链接直接购买真的不能选择吗? 我又研究了下,发现不是的!商品链接里面直接点击下单购买(这个名字在不同的商品链接还不一样, 有的叫到手价购买, 有的叫立即购买预估), 这时候不会转到新页面,而是从下方弹出来一个半屏, 上面显示收货地址,选择商品数量和规格, 平常这个时候就选"支付"了, 但注意, 这个半屏是可以上滑的! 你如果上滑一点点, 发现滑出来的只是其他商品的广告, 但如果继续上滑, 才出现商品价格详情,支付方式,发票,留言...等等这些订单信息, 全部堆在这个半屏的最下面, 跟从购物车结算的订单界面是类似的. 但是等等, 为什么礼品卡的选择消失了? 哈哈,这时候还要去选择商品金额栏目里的四个灰色小字:展开更多,才看得到优惠券和礼品卡两个选项,不得不说比购物车结算订单界面要隐蔽得多. 京东这个界面设计真的很滑头, 其逻辑是想方设法让你别用券直接支付, 让你确认地址/品类/数量这些最重要信息后就直接付款, 这样 一方面京东拿到最多的钱, 另一方面你买了以后即使想到有优惠券, 也只能下次用了, 又引诱你下次继续在京东购物. 之前几次买东西找不到开票的地方也是这个原因.
引用自定义组件 组件名 组件json-> 页面json-> 页面wxml mycomp.js/.json/.wxml/.css {"component": true,usingComponents": {}} {"usingComponents": {"mycomp": "../../components/mycomp/mycomp"}} 组件展现页面的数据和自身的数据 没有区分. 如 `Component({ properties: {propFromPage: 1}, data: {propFromData: 2} }) 在组件wxml中都是同样方式引用{{propFromPage}} {{propFromData}}. 但在组件js中引用方式有区分:this.properties.propFromPage, this.data.propFromData 调用函数 组件中的函数引用方式在js中不需要加methods, 如 `Component({ properties:{prop:{type: Number, value:1, observer(newValue, oldValue){this.f1();}}}, lifetimes:{attached(){this.f1();}}, methods: { f1(){}, f2(){this.f1()}, } }) 页面向组件传数据 页面js-> 页面wxml-> 页面wxml 组件js Page({data:{pageprop: 1}}) {{prop}} Component({ properties: {prop: 默认值}, methods:{f(){this.properties.prop },}}) 组件向页面传数据(通过事件) 组件js-> 页面wxml-> 页面js Component({method:{f(){this.triggerEvent('someevent', somevalue) },}}) processIt(e){let value = e.detail}
数据库设计:绘制实体关系图(Entry Relationship Diagram, ER图/E-R图/ERD)
有两种不同文档描述了两种不同的ER图, 一种是把属性放在实体外面https://zhuanlan.zhihu.com/p/270299029, 另一种是把属性和实体放在一起https://blog.csdn.net/character_/article/details/124142908. 后者看起来更美观些. draw.io可以画ER图.
js如何在对象的键值变化时调用函数, 并且操作对象的代码不需要变动(无感)
GPT4o给了三种方法, 在后面给出. 第三种方法是改赋值=为调用函数, 意味着所有的赋值都要改为函数调用,不实用. 分析下方法一Proxy和方法二getter/setter. Proxy的好处是不会改变原对象,而是建立了一个新的proxy对象, 对新对象的赋值会触发set函数. 问题有三个: 一是任何键值变化都会触发set,需要自己判断键值; 二是需要将原对象的名称指向新proxy对象, 才能实现无感. 三是无法通过instanceof判断pr一个实例是不是Proxy的实例, 只能自己在创建实例时添加一个自定义key如_isProxy来判断.(后面段落说明) getter/setter是最早一代vue.js用的方法, 所有在app.data中的键都会用Object.defineProperty()的get/set重定义一遍, 做到自动更新UI. 好处是可以逐个key定义,不影响其他key, 问题是原key值就会消失,除非定义前先保存一下. 并且需要保存到另一个键下面(一般前面加个下划线_)而不能保存在本key下面, 否则会导致反复触发直到调用栈溢出Maximum call stack size exceeded. 这个话题在vue的官方文档中也有讨论: https://cn.vuejs.org/guide/extras/reactivity-in-depth, 里面也提到在vue3中,从getter/setter已经转向了proxy机制. 另外一个问题, 是如果键值是一个对象(数组也是),也就是下面有子键, 对子键键值的修改, 只会调用get而不是set!并且对Proxy和getter/setter机制都一样. 如: proxyObject.k = {k1:1} // 调用set proxyObject.k.k1 = 2 //调用get 怎么解决这个问题,GPT4o的回答是递归代理. 见后面一节. 方法1: 使用Proxy 在 JavaScript 中，如果希望在对象的某个键变化时自动调用一个函数，可以使用 Proxy 对象来实现。Proxy 允许你创建一个代理对象，以便对其属性的访问和修改进行拦截。 下面是一个使用 Proxy 的示例代码，当对象的 someKey 属性变化时，会自动调用函数 a： // 定义要监控的对象 const targetObject = { someKey: '初始值', }; // 定义要自动调用的函数 function a(newValue) { console.log(`someKey 的新值是: ${newValue}`); } // 创建 Proxy 代理对象 const proxyObject = new Proxy(targetObject, { set(target, property, value) { // 当设置 someKey 时，调用函数 a if (property === 'someKey') { a(value); } // 修改属性的值 target[property] = value; // 返回 true 表示设置成功 return true; } }); // 测试：修改 someKey proxyObject.someKey = '新的值'; // 这将输出: someKey 的新值是: 新的值 // 可以继续修改其他属性也不会触发 a() proxyObject.anotherKey = '另一个值'; console.log(proxyObject.anotherKey); // 输出: 另一个值 说明： 在上面的示例中，创建了一个对象 targetObject 和一个函数 a。 使用 Proxy 创建了代理对象 proxyObject，并在其 set 拦截器中定义了逻辑。当 someKey 被修改时，会自动调用函数 a(newValue)。 修改其他属性不会触发这个函数，只会在指定的键发生变化时执行。 通过这种方式，你可以灵活地监控对象属性的变化，并根据需要触发相应的逻辑。 方法2 使用getter/setter 你可以使用 JavaScript 的 Object.defineProperty() 方法来定义 getter 和 setter，使得每次修改对象属性时都能执行相应的函数。 const targetObject = { _someKey: '初始值', // 私有变量 }; // 定义要自动调用的函数 function a(newValue) { console.log(`someKey 的新值是: ${newValue}`); } // 使用 Object.defineProperty 定义 getter 和 setter Object.defineProperty(targetObject, 'someKey', { get() { return this._someKey; }, set(value) { this._someKey = value; a(value); // 调用函数 a }, }); // 测试：修改 someKey targetObject.someKey = '新的值'; // 这将输出: someKey 的新值是: 新的值 // 读取 someKey console.log(targetObject.someKey); // 输出: 新的值 // 可以继续修改其他属性也不会触发 a() targetObject.anotherKey = '另一个值'; console.log(targetObject.anotherKey); // 输出: undefined (因为没有定义) 方法3：使用自定义方法 另一种简单的方法是创建一个用于更新对象属性的方法，以便所有更改都通过此方法发生，这样就可以在里面调用相关逻辑。 const targetObject = { someKey: '初始值', }; // 定义要自动调用的函数 function a(newValue) { console.log(`someKey 的新值是: ${newValue}`); } // 自定义方法用于更新键并执行相应逻辑 function setSomeKey(value) { targetObject.someKey = value; // 更新属性 a(value); // 调用函数 a } // 测试：修改 someKey setSomeKey('新的值'); // 这将输出: someKey 的新值是: 新的值 // 读取 someKey console.log(targetObject.someKey); // 输出: 新的值 // 修改其他属性的方法不变，不会触发函数 a() targetObject.anotherKey = '另一个值'; console.log(targetObject.anotherKey); // 输出: 另一个值 如何知道实例是Proxy的实例 在 JavaScript 中，可以使用 Proxy 对象来创建代理，从而控制对某个对象的基本操作，如属性查找、赋值、枚举、函数调用等。如果想要判断一个对象是否是一个 Proxy 实例，可以通过以下方法： 利用 WeakMap: 在将对象包装为 Proxy 时，可以使用 WeakMap 来存储原始对象和其代理之间的关系。通过这种方式，你可以检查某个代理是否存在于这个 WeakMap 中。 const originalObject = {}; const proxyMap = new WeakMap(); const proxy = new Proxy(originalObject, { set(target, prop, value) { return Reflect.set(target, prop, value); } }); // 存入 WeakMap proxyMap.set(proxy, originalObject); function isProxy(obj) { return proxyMap.has(obj); } console.log(isProxy(proxy)); // true console.log(isProxy(originalObject)); // false 标记法: 你可以在创建 Proxy 时在其内部设置一个标记属性，以便后续判断。 const originalObject = {}; const proxy = new Proxy(originalObject, { get(target, prop) { if (prop === '_isProxy') return true; return Reflect.get(target, prop); } }); function isProxy(obj) { return obj && obj._isProxy === true; } console.log(isProxy(proxy)); // true console.log(isProxy(originalObject)); // false 使用 instanceof 关键字: 不幸的是，直接通过 instanceof 来判断是否为 Proxy 是不可能的，因为我们无法直接访问 Proxy 的构造函数。 总的来说，上述方法是较常见的判断一个对象是否为 Proxy 的方案。选择适合自己需求的方法来实现即可。 递归代理 要解决object下的key是对象或者数组, 其子键或者子元素被修改时调用的是get而不是set的问题, GPTo答复是递归代理. 下面给出的是对象的递归代理, 实际还需要考虑数组. 递归代理是对了,但是GPT4o在第一次给出的代码中并没有实现递归代理,指出后,在第二次实现了递归代理, 但设置深层子元素的时候调用了2次set(重复代理了),指出问题后, GPT4o再修改了6次, 也没能回答正确. 感觉是黔驴技穷啦. 这儿贴出其中一次的代码. function createReactiveObject(obj) { return new Proxy(obj, { set(target, property, value) { // 检查设置的值是否为对象 if (typeof value === 'object' && value !== null) { // 用 Proxy 处理该对象 value = createReactiveObject(value); } // 设置实际值 target[property] = value; console.log(`属性 ${property} 被设置为: ${value}`); // 输出变更信息 return true; // 返回成功标识 }, get(target, property) { const value = target[property]; // 仅当获取的是对象时才返回新的代理，避免递归代理产生重复 if (typeof value === 'object' && value !== null) { return createReactiveObject(value); // 利用递归返回新的代理而不是多次创建同一对象的代理 } return value; } }); } // 创建动态对象并使用代理函数包裹它 const dynamicObject = createReactiveObject({ k1: { k2: { k3: {} } } // 初始化嵌套结构 }); // 测试：设置嵌套属性 dynamicObject.k1.k2.k3.k4 = 20; // 应只输出一次: 属性 k4 被设置为: 20 // 打印查看当前状态 console.log(dynamicObject);
做了个event发送和超时等待程序, 结果小程序不能用, 只适用于node
node版本 作为tools.js的功能, 代码如下 const EventEmitter = require('events'); const eventEmitter = new EventEmitter(); // 事件发射 emitEvent(event, arg){ eventEmitter.emit(event, arg) }, //等待事件, 成功则返回args, 失败则返回null async waitEvent(event, timeout = 500){ return new Promise((resolve, reject) => { let timer = setTimeout(() => { reject(timeout) // 如果用await waitEvent(),则抛出异常值为timeout }, timeout) // 监听消息事件 const messageListener = (arg) => { clearTimeout(timer); // 清除定时器 eventEmitter.removeListener(event, messageListener); // 移除监听器 resolve(arg); // 解决Promise，返回数据 }; eventEmitter.on(event, messageListener); // 添加监听器 }) } 使用示例: f = async ()=>{ setTimeout(()=>tools.emitEvent('laugh',"hahaha"), 100) try{ let res = await tools.waitEvent('laugh', 500) console.log("res is", res) }catch(e){console.log('timeout', e)} } f() // 打印: res is hahaha
英语ob开头却有不同的发音和不同的意思
obligation(义务) obviously(显然地),其中的ob-读作/ɒb/, 词根是强调的作用, 重音在o. 而oblivious(健忘的)的obliv- 读作/əˈblɪv/,词根是遗忘的意思, 重音在b.
参考https://juejin.cn/post/6995464881205936164 /** * @description 描述fn的作用或功能 * @param {string} a 参数描述 * @param {number} [b] 参数描述 * @param {boolean} [c=false] 参数描述 * @param {array} arr 参数描述 * @param {string} arr[0] 参数描述 * @param {number} [arr[1]=undefined] 参数描述 * @return {number} 描述返回值 */