2024年7月

【符咒原理-哔哩哔哩】 https://b23.tv/03OxEjN

我的理解一生二、二生三、三生万物,这些数字是带有单位的。一是一维线段,二是线段的二个方向,三是线段的左中右三个端点,也可以视为一个中点+二个方向,此即一生二二生三。三生万物呢?就是一个维度(包括二个方向三个点)叠加上其他维度,生成了万物。此维度,既可以是几何空间的维度,也可以是时间维度、以及其他的任何维度。以最简单的两个维度相叠加,中点重合、相互垂直,共一个中点、四个方向,即为五。那这个五,其实就是直角坐标系,也可以是一个二维平面。五=直角坐标系=x轴+y轴+原点。两个轴代表不同维度,这个坐标系就可以表示各种概念,也就是我们在Excel和各种统计学中看到的折线图、柱形图、散点图……用于表示GDP增长、股票涨跌、企业竞争……维度从一维到再二维增加到更多维度,就是三生万物。
十和廿不太理解老师所讲,只能说下自己的理解。将一个二维概念——平面作为基础,则两平面相交为十,相交于一条直线。这似乎变成了三维概念,但我认为不是如此,因为三维概念应是七,即六方向+一原点,但是十=五+五,即两个独立系统有各自的维度,又相互关联,确实与父母两人相互独立又关联交合很像。此处“交合”应为广义的,不限于性的交合,也包括生活方方面面的交合,与此同时两人又有各自的独立性。扩展一些,可解读为任何人与人之间在生活上的共同交集。廿似乎能解读为相互平行的平面?套用在人这个维度上,也就是相互之间没有直接交集的人,而中间一横,代表了中介人,即人与人之间即使没有直接接触,也是通过其他人连接成一个整体。人与人如此,万事万物亦是如此。
关于咒,老师说咒是口号,我理解还有一个接近的概念:座右铭。我们都知道口号光喊是没用的,重要的是行动,座右铭也是如此。说到底,古人门上贴的咒语、现代墙上刷的口号、桌子上摆的座右铭,都不只是喊喊而已的,它们的作用是时刻激励自己行动起来去改变自己。然而,很多人、甚至多数人,对待它们都只是喊喊而已,甚至喊都不喊,摆在那里就期望生效,其实只是让咒语、口号、座右铭承担了自己无法行动的愧疚。这个时候,桌上的座右铭、墙上的口号就和现代人不明所以的咒、符一样,变成了单纯的精神寄托、甚至是迷信了。咒、口号、座右铭上所写,都是自己的心愿,是所想要达成的自己,如何达成?挂墙上就能达成吗?是念。念咒的念字,是心字底,如果只是嘴上说说而不行动,就是心口不一,就不叫念。心口一致,就是知行合一,长期坚持,就是定力,正是因为在自己在自己的心愿上长期坚持,知行合一,才会产生法力:量变到质变,达成心愿,产生奇迹。

希望用油猴做一些自动化的工具. 不用自动化测试软件的原因是特征都能被浏览器和页面检测出来, 所以这就存在一些风险. UiBot RPA虽然也可以, 没有检测痕迹, 但一是感觉软件太重了, 二是只能解决一些简单的Web上的问题, 很多时候复杂的问题如shadowRoot还需要配合js代码注入, 三是Uibot的代码编辑页实在有点难用,仿VB语言的算法也实在不太适应,尤其是不等号<>, 还有赋值和比较都是=不区分, 四是缺乏第三方库.
先推荐一个教程, 据说是中文唯一写的好的. https://github.com/scriptscat/tampermonkey-learn-guide
油猴官方可以说没有教程tutorial, 只有按字母序排列的API的说明. 虽然会JS上手也能写, 但只有明白额外的API才能进阶高级, 感觉有点像是electron, 不知道油猴是不是能实现类似electron的效果?

油猴名字

