李恒道 发表于 2024-3-15 17:54:24

[油猴脚本开发指南]实战抖音React富文本输入框

我们的目标是触发输入框的消息
![图片.png](data/attachment/forum/202403/15/170036npz5jr9bcth339bm.png)
查看DOM结构发现没有任何输入框
应该是通过监听输入事件后读取数据自己合成出来文字
![图片.png](data/attachment/forum/202403/15/170129ld502353e9092eta.png)
我们网上逐层找看看会不会有什么思路
可以看到有一个叫做DraftEditor-root的Dom节点,这个大概率是一个React组件的根
![图片.png](data/attachment/forum/202403/15/170308c3thk4vvkvyry4kc.png)
我们在他和im-richtext-container两个之间找找有没有什么有用的信息
发现在im-richtext-container的__reactFiber$n5t796psn7s.memoizedProps.children.props.children.props中有一个onChange的回调函数
![图片.png](data/attachment/forum/202403/15/170514gtxwp7j6xcuc2i68.png)
感觉有戏?我们在控制台打印出来然后追过去下一个断点
![图片.png](data/attachment/forum/202403/15/170611weyye02qra08xj5j.png)
再次尝试触发输入,但是没有显示任何的数据,而是一个{_immutable:n}的对象
![图片.png](data/attachment/forum/202403/15/170652l4jgvjjfvvwgwg4w.png)
那我们目前就走投无路了,难道真的就就此停止了?
不!!
我直接给我女神打一个电话表白,表白失败获得度日如年BUFF
然后打开网易云音乐叠一个战歌BUFF
再高喊因为我背负的太多,所以我根本不会输
然后临时叠上LGBT,素食主义者,螺旋武装直升机等BUFF
只要BUFF叠的够满,一级也能打爆BOSS

BUFF叠的差不多了,我们就开干
我们从DraftEditor-root找找思路,发现根据搜索有一个Draft.js的库
同样也有react版本,我就找了一份在线例子看看
https://codesandbox.io/p/sandbox/draftjs-ytf7q
发现对比抖音的结构几乎一致
!(data/attachment/forum/202403/15/171121f334dkzdq30fo4x0.png)

那我们就去看看react版本的draftjs
可以发现其中我们刚才找到的应该是editorState对象,onChange则是通过一些其他逻辑然后设置editorState
```js
import React from 'react';
import ReactDOM from 'react-dom';
import {Editor, EditorState} from 'draft-js';
import 'draft-js/dist/Draft.css';

class MyEditor extends React.Component {
constructor(props) {
    super(props);
    this.state = {editorState: EditorState.createEmpty()};
    this.onChange = editorState => this.setState({editorState});
}

render() {
    return (
      <Editor editorState={this.state.editorState} onChange={this.onChange} />
    );
}
}

ReactDOM.render(<MyEditor />, document.getElementById('container'));
```
那我们的目标就是如何生成editorState并且丢给onChange呢?
我们查阅各种提问找到了一个设置初始值为自定义类型的demo
https://stackoverflow.com/questions/71496940/how-can-i-set-defaultvalue-on-react-draft-wysiwyg
```js
import { Editor } from "react-draft-wysiwyg";
import { EditorState, ContentState } from "draft-js";

export const TestComponent = () => {
const = useState(() => {
    const content = ContentState.createFromText(
      "This is your default content."
    );
    return EditorState.createWithContent(content);
});

   return (<Editor
            editorState={editorState}
            wrapperClassName="wrapper-class"
            editorClassName="editor-class"
            toolbarClassName="toolbar-class"
            onEditorStateChange={onEditorChange}
            />);
}
export default TestComponent;
```
到这里我们就知道了需要调用`ContentState.createFromText`以及`EditorState.createWithContent`生成,我们可以选择Webpack核心注入方式拿到draft.js的函数,但是由于Tree-Shark的原因难以保证没有被调用的函数依然能正确运行,同时由于这种初始化数据的函数极有可能是有一个无状态函数,所以我们尝试直接引入一个draft.js生成editorState内容试试。
直接引入`// @require      https://cdn.bootcdn.net/ajax/libs/draft-js/0.11.7/Draft.js`会报错,根据查阅发现还需要react以及react-dom,过于复杂了,所以感觉建立一个项目通过webpack打包到一起暴露出去吧。

