lubyxu / record Goto Github PK
View Code? Open in Web Editor NEW日常工作总结
日常工作总结
最近公司有一个类似富文本的一个需求。类似markdown。为了满足公司个性化的一些问题,最终在方案选型上,选择了比较偏底层的draft-js
。
关于draft-js
有一些概念,根据一些真实体验,重新定位了一下:
EditorState
(Immutable
类型),表示整个编辑器对象。包含三个模块:ContentState
、SelectionState
、CompositeDecorator
。还有一些公共的方法:撤销/重置。
ContentState
(Immutable
类型),表示编辑器里的所有内容。内容由单元(ContentBlock
)组成。段落里面会有一些Entity
(实例对象),比如对于image来说,他的ContentBlock
是一个atomic
,需要对这个block
创建一个entity
用来存储image背后的url
。
contentState
返回如下:
由此可以看出,这里的ContentState
3组ContentBlock
,每个block
代表一个段落。他的entityMap为空。
CharacterMetadata
代表每一个字符的元数据。比如对于文本hello
来说
// 假设contentBlock的text是hello
// contentBlock.getCharacterList() 返回的则是
// [
// {style: [], entity: null},
// {style: [], entity: null},
// {style: [], entity: null},
// {style: [], entity: null},
// {style: [], entity: null},
// ]
// 数组中 第一个元素表示 'h'这个字符,他的style是个[],并且没有entity
SelectionState
(Immutable
类型),表示编辑器里的选择区域对象。既然是选择区域,那就有开始和结束。
他的SelectionState
anchorKey
: 代表区域start的block.key
。anchorOffset
:从block.key
到开始的偏移量。
focusKey
:代表区域end的block.key
。focusOffset
:从block.key
到开始的偏移量。
由于inline
、block
的样式不能覆盖全部富文本样式。比如可能要需要高亮、需要加背景。这个时候就想要用的自定义的组件了。
CompositeDecorator
可以扫描所有ContentBlock
,如果满足某些策略的话,就可以引用自定义的组件。
今天碰到了一个问题,__DEV__ is not defined
。 想了半天,不知道为什么!!!
__DEV__
没有的话,不是会一直往上找的么!!直到找到这个为止,找不到默认就是undefined,不应该报错呀!!
但是!!!!我错了。。。
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Errors/Not_defined
对于getter来说,如果整条作用域链上没有这个变量,会报 is not defined错误。
但是!对于setter而言。如果整条作用域链 没有这个变量,会做两件事情:
// 1、先在globalThis上声明这个变量
var __DEV__;
// 2、 再对这个变量赋值。
__DEV__ = 1;
!!!!!!!!多么基础的问题啊。。。。。。我居然没想到。。。。。可见生活之中处处是基础。
背景:当接口报一些没权限的错误时,如何处理这个问题?
有一个错误页面统一处理错误:ErrorPage
。
api返回成功后,判断errno,如果是NO_AUTH,跳转到错误页面,加上query。type=no-auth。
缺点:这个方案,看起来没有问题,但是也有很多问题。下面列出几个:
对于小程序来说
ErrorPage
需要记录上一页的路径,才能实现。因此,需要加页面加一个协议:backUrl=xxxxxxxx
,ErrorPage
需要加上一个协议backUrl=scanCode
,然后加上扫码逻辑。这个时候,问题又来了,扫码跳转到哪呢。因此,当错误多的时候,显然ErrorPage
上的路由协议是难以维护的。同时ErrorPage
里面的业务逻辑也是难以维护的。
总结:这个方案,可以临时使用,快速上线,但是显然,维护成本比较高。
这个方案分两个步骤:一个是接口出错时候的throw Promise.reject(注意,这个是Promise,不能是throw Error, 原因是Suspense,本身fallback出发,需要底层throw Promise.reject)。二个是为Suspense添加不同的fallback UI。
这个能解决的问题:我们将fallback的处理,分到了各个页面上,将
mark: https://blog.csdn.net/qq_41070393/article/details/110862053
不想知道原因。。。
React-Konva
主要作用是将Konva
的创建出来的节点,通过react-reconciler
来做协调。 React-Konva
将 Konva
节点,当做虚拟节点。因此,能看到React-Konva
代码里,有这么一段很奇怪的代码:
export const Layer = 'Layer';
export const FastLayer = 'FastLayer';
export const Group = 'Group';
export const Label = 'Label';
export const Rect = 'Rect';
export const Circle = 'Circle';
export const Ellipse = 'Ellipse';
export const Wedge = 'Wedge';
export const Line = 'Line';
export const Sprite = 'Sprite';
export const Image = 'Image';
export const Text = 'Text';
export const TextPath = 'TextPath';
export const Star = 'Star';
export const Ring = 'Ring';
export const Arc = 'Arc';
export const Tag = 'Tag';
export const Path = 'Path';
export const RegularPolygon = 'RegularPolygon';
export const Arrow = 'Arrow';
export const Shape = 'Shape';
export const Transformer = 'Transformer';
单纯的字符串的导出。那他到底划出来的呢!!!
感恩:
import ReactFiberReconciler from 'react-reconciler';
const KonvaRenderer = ReactFiberReconciler(HostConfig);
KonvaRenderer
有两个关键的API
: KonvaRenderer.createContainer(stage.current)
返回一个根的Fiber
节点,KonvaRenderer.updateContainer(props.children, fiberRef.current);
用于更新操作。
import React from 'react';
import { Text } from 'react-konva';
const Demo = () => {
return <Text text="hello" />
};
上述代码被转化为:
import React from 'react';
import { Text } from 'react-konva';
const Demo = () => {
return React.createElement('Text', {
text: 'hello'
}, null);
};
HostConfig
createInstance(type: Type, props, rootContainer, hostContext)
创建一个节点,相当于document.createElement(type)
。在创建之后,返回之前,我们会常常设置这个节点的属性(除了一些事件句柄)。这是因为,当一个节点创建了之后,他并不能保证被挂在到这棵树上。
/**
* This method should return a newly created node. For example, the DOM renderer would call `document.createElement(type)` here and then set the properties from `props`.
*
* You can use `rootContainer` to access the root container associated with that tree. For example, in the DOM renderer, this is useful to get the correct `document` reference that the root belongs to.
*
* The `hostContext` parameter lets you keep track of some information about your current place in the tree. To learn more about it, see `getChildHostContext` below.
*
* The `internalHandle` data structure is meant to be opaque. If you bend the rules and rely on its internal fields, be aware that it may change significantly between versions. You're taking on additional maintenance risk by reading from it, and giving up all guarantees if you write something to it.
*
* This method happens **in the render phase**. It can (and usually should) mutate the node it has just created before returning it, but it must not modify any other nodes. It must not register any event handlers on the parent tree. This is because an instance being created doesn't guarantee it would be placed in the tree — it could be left unused and later collected by GC. If you need to do something when an instance is definitely in the tree, look at `commitMount` instead.
*/
react-knova
来说// createInstance 只列出了核心代码
export function createInstance(type, props, internalInstanceHandle) {
let NodeClass = Konva[type]; // type 是 Layer、Group 等 会找到
const instance = new NodeClass(propsWithoutEvents);
applyNodeProps(instance, propsWithOnlyEvents); // 将event设置到节点上,并绘制在canvas上。
return instance;
}
createTextInstance(text: string, rootContainer, hostContext)
text
节点的createInstance
/**
* Same as `createInstance`, but for text nodes. If your renderer doesn't support text nodes, you can throw here.
*/
react-knova
来说不做处理。
appendInitialChild(parentInstance: Instance, child: Instance | TextInstance)
会改变parentInstance
,会增加child
到他的子节点中。类似于DOM
中的parentInstance.appendChild(child)
/**
* This method should mutate the `parentInstance` and add the child to its list of children. For example, in the DOM this would translate to a `parentInstance.appendChild(child)` call.
*
* This method happens **in the render phase**. It can mutate `parentInstance` and `child`, but it must not modify any other nodes. It's called while the tree is still being built up and not connected to the actual tree on the screen.
*/
react-knova
来说export function appendInitialChild(parentInstance, child) {
// parentInstance 是 Knova的node
parentInstance.add(child);
// parentInstance 绘制,类似于DOM中的操作DOM
updatePicture(parentInstance);
}
finalizeInitialChildren(instance: Instance, type: Type, props, rootContainer, hostContext):boolean
最后操作instance
的阶段。不像 createInstance
,当 finalizeInitialChildren
被调用的时候,所有的子节点被加到了instance
,但还是处于离屏的状态。
这个API设计还有一个目的:当这个节点被挂载到屏幕的时候,你可以判断是否需要处理某些工作。当finalizeInitialChildren
返回true
时,instance
会调用commitMount
。
/**
* In this method, you can perform some final mutations on the `instance`. Unlike with `createInstance`, by the time `finalizeInitialChildren` is called, all the initial children have already been added to the `instance`, but the instance itself has not yet been connected to the tree on the screen.
*
* This method happens **in the render phase**. It can mutate `instance`, but it must not modify any other nodes. It's called while the tree is still being built up and not connected to the actual tree on the screen.
*
* There is a second purpose to this method. It lets you specify whether there is some work that needs to happen when the node is connected to the tree on the screen. If you return `true`, the instance will receive a `commitMount` call later. See its documentation below.
*
* If you don't want to do anything here, you should return `false`.
*/
react-knova
来说// 不处理 `commitMount`
export function finalizeInitialChildren(domElement, type, props) {
return false;
}
prepareUpdate(instance: Instance, tye: Type, oldProps, newProps, rootContainer, hostContext): UpdatePayload
比较oldProps
和 newProps
,返回一组需要update
的对象,这些update
会在commitUpdate
里被应用到。
/**
* React calls this method so that you can compare the previous and the next props, and decide whether you need to update the underlying instance or not. If you don't need to update it, return `null`. If you need to update it, you can return an arbitrary object representing the changes that need to happen. Then in `commitUpdate` you would need to apply those changes to the instance.
*
* This method happens **in the render phase**. It should only *calculate* the update — but not apply it! For example, the DOM renderer returns an array that looks like `[prop1, value1, prop2, value2, ...]` for all props that have actually changed. And only in `commitUpdate` it applies those changes. You should calculate as much as you can in `prepareUpdate` so that `commitUpdate` can be very fast and straightforward.
*
* See the meaning of `rootContainer` and `hostContext` in the `createInstance` documentation.
*/
react-knova
来说export function prepareUpdate(domElement, type, oldProps, newProps) {
return UPDATE_SIGNAL;
}
shouldSetTextContent(type: Type, props: Props): boolean
某些平台支持直接设置节点的属性,比如 node.textContent
。如果返回true
,React
会假设这个节点的子节点都是文本,并不会创建节点。
如果你不想做任何处理,返回 false
/**
* Some target platforms support setting an instance's text content without manually creating a text node. For example, in the DOM, you can set `node.textContent` instead of creating a text node and appending it.
*
* If you return `true` from this method, React will assume that this node's children are text, and will not create nodes for them. It will instead rely on you to have filled that text during `createInstance`. This is a performance optimization. For example, the DOM renderer returns `true` only if `type` is a known text-only parent (like `'textarea'`) or if `props.children` has a `'string'` type. If you return `true`, you will need to implement `resetTextContent` too.
*
* If you don't want to do anything here, you should return `false`.
*
* This method happens **in the render phase**. Do not mutate the tree from it.
*/
react-knova
来说export function shouldSetTextContent(type, props) {
return false;
}
getRootHostContext(rootContainer: Container)
返回初始上下文 the root of the tree
。
/**
* This method lets you return the initial host context from the root of the tree. See `getChildHostContext` for the explanation of host context.
*
* If you don't intend to use host context, you can return `null`.
*
* This method happens **in the render phase**. Do not mutate the tree from it.
*/
react-knova
来说export function getRootHostContext() {
return NO_CONTEXT;
}
getChildHostContext(parentHostContext: HostContext, type: Type, rootContainer: Container): HostContext
Host
上下文会帮助我们记录一些信息,这些信息表示你在这棵树的哪里。比如说:DOM renderer
利用他去基于是在HTML的tree里,还是在SVG的tree里。
/**
* Host context lets you track some information about where you are in the tree so that it's available inside `createInstance` as the `hostContext` parameter. For example, the DOM renderer uses it to track whether it's inside an HTML or an SVG tree, because `createInstance` implementation needs to be different for them.
*
* If the node of this `type` does not influence the context you want to pass down, you can return `parentHostContext`. Alternatively, you can return any custom object representing the information you want to pass down.
*
* If you don't want to do anything here, return `parentHostContext`.
*
* This method happens **in the render phase**. Do not mutate the tree from it.
*/
react-knova
来说export function getChildHostContext() {
return NO_CONTEXT;
}
getPublicInstance(instance: Instance | TextInstance): PublicInstance;
对外二次处理之后的暴露ref
,也可以直接返回这个实例。
/**
* Determines what object gets exposed as a ref. You'll likely want to return the `instance` itself. But in some cases it might make sense to only expose some part of it.
*
* If you don't want to do anything here, return `instance`.
*/
react-knova
来说export function getPublicInstance(instance) {
return instance;
}
prepareForCommit(containerInfo: Container): Record<string, any> | null;
在改变screen节点之前的一些操作。比如说DOM renderer
会保存当前的selection
,之后在重新回显回去。与resetAfterCommit
相反。
/**
* This method lets you store some information before React starts making changes to the tree on the screen. For example, the DOM renderer stores the current text selection so that it can later restore it. This method is mirrored by `resetAfterCommit`.
*
* Even if you don't want to do anything here, you need to return `null` from it.
*/
react-knova
来说export function prepareForCommit() {
return null;
}
resetAfterCommit(containerInfo: Container): void;
/**
* This method is called right after React has performed the tree mutations. You can use it to restore something you've stored in `prepareForCommit` — for example, text selection.
*
* You can leave it empty.
*/
react-knova
来说export function resetAfterCommit() {
// Noop
}
scheduleTimeout
/**
* You can proxy this to `setTimeout` or its equivalent in your environment.
*/
react-knova
来说export const scheduleTimeout = setTimeout;
cancelTimeout(id: TimeoutHandle): void;
/**
* You can proxy this to `clearTimeout` or its equivalent in your environment.
*/
react-knova
来说export const cancelTimeout = clearTimeout;
appendChild?(parentInstance: Instance, child: Instance | TextInstance): void;
类似于DOM
里的parentInstance.appendChild(child)
。在 commit 阶段,但是在这个函数里,你仍然不能操作已经绘制在screen中的节点。如果需要操作,请在commitMount
处理。
/**
* This method should mutate the `parentInstance` and add the child to its list of children. For example, in the DOM this would translate to a `parentInstance.appendChild(child)` call.
*
* Although this method currently runs in the commit phase, you still should not mutate any other nodes in it. If you need to do some additional work when a node is definitely connected to the visible tree, look at `commitMount`.
*/
react-knova
来说export function appendChild(parentInstance, child) {
// step1: 处理节点 已有的 => 设置到最上层; 没有的 => add
if (child.parent === parentInstance) {
child.moveToTop();
} else {
parentInstance.add(child);
}
// 批量绘制
updatePicture(parentInstance);
}
insertBefore?(parentInstance: Instance, child: Instance | TextInstance, beforeChild: Instance | TextInstance | SuspenseInstance): void;
类似于DOM里的parentInstance.insertBefore(child, beforeChild)
.
/**
* This method should mutate the `parentInstance` and place the `child` before `beforeChild` in the list of its children. For example, in the DOM this would translate to a `parentInstance.insertBefore(child, beforeChild)` call.
*
* Note that React uses this method both for insertions and for reordering nodes. Similar to DOM, it is expected that you can call `insertBefore` to reposition an existing child. Do not mutate any other parts of the tree from it.
*/
react-knova
来说export function insertBefore(parentInstance, child, beforeChild) {
// child._remove() will not stop dragging
// but child.remove() will stop it, but we don't need it
// removing will reset zIndexes
child._remove();
parentInstance.add(child);
child.setZIndex(beforeChild.getZIndex());
updatePicture(parentInstance);
}
removeChild?(parentInstance: Instance, child: Instance | TextInstance | SuspenseInstance): void;
类似于DOM的removeChild
。
/**
* This method should mutate the `parentInstance` to remove the `child` from the list of its children.
*
* React will only call it for the top-level node that is being removed. It is expected that garbage collection would take care of the whole subtree. You are not expected to traverse the child tree in it.
*/
react-knova
来说export function removeChild(parentInstance, child) {
child.destroy();
child.off(EVENTS_NAMESPACE);
updatePicture(parentInstance);
}
commitTextUpdate?(textInstance: TextInstance, oldText: string, newText: string): void;
这个方法会更新textInstance
的 textContent
为nextText
/**
* This method should mutate the `textInstance` and update its text content to `nextText`.
*
* Here, `textInstance` is a node created by `createTextInstance`.
*/
react-knova
来说不做处理
commitMount?(instance: Instance, type: Type, props: Props, internalInstanceHandle: OpaqueHandle,): void;
finalizeInitialChildren
返回为true
的时候,才会被调用。在这个阶段,我们可以节点已经绘制到浏览器中去了,我们可以对这些实际的节点做一些事情。比如对于DOM节点来说,是使某个节点autoFocus
一个理想状态的 commitMount
只需要考虑自己。举个不理想的场景的例子: 节点A在其他节点上注册了一些事件,那么在调用removeChild
函数时,就需要主动注销掉他们。(// TODO: 这些应该怎么翻译呢???)
/**
* This method is only called if you returned `true` from `finalizeInitialChildren` for this instance.
*
* It lets you do some additional work after the node is actually attached to the tree on the screen for the first time. For example, the DOM renderer uses it to trigger focus on nodes with the `autoFocus` attribute.
*
* Note that `commitMount` does not mirror `removeChild` one to one because `removeChild` is only called for the top-level removed node. This is why ideally `commitMount` should not mutate any nodes other than the `instance` itself. For example, if it registers some events on some node above, it will be your responsibility to traverse the tree in `removeChild` and clean them up, which is not ideal.
*
* The `internalHandle` data structure is meant to be opaque. If you bend the rules and rely on its internal fields, be aware that it may change significantly between versions. You're taking on additional maintenance risk by reading from it, and giving up all guarantees if you write something to it.
*
* If you never return `true` from `finalizeInitialChildren`, you can leave it empty.
*/
react-knova
来说不做处理
commitUpdate(instance: Instance, updatePayload: UpdatePayload, type: Type, prevProps, nextProps, internalHandle): void
将之前在比较新老props后得到的一组updatePayload
,应用到实例中。
/**
* This method should mutate the `instance` according to the set of changes in `updatePayload`. Here, `updatePayload` is the object that you've returned from `prepareUpdate` and has an arbitrary structure that makes sense for your renderer. For example, the DOM renderer returns an update payload like `[prop1, value1, prop2, value2, ...]` from `prepareUpdate`, and that structure gets passed into `commitUpdate`. Ideally, all the diffing and calculation should happen inside `prepareUpdate` so that `commitUpdate` can be fast and straightforward.
*
* The `internalHandle` data structure is meant to be opaque. If you bend the rules and rely on its internal fields, be aware that it may change significantly between versions. You're taking on additional maintenance risk by reading from it, and giving up all guarantees if you write something to it.
*/
react-knova
来说export function commitUpdate(
instance,
updatePayload,
type,
oldProps,
newProps
) {
// 比较新老属性,应用到instance上。
applyNodeProps(instance, newProps, oldProps);
}
利用ReactFiberReconciler
创建出来指定某个宿主环境下的节点操作机制,指的component-unit
借鉴。component-unit
完全可以做到,分别在PC\H5\Canvas 上传不同的HostConfig
实现不同的fieldType
渲染。
原先对跨域问题的理解,只是停留在面试的基础上。前几天开发的一个关于认证的一个dev-server插件,出现了微服务之间的跨域问题。当对devServer
加上
headers: {
'Access-Control-Allow-Origin': '*',
},
时,就开启的跨域支持。
那么问题来了:为什么加上Access-Control-Allow-Origin
头,浏览器就支持了呢?
通过charles抓包,就能发现,当不加Access-Control-Allow-Origin
头,其实后端是正常返回的:
只是到了浏览器这一层面,会检查请求是否和origin同源,如果不同源的话,浏览器层面拦截。
那么如何让浏览器知道,我这个请求是安全的呢?这就需要后端在response的header里面加上Access-Control-Allow-Origin
头,告诉浏览器,我这个请求麻烦请通过一下。
这样,浏览器拿到这个header之后,自然就会放过这个请求。
业务代码开发过程中,经常需要设置set-cookie,302,等这些header信息。但是集成在@nestjs/graphql中,我们抛出的error,形成在了graphql的response body中。没办法报http error code。 基于这些原因,本人稍微往里看了看,总计如下:
nestjs背后,默认运行的是一个express服务。业务实现中,会首先创建一个app: NestFactory.create(AppModel),那么在AppModel中,我们会把ApolloServer植入进nestjs中。
实际上,在代码中,@nestjs/graphql将apollo-server-express已第三方中间件的方式,注入到了nestjs中。
fb34fba1770b87debffa25cc084712fa.png
apollo-server-express中的graphqlExpress将核心的工作交给了apollo-server-core中的runHttpQuery处理,并收尾runHttpQuery一些工作:
将runHttpQuery返回的responseInit设置response headers。
将runHttpQuery返回graphqlResponse直接res.send出去。(阶段了后续的中间件工作)。
具体代码,请看代码
runHttpQuery的主要工作是处理request中的请求,执行graphql代码,并返回response给中间层。
apollo-server-express会给每个请求生成一个上下文(requestContext),用来共享数据。
{
logger: options.logger || console,
schema: options.schema,
schemaHash: options.schemaHash,
request,
response: {
http: {
headers: new Headers(),
},
},
context,
cache: options.cache,
debug: options.debug,
metrics: {},
}
然后进入这个request生命周期,处理生命周期以及执行请求。apollo-server-express起了一个有趣的名字:requestPipline
requestPipline会走过request自己的生命周期。最后将response挂在requestContext上。
返回的response是Graphql的response结构:
export interface GraphQLResponse {
data?: Record<string, any> | null;
errors?: ReadonlyArray<GraphQLFormattedError>;
extensions?: Record<string, any>;
http?: Pick<Response, 'headers'> & Partial<Pick<Mutable<Response>, 'status'>>;
}
其中的http,代表的response的返回头部,最终会被赋值给express的res。代码。
在代码中看见最多的是dispatcher.invokeHookAsync调用生命周期hook。dispatcher是一个订阅发布实现的调度器。代码。在初始化的时候,会拿到apollo-server中的plugins,这些plugins其实是一堆listeners。然后在执行流程中触发即可。
定义一个plugin,处理http头部:
{
requestDidStart(requestContext) {
return {
willSendResponse(requestContext) {
const { data } = requestContext.response;
const host = requestContext.request.http.headers.get('host');
if (data?.login?.token) {
requestContext.response.http.headers.set(
'Set-Cookie', '_t=' + data?.login?.token
+ '; Domain=' + domain + '; Path=/;'
);
}
if (data?.operation) {
requestContext.response.http.status = 302;
}
};
}
}
@storybook/preset-create-react-app
中,getScriptsPath
会在require.resolve('react-scripts')
失败。导致react-scripts
相关的webpack config
应用不到项目中。
原因,来自于@storybook/preset-create-react-app
的bug。react-scripts
中的package.json
没有定义相关的入口文件,导致require.resolve('react-scripts')
失败。以下是相关的临时解决方案:
const rewiredPath = require.resolve('@storybook/preset-create-react-app/dist/helpers/getReactScriptsPath');
const rewired = require(rewiredPath);
require.cache[rewiredPath].exports = {
getReactScriptsPathWithYarnPnp: rewired.getReactScriptsPathWithYarnPnp,
getReactScriptsPath: () => {
const path = require.resolve('react-scripts/package.json');
return path;
},
};
const presets = require('@storybook/preset-create-react-app');
exports = {
...presets
};
最近在做一个项目是,将微信小程序迁移到企业微信小程序中。但是遇到了一些问题:
解决的方案有很多种,其中最简单粗暴的是,在每个调用wx.api的地方做一个判断:
// wx.login({}) => isQyWx ? wx.qy.login : wx.login
显然这个是改动量最大的。
感谢ES6 proxy。我们将所有调用wx的地方,采用调用wx代理的方式解决问题:
// 小程序启动文件
const isWxEnv = wx.getSystemInfoSync()?.environment === 'wxwork';
(function () {
wx = new Proxy(wx, {
get(target, propKey, recevier) {
if (isWxEnv && propKey === 'login') {
return wx.qy.login;
}
return target[propKey];
}
})
})();
同样,在wx.request上做代理。做以下来个步骤:
const wxRequestProxy = async (fn, {url, method, data, ...params}: any) => {
let baseUrl = ''
// step1: 远程获取baseUrl,并设置缓存
if (!url.startsWith('http')) {
baseUrl = await getBaseUrl();
}
// 调用wx.request。 这里不能直接调用。
// 如果只写调用wx.request,这是的wx则为代理,会出现死循环
return fn.call(this, {
...params,
method,
data: method === 'GET' ? null : data,
url: method === 'GET' ? qs.stringifyUrl({url: baseUrl + url, query: data}) : (baseUrl + url)
});
};
(function () {
wx = new Proxy(wx, {
get(target, propKey, recevier) {
if (isWxEnv && propKey === 'login') {
return wx.qy.login;
}
if (propKey === 'request') {
return (params) => wxRequestProxy.call(this, target[propKey], params);
}
return target[propKey];
}
})
})();
平时写业务代码写太多了,很少会用到Proxy,Reflect。总算碰到了一个。记录下来。
export const INIT_FORM = gql`
query initFormFieldsAndValue($request1: ListFieldsByObjIdReq, $request2: ReqIdWithForm, $requestInitValue: Boolean!) {
getFormValueById (request: $request2) @include(if: $requestInitValue) {
id
obj_type
obj_id
form_id
vars
}
listFieldsByObjId(request: $request1) {
items {
field_id
setting {
id
name
key
field_type
filter_order
enum_value {
value: key
text: value
}
enum_map
display_type
enum_items{
key
value
desc
en_value
en_desc
meta{
color
}
}
config
}
}
}
}
`;
局限性: @include 后面的参数只能是boolean
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.