油猴这个翻译其实是grease monkey, 代码里简称的GM就是. 而tamper monkey是破坏猴的意思.

// @

最前面的注释部分, 以// @开头的其实都是给油猴看的代码, 类似于预定义, 是和油猴交互的关键. 其中最重要的一定要改的部分呢列出来.

//@命令 子命令 解释
//@name 名称 脚本名称
//@match 网址 匹配网址, 也就是在哪个网址运行. 支持通配符*
// @grant none 脚本直接注入window环境, 同时也不能使用GM_*命令了,所以一般不用
- unsafeWindow 直接使用页面中的任何脚本. 这就会打通页面和本地,理论上页面可以窃取本地内容并操控本地的一切. 脚本中的window需要替换为unsafeWindow
- GM_* 申请指定的GM函数权限.页面window环境需要用unsafeWindow访问.
- GM_xmlhttpRequest 允许跨域请求API
- GM_setValue/ GM_getValue/ GM_deleteValue/ GM_addValueChangeListener/ GM_removeValueChangeListener/ GM_listValues 设置/获取/删除/监听/停止监听/列出本地键值对
- GM_registerMenuCommand /GM_unregisterMenuCommand 在油猴按钮上注册菜单
- GM_addStyle 增加
- window.onurlchange/.close/.focus 这三个window权限需要grant声明才能用
// @run-at document-start 在document加载时就尽快调用脚本(比页面脚本更早)
context-menu 右键增加tempermonkey菜单,子菜单为本脚本名称, 点击运行
// @connect 网址 允许被GM_xmlhttpRequest请求的网址
// @require js文件URL#md5=xxxx 加载外部js资源文件并附带md5校验.引入油猴环境还是页面环境要看@grant定义. 也可以通过在html中插入script的方式来引用
// @resource css css文件URL 加载外部css

常用js代码部分

在html中增加元素

let div = document.createElement("div");
div.innerHTML = '<span>span1</span><span>span2</span>';
// 插入到页面的body中
document.body.append(div);

在html中增加按钮并监听

监听单个元素

let btn = document.createElement("button");
btn.innerHTML =
  "按钮文字,其实也可以写html,变成下面的样子(不过谁用按钮来包那么多html标签呢)";
//innerText也可以,区别是innerText不会解析html
btn.onclick = function () {
  alert("点击了按钮");
};
document.body.append(btn);

监听多个元素

let div = document.createElement("div");
div.innerHTML =
  '<span id="span-1">span1</span><span class="sp">span class</span>';
div.onclick = function (event) {
  if (event.target.id == "span-1") {
    alert("span-1被点击了");
  } else if (event.target.className == "sp") {
    alert("sp这一类被点了");
  }
};
document.body.append(div);

用事件监听器去减轻监听

div.addEventListener("click", function (ev) {
  console.log(ev);
});

在html中插入script

let script = document.createElement('script');
script.setAttribute('type', 'text/javascript');
script.src = "https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.min.js";
document.documentElement.appendChild(script);

在html中插入css

let script = document.createElement('link');
script.setAttribute('rel', 'stylesheet');
script.setAttribute('type', 'text/css');
script.href = "https://blog.icodef.com/wp-content/themes/Kratos-3.0.7/assets/css/kratos.min.css?ver=3.2.4";
document.documentElement.appendChild(script);

直接用GM_addStyle插入样式

GM_addStyle("#HMRichBox{display:none !important}");

在页面加载完毕后再执行

等所有元素加载完毕(包括图像等)

    window.onload = ()=>{
        alert('loaded')
    }

在油猴按钮上注册菜单 GM_registerMenuCommand

let id = GM_registerMenuCommand(
  "自定义的菜单",
  function () {
    alert("菜单被点击");
    GM_unregisterMenuCommand(id); //删除菜单
  },
  "h"  // 这个是accessKey, 快捷键
);

其他问题

如何对付嵌套iframe的页面

要看iframe打开的是哪个url, @match进去就好