安装webpack依赖`npm i webpack webpack-cli -D`,安装draft依赖`npm i draft-js `,然后编写代码
```js
import { EditorState, ContentState, convertFromHTML } from "draft-js";

export function init() {
return {
    EditorState,
    ContentState,
    convertFromHTML,
};
}
```
然后编写一个简易的webpack模板
```js
//webpack.config.js

const path = require("path");
module.exports = {
entry: "./index.js",
output: {
    filename: "bundle.js",
    path: path.resolve(__dirname, "dist"),
    library: "draftUtils",
},
mode: "production",
optimization: {
    usedExports: true,
},
};
```
通过npx webpack即可打包
然后引入我们的js并且写一个生成函数
```js
// ==UserScript==
// @name         New Userscript
// @namespace    https://bbs.tampermonkey.net.cn/
// @version      0.1.0
// @descriptiontry to take over the world!
// @author       You
// @match      https://www.douyin.com/*
// @require      https://scriptcat.org/lib/1612/1.0.0/draftUtils.js
// @grant      unsafeWindow
// ==/UserScript==

const { ContentState, EditorState } = draftUtils.init()
function generateRichText(text) {
    const content = ContentState.createFromText(
      text
    );
    return EditorState.createWithContent(content)
}
unsafeWindow.generateRichText = generateRichText
```
根据测试可以正确生成富文本的数据对象了
![图片.png](data/attachment/forum/202403/15/174508awsq3rrw0r33slc0.png)
接下来我们把刚才的im-richtext-container的__reactFiber$wwgviaigfbb.memoizedProps.children.props.children.props.onChange投递进去这个对象即可实现draft.js的数据触发
# 结语
撒花

uuorz 发表于 2024-3-17 12:57:10

大佬,mac不支持scriptcat+vscode吗

李恒道 发表于 2024-3-17 14:08:43

uuorz 发表于 2024-3-17 12:57
大佬,mac不支持scriptcat+vscode吗

应该是可以的吧
我没用过mac
但是论坛其他人有
哥哥可以开个新帖询问

Su. 发表于 2024-3-17 15:30:49

放手一搏吧,别顾虑太多

cocang 发表于 2024-3-17 23:47:14

dgnb !!!!!!!!!

tao233 发表于 2024-10-10 11:58:06

大佬厉害,我也是被这个问题困扰了

tao233 发表于 2024-10-10 14:28:32

虽然看完了,但我还是不太明白,这怎么使用{:4_115:},我也遇到了这个问题,还发了一个求助帖

tao233 发表于 2024-10-10 14:40:50

我使用控制台调用,输入框里面还是没有内容呀,前端学的不是很明白,求求大佬告诉一下原因

tao233 发表于 2024-10-10 14:59:14

我把这个输入框onchange函数改为你的,但是不知道怎么触发,我js还是薄弱了,大佬求教

李恒道 发表于 2024-10-10 16:07:39

tao233 发表于 2024-10-10 14:59
我把这个输入框onchange函数改为你的,但是不知道怎么触发,我js还是薄弱了,大佬求教 ...

我后边有写
通过react的函数来触发
比如im-richtext-container的__reactFiber$wwgviaigfbb.memoizedProps.children.props.children.props.onChang
怎么找可以参考
https://learn.scriptcat.org/%E6%B2%B9%E7%8C%B4%E6%95%99%E7%A8%8B/%E4%B8%AD%E7%BA%A7%E7%AF%87/%E5%85%83%E7%B4%A0%E8%A7%84%E5%88%99%E6%A0%A1%E9%AA%8C%E5%92%8C%E6%A3%80%E6%B5%8B%E7%9A%84%E8%A7%A6%E5%8F%91/

尽量还是看独立站的,这个更简洁干净一些
页: [1] 2
查看完整版本: [油猴脚本开发指南]实战抖音React富文本输入框