如何劫持js页面函数

在window下面的函数都可以直接劫持. 如 window.setInterval = 自己的函数, 页面中自定义的函数也可以这么劫持, 如window.页面函数 = 自己的函数
几个常常劫持的函数, 除了setInterval函数劫持后可以改变时间帧间隔外, XMLHttpRequest函数劫持可以获取网络请求. 比如劫持XMLHttpRequest.prototype.send就可以修改发送的内容.
除了用XMLHttpRequest,页面还可能用fetch获取服务, 这时候需要对fetch劫持

let oldFetch = fetch;
function hookFetch(url, init) {
  //这里进行提交内容劫持
  return oldFetch.apply(this, arguments);
}
window.fetch = hookFetch;

对事件监听器劫持

const oldEventListener = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function (...args) {
  console.log("addEventListener Hook", this, ...args);
  return oldEventListener.call(this, ...args);
};

其他可以劫持的还包括window.WebSocket
还可以劫持原型链上的函数. 如某个object.func()在其原型链上, 可以object.prototype.func = 自己的函数

如何在代码中打断点

在代码中使用debugger;命令,F12打开时就会停在这儿

传统上有很多, 但有的太老,有的太难. 比如Selenium. 微软新出的playwright学习曲线也比较陡峭.
谷歌的puppeteer, testcase似乎更容易些. 然而最近比较火的是cypress, 基于node, 据说非常容易上手.
其实,我觉得油猴是否也可以用来写测试, 说不定也挺好用.
油猴就相当于在F12里写js. 但cypress的好处是可以自动等待页面或元素的加载.
但是cypress会被https://bot.sannysoft.com/检查出正在使用WebDriver, 也就是可能被识别为爬虫. 浏览器自身也会识别出来. 如用edge做cypress的时候, 会提示正在被自动测试软件控制.
另外UiBot creator打开https://bot.sannysoft.com/也不会被检测出任何问题.

之前对分页和瀑布流的理解比较简单, 就是手机滑动更适合瀑布流而电脑点击更适合分页. 今天才发现自己想简单了.
确实, 电脑上鼠标拖拉和滚动都不如手机上的手指滑动操作方便.上滑就特别适合加载新的数据.
但是,数据呈现的目的是不同的,两种方式各有优劣. 虽然瀑布流在手机上发扬光大, 但两者不是以手机或电脑来区分的.
我最近做的小程序, 需要呈现很多数据, 并且这些数据还需要增删改查. 因为是手机用, 我想当然认为瀑布流体验更好(当然实现难度也大), 就选择了用瀑布流.
然而近期发现一些问题, 用户反馈有时候数据会乱, 常常是重复. 查了下不是数据库的问题, 而是界面呈现的问题. 当然这种情况重新进入小程序也能解决. 我增加了一些控制, 在从数据库取数据的时候禁止用户操作, 但只解决了一部分问题.
最近打算用js面向对象的方法重构这部分代码, 写到增删改查的时候想到了这个问题: 在UI设计中, 瀑布流的方式是否适合呈现有大量数据的增删改查的页面?
如果增加了一个数据, 需要考虑这个数据增加的位置. 如果增加的数据排在前面已经显示的数据中, 那么就要重新请求已显示的数据. 但数据库的查询是按分页进行的, 我应该请求哪些分页? 似乎从数据增加位置之后的分页都要请求. 那么新数据增加在第几页? 需要计算,且计算结果必须和数据库自己的排序计算结果一致. 如果请求这之后的所有分页,有可能数据量非常大. 而且界面现在显示了N页, 增加1条数据变成了N页+1条, 而数据库是按页请求, 这样又不对齐了, 显示的最后一条数据要么从显示中删除, 要么再请求一整页.
删除有同样的问题. 修改操作如果修改的是排序的依据, 也存在新数据排到了哪儿的问题, 新旧位置之间的数据都要更新,或者用算法保持与数据库端一致.
这个逻辑就会变得复杂. 根源是: 数据库是按照分页方式请求的, 前端的增删操作导致前端数据和数据库数据无法对齐. 需要大量操作使两端对齐, 耗费本地计算和带宽, 感觉很不经济.
用分页就解决了, 非常简单, 增删改查后, 只要再次请求当前页就好了!即便是删除数据导致当前页消失, 也很容易计算到最近还存在数据的页是第几页.
这个问题抛给了metaso和gpt4o,两者都给出了否定的回答, 都指出分页更适合.
根据metaso给出的链接参考: https://blog.csdn.net/weixin_64051447/article/details/129420444, 其中有一个引文很重要:

滚动是延续,而点击是决定。—— Josh Porter

瀑布流就是为了不断地让用户看新的东西(新数据不断延续没有终点), 而点击是用户自己决定要看哪一部分东西.
所以瀑布流适合给用户不断地灌输新的数据, 而分页适合让用户管理数据.
贴一下gpt4o的回答, 我觉得总结得挺好

gpt4o的回答

在UI设计中,瀑布流(也称为无限滚动)是一种常见的布局方式,尤其适用于展示大量内容,例如图片库、社交媒体动态等。然而,这种布局方式在某些场景中可能并不合适,特别是在需要对大量数据进行增删改查(CRUD操作)的页面上。

瀑布流布局的优势:

  1. 用户体验:用户可以不间断地浏览内容,不需要经过分页的过程。
  2. 视觉吸引力:对于展示图像、视频等多媒体内容时,瀑布流能够更好地利用屏幕空间,看起来更加美观。
  3. 加载效率:通过懒加载技术,可以动态加载内容,从而减少初始加载时间,提高性能。

在增删改查页面中使用瀑布流可能的问题:

  1. 可查找性差:当用户需要查找特定数据时,瀑布流不如分页结构直观。无限滚动让定位特定记录变得困难。
  2. 数据管理复杂:频繁的数据增删操作可能导致数据的顺序和显示出现问题,需要复杂的逻辑进行维护。
  3. 浏览状态难以保存:用户在进行编辑后需要返回列表时,不容易恢复到之前的浏览位置,这会影响用户体验。
  4. 性能问题:随着数据量增加,长时间滚动会占用更多内存,可能导致性能下降。

适合增删改查页面的替代设计方案:

  1. 分页设计

    • 每页显示固定数量的数据,便于管理和查找特定记录。
    • 提供清晰的导航条,让用户能够快速跳转到不同页码。
  2. 列表视图和表格视图结合

    • 使用表格视图提供清晰的数据结构显示,便于排序和筛选。
    • 提供简单直观的数据操作按钮,例如新增、编辑或删除。
  3. 搜索和筛选功能

    • 提供强大的搜索栏和筛选条件,让用户能够快速找到所需数据。
    • 动态更新结果,提高交互效率。
  4. 分区加载

    • 结合懒加载技术,仅在用户需要时才加载更多内容,但采用明确的分段结构,而非无限滚动。

综上所述,对于有大量数据且涉及频繁增删改查操作的页面设计来说,更建议采取分页设计、结合列表和表格视图,以及提供强大的搜索和筛选功能来提升用户体验。瀑布流布局虽有其独特优势,但在这种场景中并不是最佳选择。

jest也是微信官方推荐的.
最简单的方式: jest安装后, 在目录下运行jest就可以. 它会搜索当前目录和所有子目录,并运行*.test.js结尾的所有测试,并汇总.
对于微信中的一些全局模块如wx, 需要mock. 在测试目录下建立__mocks__/目录, 所有要mock的都放在这儿. 如放个wx.js
*.test.js中, 对全局的wx赋值global.wx=require('__mocks__/wx.js').
wx.js使用module.exports导出即可.
除了自己直接写mock模拟的函数外(如写一个wx.cloud.database = function mockFunc(){}的mock函数), 还可以用jest的mock函数const mockFunc = jest.fn(函数体);wx.cloud.database = mockFunc. 这样被mock的函数就会自带统计和记录功能.
如:

  • 统计mock函数被调用的次数 mockFunc.mock.calls.length
  • mock函数第n次调用时的第x个参数值 mockFunc.mock.calls[n][x]
  • mock函数第n次调用的返回结果 mockFunc.mock.result[n].value
  • mock函数最后一次调用的第一个参数 mockFunc.mock.lastCall[0]
  • 对class的mock, 同样可以使用new const myMock1 = jest.fn();const a = new myMock1();
  • mock函数定义每一次的返回值,并且尅循环调用 mockFunc.mockReturnValueOnce(10).mockReturnValueOnce('x').mockReturnValue(true)
  • mock模块的异步Promise返回值
import axios from 'axios';
jest.mock('axios'); 
const users = [{name: 'Bob'}];
const resp = {data: users};
axios.get.mockResolvedValue(resp);
  • mock一个模块的部分函数和值

五块金牌是留给勇敢者的, 智慧者的, 发挥最好的人才配得上.

阅读理解: 勇敢和智慧, 即胆识. 主观的胆识才能遇到和抓住客观的机遇. 发挥最好, 也就是说能力最强并不能拿到冠军, 要临场发挥最好. 也就是说, 我们自己每个人恃才傲物, 觉得自己能力很强, 但只有在实战中发挥出来, 才能赢.

你面面俱到, 练得没有漏洞是不可能的, 只是在这些当中, 能够提炼出重点, 把这些得分手段精益求精, 把短板,把对手抓你的地方有所突破, 有所改善.

阅读理解: 面面俱到没有漏洞等于不可能. 所以没有人是完美的, 不要完美主义. 那要怎么做? 要把重点的得分手段去精益求精, 把短板(是指对方攻击自己的点)有所突破和改善. 这和木桶理论有一点矛盾, 或者说, 和用木桶理论作为解释一切的手段有矛盾. 木桶理论说最短的木板决定装水的容量, 所以要把所有的短板都补长, 所以要方方面面每个木板都做高, 做完美. 木桶理论有什么问题? 木桶是装水的, 不让静态的水流失的手段,所以木桶理论仅仅是防御静止的成果流失的手段, 只守而不攻, 并且是不去区分地防守. 个人资源是有限的, 环境是动态变化的, 而完美是不可能的, 把所有资源都投入防守, 面对动荡变化的环境, 最后只会成果越来越少,就像拎着装水的木桶在疾驰在颠簸路面上疾驰, 木桶上下翻滚, 然后我们的精力却全部放在修补木桶的短板上. 回到刘教头的话, 短板只能是有所突破和改善就很好了, 并且要补对手攻击自己的短板, 如果自己知道的弱点而别人不知道, 无法攻击也就无所谓去弥补. 面面俱到不可能, 要加强得分手段, 也就是要攻击对方, 要得分, 要开源, 而不是只是固守现有的成果. 所以, 强调木桶理论很容易故步自封陷入完美主义, 防御不存在的假想敌. 开源节流, 不能只节流不开源. 并且要突出自己的优势去开源, 去最大可能地发挥优势主动去抢夺(市场/资源/分数). 对于短板的修补要有针对性, 争取突破改善, 而不是要把短板做到最好. 短板之所以是短板, 就是自己天生或习惯弱于对方的, 补短板是事倍功半, 要补, 但要在自己有限的资源下看性价比.

会打球和会赢球是两码事

阅读理解: 能力强和能成功是两码事. 自己很强, 会很多事情, 很勤奋, 但就能成功吗? 两码事. 所以不要总是想着自己多强,或者把资源都投入让自己变强. 是不是很反传统? 除了变强,还要去赢. 强为什么不等于赢? 还是因为"强"是静态的,是此时此刻的一个状态, 而"赢"是动态的, 是竞争,是争取, 是随机应变. 如果不能随机应变,发挥自己的强, 适应竞争的环境,打败现实的对手(而不是想象的不存在的对手).

在赛场上的时候, 侥幸和犹豫, 想赢怕输, 这是失败的根本.宁肯坚决地错,也不犹豫地对. 因为你坚定下来的东西一定是你的认知.

阅读理解: 坚决地错, 很反传统. 传统有道是"三思而后行",但这未必是对的. 坚决地错和犹豫地对有什么根本区别? 坚决就是出自自己的认知, 犹豫就是混杂了别人的想法. 因为对别人的想法理解不通透, 所以即使是对也不知道为什么对, 又因为与自己想法的冲突, 因此犹豫.但在赛场上, 在战场上商场上, 一是没有时间给你犹豫, 二是没有足够的信息给你犹豫, 在那一刻必须做出尽快的决定, 无论对错. 如果是错的, 也是事后有了结果,有了充足的时间再去分析, 然后纠正的改善的是自己的认知, 而不是去简单听从别人的意见.所以, 坚决地错, 就是坚定执行自己的认知, 即便是错误的, 也是改善自己认知的机会. 如果没错过, 也就不可能提升自己的认知.

如果你在犹豫的时候,其实你怀疑的是自己,把位置摆低,去拼这五个项目,而不要去守.

阅读理解: 去拼,不要去守. 是换个方式讲上面说的得分手段精益求精. 得分就是要进攻, 进攻才能开源, 开源才有节流的资本, 才有能守的对象. 然而, 在激烈的竞争中, 主动进攻胜于被动防守. 被动防守总是容易消极的, 盯着自己的错误而不是别人的错误, 只能防止资本的减少而不能增加资本.

实现梦想,不留遗憾, 相信自己,相信团队.

阅读理解: 这句话虽然是末尾的一句祝福打气话, 但是也是再一次强调了前面说的话. 实现梦想不留遗憾, 也就是要去拼, 做自己想做的. 相信自己也就是要坚定和实践自己的认知. 相信团队, 做很多事情都不是一个人能完成的, 如果是一个团队去做, 要彼此信任才能减少不必要的内耗.

默认的导航栏NavigationBar不支持触摸事件, 需要自定义导航栏. 官方社区有个文档可以参考https://developers.weixin.qq.com/community/develop/article/doc/000a8c989307888cbe1abbf675f413

以下是gpt4o的回答.

在微信小程序中,原生的导航栏(通过 navigationBarTitleText 等配置项定义的顶部标题栏)本身不支持直接添加点击事件。不过,你可以采用一些变通的方法来实现类似的效果。

自定义导航栏

你可以通过自己编写一个自定义导航栏组件来实现点击事件。这通常涉及隐藏原生导航栏,并在页面顶部放置一个自定义视图组件。

隐藏原生导航栏

app.json 或单个页面的 json 文件中,将 navigationStyle 设置为 "custom"

{
  "navigationStyle": "custom"
}

创建自定义导航栏

创建一个自定义组件,例如 custom-navbar:

custom-navbar.wxml

<view class="navbar">
  <view class="navbar-title" bindtap="onTitleClick">{{title}}</view>
</view>

custom-navbar.wxss

.navbar {
  height: 40px;
  background-color: #fff;
  display: flex;
  justify-content: center;
  align-items: center;
}

.navbar-title {
  font-size: 18px;
}

custom-navbar.js

Component({
  properties: {
    title: {
      type: String,
      value: '默认标题'
    }
  },

  methods: {
    onTitleClick() {
      // 自定义逻辑,比如跳转或者弹出提示等
      wx.showToast({
        title: '标题被点击了',
        icon: 'none'
      });
    }
  }
})

在页面中使用自定义导航栏

page.wxml

<custom-navbar title="我的标题"></custom-navbar>
<view class="page-content">
  <!-- 页面内容 -->
</view>

这样一来,你就可以在自定义导航栏中处理各种点击事件,完全掌控其行为和样式。此外,自定义导航栏组件可以反复使用,还能根据需要灵活调整。

先是介绍了newrank 新红网站, 可以搜索小红书的一些数据. 和小红书官方的蒲公英类似. 注意不是千帆, 千帆是卖家订单管理.
新红虽然是非官方, 数据刷新肯定不如官方及时, 但是比蒲公英的数据肯定更全面的. 蒲公英的目的是要推荐商家与博主合作, 并且管理自己与博主合作的笔记, 所以像是笔记版的1688, 包括筛选博主, 筛选笔记,管理合作的笔记. 所以是没有全局的数据的, 比如某一个类别的整体数据表现. 当然单个博主的数据还是挺全面的. 包括其笔记内容和粉丝画像等.

新红和蒲公英对比

数据 新红 蒲公英
大盘数据 有, 种草流量大盘可看到类别下面的商业笔记和种草达人数量, 计算含商量
博主筛选,找对标账号 有, 找红人-红人搜索, 按作者类别/ 粉丝数/ 进行筛选.列表中可以看到合作品牌数 有, 在寻找博主-博主广场中, 可以按内容类目/ 粉丝量搜索. 但合作的笔记数需要点入博主详情页, 笔记案例-按笔记类型-合作笔记中查看, 也可以看近期传播表现-近90日查看笔记数据

课程内容

这一节说定位和赛道,我认为本质还是降本(成本维度)增效(变现维度),另外看自身能力(能不能做)和优势(做的比别人好).
除了上面的优势外, 还有所谓养成号,如挑战减肥多少斤第N天.
赛道: 主题 .
三类赛道:

  • 观点: 心理学,情感等,输出价值观
  • 类目: 类似电商类目的选择
  • 人设: 经营自己,相对较难
    变现: 广告/咨询/社区/群聊

评估广告变现能力:

  • 不同赛道的含商量, 大牌不太在乎变现, 可能只想种草. 对应一个垂类市场变现能力就强

定义含商量: 商业笔记数量/种草达人数量 种草大盘
如 影视综: 6345/63110 = 0.1商业笔记(报备)/种草达人.
科技互联网 0.03, 美妆: 0.3 健康养生:0.4 职场: 0.01 旅游: 0.05 家居家装: 0.1 运动健身: 0.08 摄影摄像: 0.01 情感星座: 0.1 科学科普: 0.04 母婴 17w/79w=0.23 美食: 0.05 生活: 0.08 交通工具 <0.01 教育 0.03
小博主主要走非报备. 报备:非报备=1:1

  • 对标账号的变现能力分析
    举例账号: 内在小孩关爱计划
    teacher账号 阿言roy(地方的MCN) 挪威Talk
    其他 魏知新(No1 麻瓜MCN)

搭建人设
个人优势转化为他人价值(1. 利他; 2. 观点引发共鸣)
个人简介: 1. 介绍成就; 2. 经历; 3. 账号主要内容; 4. 联系人/Slogan

小红书主页经营:
头像/背景/介绍/打卡瞬间/封面 (这些都是告知算法自己是什么账号)
深耕.不单单是重复,还要做深.
商家倾向于投中小博主(1~5W)

红人搜索:作者类别

维系微信和小红书群。小红书群用于转发点赞,微信群用于聊天。
图文还是视频?答:从图文转视频。
知识类成本<非知识类的成本
单一场景<多场景
xx 100个系列
数码赛道抽奖比较容易提升点赞
标题反复强调相同的点,形成强化
呈现形式带植入点(产品植入)就容易变现广告
利用社会资源降低成本
要判断选题吸引观众的原因:是标题文字还是封面图片?
笔记分为两种:冲流量和粉丝的笔记(未来隐藏)和长期呈现的
笔记要写得扎心
观众为什么要点进来形成流量?奔着热点话题.
一开始不要打造差异化,先形成足够的用户(做好模仿),再去差异,筛选出用户。

小红书选题策略

  • 流量选题
  • 人设选题
  • 商业选题
    选题需要挖掘而不是去凭空想

自动化:在发现页找选题:点赞高的题目->搜索->看其中有多少点赞高的->看点赞高的作者粉丝数是否低->给出评分。最后要排除封面太好看点进来的。
点赞高有三个原因:1选题好,2粉丝多,3封面靓。要去排除2和3,找到仅因为选题好而获赞的选题。(粉丝少但流量高)
新鲜度:区分是最近的流行爆款(一个月内)还是长期的爆款(年年有)
建立选题库

通过tag寻找。点击tag->筛选->最热->回到上面的路径,找低粉高赞的选题。

通过笔记灵感寻找。小红书“创作服务平台“->笔记灵感->最热。有点接近于笔记灵感

同样的选题反复讲。 看到还有个区别是内容更加真诚更容易吸引人。

新红查找法(付费的)。新红中按互动量排名搜索。
还可以按爆款笔记排行榜查。

火过的选题还会再火,过段时间再次做。

JS中存储JSON只要简单的将object stringify以后写入文件就可以. 反过来读取就是读入文件为字符串再parse.
C语言如何实现配置文件呢? struct当然是最像json的了, 保存就用Flash.
这儿需要注意struct和flash的麻烦之处.
struct的成员变量无论是什么类型,都需要内存地址对齐. struct变量所占内存是连续的, 且大小可以整除最大的变量类型大小. 比如 struct{char a; long b;}x; 那么sizeof(x)不是1+8=9,而是16. 这样如果flash寸土寸金就会显得浪费, 此时可以都用char存储. 这样存储时为了提高内存访问效率, 可以看这篇文章的解析, 有图示.
另外,struct类型的变量名不是地址, 如上面的x,要访问这个变量的地址需要加&,如&x. 这和数组就很不一样. 数组的变量名就是数组的地址. struct变量名其实更像普通变量.
flash 在前面讲过了, 每次写入需要擦除, 擦除需要整个扇区.
简单的做法, 就是把struct转为空指针, 并按大小存储到flash中. 读取也是同样.

存储数据必然有读和写. Flash当然也有. 但是, Flash的写是非常特殊的, 会引出一系列问题.

  1. 首先, Flash数据只能从1改为0, 那就意味着写以前必须得先把要写的字节都变成0xFF. 还好, 一般都会提供一个erase擦除的函数.
  2. 然而, 擦除操作必须要擦除整个sector! sector(一般翻译为扇区)是flash的最小单位, 具体多大看设置, 从512B到4K不等. BL2028N上有一个_MAX_SS_MIN_SS的宏定义, 默认为512, SS是Sector Size的简称.
  3. 所以如果你要写, 那么你需要擦除整个扇区的数据. 如果你不擦除, 那么你写的结果事实上是和当前扇区上的值相与的结果
    参考这个STM32 Flash读写的说明, 写数据要经过解锁-擦除-写入-上锁四个步骤.

所以正常来说还是用一个flash的库比较好, 比如easyFlash.EasyFlash在2019年v4.0以前只支持字符串值的读写. BL2028N使用的easyFlash正好是2018年的, 只能读写字符串.

感谢AI给出答案啊, 非常有用, 尤其是在第三方文档跟一坨屎一样的时候,还不如直接看原始代码.

var obj = {
name: "John",
age: 30,
city: "New York",
myFunction: function() {
        console.log ("Hello");
}
};

// 自定义replacer函数
function replacer(key, val) {
if (typeof val === 'function') {
        return val.toString ();
}
return val;
}

// 转换为JSON字符串
var jsonString = JSON.stringify(obj, replacer);
console.log (jsonString);

输出的json复制到vscode里格式化一下, 就能读了