Автор этой статьи: Бао Гуанься
задний план
С быстрым развитием экосистемы React решения по управлению состоянием сообщества на основе React появляются бесконечным потоком, а это означает, что многим разработчикам решений все еще приходится делать большой выбор, нет согласованной команды, стоимость коммуникации и перекрестных - сотрудничество в команде и долгосрочное обслуживание очень высоки. В настоящее время особенно важно унифицировать набор моделей разработки.
В этой статье будет рассказано, как с нуля создать многоразовый фоновый фреймворк, чтобы каждый мог легко создать свой собственный фон и глубоко понять свой собственный фреймворк.
Практическое знакомство с фреймворком проекта дает много преимуществ:
1. Сильная бизнес-настраиваемость (например, у вашей команды есть набор библиотек компонентов пользовательского интерфейса с сильной бизнес-настройкой; у вашей команды есть собственный набор передовых методов управления состоянием; у вашей команды есть набор сложных процессов управления разрешениями и т. д.)
PS: Конечно, вы можете найти сторонний фреймворк, чтобы превратить его в то, что вам нужно, но стоимость запуска, последующего обслуживания и обновления технологий будет очень высокой.
2. Конвергентные технологические стеки, скрытие основных различий и унификация опыта разработки, помогающие командам снизить затраты на разработку и обслуживание.
3. Станьте контроллером фреймворка, обновите технологию и трансформируйте нижний слой по своему усмотрению.
написать впереди
В этой статье описывается основная технология и процесс создания среды фоновой разработки React с нуля. Используемая технология не является единственным необязательным стеком технологий. Вы можете заменить ее на стек технологий, с которым вы знакомы, в любое время. В то же время я постараюсь уменьшить сложность чтения этой статьи и снизить порог фронтенд-разработки, но некоторые знания, которыми необходимо обладать, все же есть:
- React Hooks
- React-Redux
- React Router 5.0
- Ant Design 4.x
Этот проект в основном строит структуру скелета системы управления уровня предприятия, предоставляет общие функции и требования к расширению, не требует разработки бизнес-логики, не требует запросов данных, и все данные являются фиктивными.
начать строить
Инфраструктура и конфигурация
1. Создайте основной каталог и структуру проекта
Приложение Create React рекомендуется для создания базовой структуры проекта. В Интернете есть много связанных процессов инициализации, которые не будут повторяться здесь. Официальный учебник находится по адресуздесь.
Create React App — это инструмент создания шаблонов, официально запущенный React для создания одностраничных приложений React. Он интегрирует сам Webpack и настраивает ряд встроенных загрузчиков и базовых сценариев npm, которые позволяют легко достичь нулевой конфигурации и быстро разрабатывать приложения React.
Структура каталогов проекта по умолчанию выглядит следующим образом:
├── package.json
├── public # 静态目录
│ ├── favicon.ico
│ ├── index.html # 最终的html的基础模板【默认是单页面应】
│ └── manifest.json
├── src
│ ├── App.css # App根组件的css
│ ├── App.js # App组件代码
│ ├── App.test.js
│ ├── index.css # 启动文件样式
│ ├── index.js # 启动的文件(执行入口)
│ ├── logo.svg
│ └── serviceWorker.js
└── yarn.lock
2. Выполните команду
npm start
# or
yarn start
Открытьhttp://localhost:3000Посмотрите это в своем браузере.
Пока что простой проект React стал.
Расширенный проект
React Router
Почему стоит выбрать динамическую маршрутизацию
Большинство людей привыкли к методу разработки конфигурации маршрутизации, включая Angular, Express, Ember и т. д., включая инфраструктуру Ant Design Pro и Umi, которые представляют собой конфигурацию статической маршрутизации. React Router V4 также использовал этот метод раньше, но в React Router V4 был выполнен рефакторинг с прямой несовместимостью. Итак, каковы болевые точки маршрутизации конфигурации React Router V3? Зачем делать его динамичным?
Я понимаю, что болевые точки этого React Router V3 следующие:
Для удобства ознакомления React Router V3 далее именуется как V3, React Router V4 далее именуется как V4;
- V3 отходит от идеи компонентизации React. Хоть V3 и является компонентом React по форме, он не имеет ничего общего с UI, а лишь предоставляет элемент конфигурации.
Это можно проследить из соответствующего исходного кода
const Route = createReactClass({
// 无关代码
/* istanbul ignore next: sanity check */
render() {
invariant(
false,
'<Route> elements are for router configuration only and should not be rendered'
)
}
});
В методе рендеринга Route он не выполняет никакой работы, связанной с рендерингом пользовательского интерфейса, и не является аутентичным компонентом.
- Метод написания маршрута V3 должен соответствовать согласованному формату, например, Route нельзя использовать без Router, что противоречит концепции «сборки компонентов с декларативной гибкостью», отстаиваемой React.
- Версия 3 предоставляет множество методов, похожих на жизненный цикл, например: onEnter, onUpdate, onLeave и т. д., чтобы обеспечить методы-ловушки для маршрутов на разных этапах. Но сам React имеет хорошо зарекомендовавший себя подход к жизненному циклу. Проблема с методом маршрутизации V3 заключается в том, что он разрабатывает независимый API за пределами идеи компонента React, что является навязчивым.
- Централизованная маршрутизация вложена слой за слоем.В конфигурации необходимо позаботиться об уровне предков, к которому принадлежит маршрутизация.Отображение страницы определяется маршрутизацией верхнего уровня, которая не может отражать гибкость динамической маршрутизации.
Конечно, версия V4 решила эти проблемы. В версии V4 от традиционной концепции маршрутизации отказываются, и Route возвращается к компонентизации.
V4 начал принимать структуру модели склада с одним кодом, каждый склад отвечает за разные функциональные сценарии, и они независимы друг от друга.
- Базовая библиотека маршрутизации react-router
- Оболочка react-router-dom, используемая в браузерах
- React-router-native Собственный пакет React
В этой статье нам нужно использовать только репозиторий react-router-dom.Если вы не понимаете почему, см.здесь;
Вам необходимо освоить следующие компоненты react-router-dom:
- BrowserRouter
- Route
- Switch
- Link
Вам нужно освоить объекты react-router-dom и их методы:
- history
- location
- match
Начиная с версии 4.0, React Router полностью удалил централизованную настройку, больше не поддерживает централизованную маршрутизацию и позволил React вернуться к разработке компонентов, которые сами по себе являются лишь компонентом, обеспечивающим функции навигации. Здесь мы проектируем маршрут по рекомендованной динамической идее, для входа разработано только меню первого уровня, а бизнес управляет своими подмаршрутами.
Из-за нехватки места здесь указан только случай вторичной маршрутизации, то же самое верно и для многоуровневой маршрутизации.
1. Установите зависимости
npm install --save react-router-dom
cd src
touch router.js // 构造我们的一级路由
2. Построить директорию src (можно гибко настраивать), надеюсь будет вот так
.
├── src
│ ├── index.js // 入口文件
│ ├── pages
│ │ ├── demo1 // 一级菜单A
│ │ │ ├── index.js
│ │ │ ├── page1 // A下面的二级页面a
│ │ │ │ └── index.js
│ │ │ └── page2 // A下面的二级页面b
│ │ │ └── index.js
│ │ └── demo2 // 一级菜单B
│ │ ├── index.js
│ │ ├── page1 // B下面的二级页面a
│ │ │ └── index.js
│ │ └── page2 // B下面的二级页面b
│ │ └── index.js
│ └── router.js
3. Построить маршрут первого уровня
router.js
import { Switch, Route } from 'react-router-dom';
// 一级菜单
import demo1 from './pages/demo1';
import demo2 from './pages/demo2';
const router = (
<Route render={() => {
return (
<Switch>
<Route path="/demo1" component={demo1}></Route>
<Route path="/demo2" component={demo2}></Route>
</Switch>
)
}}></Route>
);
4. Пусть маршрутизация первого уровня управляет маршрутизацией второго уровня.
pages/demo1/index.js (аналогично страницам того же уровня)
import { Switch, Route } from 'react-router-dom';
import page1 from './page1';
import page2 from './page2';
const Router = ({ match }) => (
<Switch>
<Route path={`${match.path}`} exact component={page1} />
<Route path={`${match.path}/page1`} component={page1} />
<Route path={`${match.path}/page2`} component={page2} />
</Switch>
);
Switch содержит Route и отображает только первый соответствующий маршрут. Поэтому к основному совпадению маршрута добавляется точное соответствие, и последующие совпадения не будут заблокированы.
5. Файл входа добавляется в маршрут
src/index.js
import React from 'react';
import ReactDom from 'react-dom';
import { BrowserRouter as Router } from 'react-router-dom';
import routeChildren from './router';
ReactDom.render(
<Router>
{routeChildren}
</Router>,
document.getElementById('app')
);
Здесь мы используем компонент BrowserRouter. Откройте файл BrowserRouter, и вы увидите, что он объявляет объект истории свойства экземпляра. Объект истории создается из метода createBrowserHistory пакета истории.
import { createBrowserHistory as createHistory } from "history";
class BrowserRouter extends React.Component {
history = createHistory(this.props);
render() {
return <Router history={this.history} children={this.props.children} />;
}
}
У объекта истории есть много свойств и методов, которые в дальнейшем принесут нам большое удобство.Если вы хотите узнать больше о доступе к истории, см.здесь.
6. Измените нашу бизнес-страницу
pages/demo1/page1/index.js (аналогично страницам того же уровня)
import React from 'react';
const Page1 = history => {
return (
<div>demo2 page1</div>
);
};
export default Page1;
На этом наша схема маршрутизации завершена.
Теперь запустите npm run start, чтобы увидеть~
Базовая настройка маршрутизации проекта завершена.
Управление меню конфигурации
В бэкэнд-проектах маршрутизация и меню являются ключевыми скелетами, организующими приложение. После проектирования маршрута рассмотрим управление навигационным меню.
На этом этапе мы начинаем создавать основные возможности платформы: конфигурация меню, интеграция пользовательского интерфейса, управление состоянием, вход пользователя в систему и аутентификация маршрутизации.
Навигация должна быть интегрирована в структуру макета и отделена от бизнес-логики.Чтобы предотвратить привязку меню разработчика к бизнес-логике, здесь используется управление меню конфигурации, и разработчику нужно заботиться только о конфигурации меню.
Для простоты понимания библиотека компонентов пользовательского интерфейса использует Ant Design.
1. Конфигурация меню и интеграция пользовательского интерфейса
Поскольку мы планируем сделать меню конфигурации, мы разрабатываем конфигурацию меню и генерируем меню в соответствии с конфигурацией.
cd src
touch menuConfig.js
menuConfig.js
const menu = [
{
path: 'demo1',
name: '一级菜单A',
children: [{
name: 'subnav1',
path: 'page1'
},
{
name: 'subnav2',
path: 'page2'
}]
},
{
path: 'demo2',
name: '一级菜单B'
children: [{
name: '测试',
path: 'page2'
}]
}
];
Конечно, вы можете добавить в конфигурацию любой элемент, чтобы обогатить вашу конфигурацию, например, иконку, перенаправление и т. д.;
2. Создайте конфигурацию меню
Далее нам нужно построить нашу навигацию в соответствии с этой конфигурацией и посмотреть, какие данные требуются компоненту «Меню», предоставляемому Ant Design? Официальная демо-версия:
<Menu
theme="dark"
mode="inline"
defaultSelectedKeys={['2']}>
<Menu.Item key="1">nav1</Menu.Item>
<Menu.Item key="2">nav2</Menu.Item>
</Menu>
Чтобы наша конфигурация легко генерировала компонент меню, нам нужно написать метод для преобразования нашего меню в мозаичную форму. Используя путь в качестве ключа, вы можете легко проанализировать selectKey.
Мы хотим, чтобы наше меню выбиралось или переключалось по пути, нам нужно построить такую структуру согласно MenuConfig:
{
"selectMainMenu": { // 当前访问一级菜单信息【用于标记一级菜单选中】
"path": "demo1",
"name": "一级菜单A"
},
"mainMenu": [ // 当前所有一级菜单信息【用于渲染一级导航】
{
"path": "demo1",
"name": "一级菜单A"
},
{
"path": "demo2",
"name": "一级菜单B"
}
],
"subMenu": [ // 当前一级菜单下的所有子菜单【用于渲染子导航】
{
"name": "subnav1",
"path": "page1",
{
"name": "subnav2",
"path": "page2"
}
],
"paths": [
{
"name": "一级菜单A",
"path": "/demo1"
}
],
"prePath": "/demo1" // 一级路由+二级路由作为子菜单唯一 key【标识二级菜单状态】
}
Сгенерированный компонент HeadMenu:
<Menu theme="dark"
mode="horizontal"
selectedKeys={[selectMainMenu.path]} >
{
mainMenu.map(item => {
<Menu.Item key={item.path}>
<Link to={item.path === '/' ? '/' : `/${item.path}`}>{item.name}</Link>
</Menu.Item>
})
}
</Menu>
Сгенерированный компонент SideMenu:
<Menu theme="dark"
mode="horizontal"
selectedKeys={[currentPath]} >
{
subMenu.map(item => {
<Menu.Item key={`${prePath}/${item.path}`}>
<Link to={item.path === '/' ? '/' : `${prePath}/${item.path}`}>
<span>{item.name}</span>
</Link>
</Menu.Item>
})
}
</Menu>
Этот шаг преобразования не сложен и может быть реализован сам по себе. В основном это обеспечивает идею маркировки состояния меню в соответствии с путем маршрутизации.
3. Компоновка интегрированного компонента меню
const BaseLayout = ({ location, children }) => {
const { pathname } = location;
const [menuInfo, setMenuInfo] = useState({});
// 菜单信息随着路径变化
useEffect(() => {
const newInfo = pathChange(pathname, menuConfig);
setMenuInfo(newInfo);
}, [pathname]);
return (
<Layout>
<Header className="header" >
<div className="logo" />
<HeadMenu menuInfo={menuInfo}></HeadMenu>
</Header>
<Content>
<Layout>
<Sider width={200}>
<SideMenu menuInfo={menuInfo}></SideMenu>
</Sider>
<Content>{children}</Content>
</Layout>
</Content>
</Layout>
)
}
4. Применить макет ко всем маршрутам
Измените нашу запись маршрутизации (плюс структуру макета макета):
import React from 'react';
import { Switch, Route } from 'react-router-dom';
import BaseLayout from './layouts';
// 各个一级路由
import demo1 from './pages/demo1';
import demo2 from './pages/demo2';
const router = (
<Route render={(props) => {
return (
<BaseLayout {...props}>
<Switch>
<Route path="/demo1" component={demo1}></Route>
<Route path="/demo2" component={demo2}></Route>
</Switch>
</BaseLayout>
)
}}></Route>
);
export default router;
Меню нашего профиля готово, выглядит оно так:
аутентификация маршрута
Самая большая разница между проектом toB и toC заключается в контроле разрешений, который является едва ли не самой сложной частью фоновой интеграции фреймворка.
В крупномасштабной системе последствия неправильной работы могут быть очень серьезными, и управление полномочиями является неотъемлемым звеном.
Наличие системы разрешений в наибольшей степени позволяет избежать таких проблем — пока функции появляются в интерфейсе, ими можно управлять или они не имеют серьезных последствий. После входа в систему каждая учетная запись может видеть только информацию, относящуюся к ней самой, и может быстрее понять бизнес в рамках своей работы.
Базовый состав фоновых разрешений
Дизайн разрешений в основном состоит из трех элементов: учетная запись, роль, разрешение.
- 帐号:登录系统的唯一身份识别,一个账号代表一个用户;
- 角色:为账号批量分配权限。在一个系统中,不可能为每个帐号订制权限,所以给同一类帐号赋予一个“角色”,以达到批量分配权限的目的;
- 权限:对于前端来说,权限又分为页面权限和操作权限;其中页面权限分为菜单权限和路由权限;
Основная идея дизайна заключается в следующем:
1. Реализация входа
login.js
import { connect } from 'react-redux';
const Login = ({
loginStatus,
location,
setLoginInfo,
history
}) => {
let { redirectUrl = '/' } = location.state || {};
// 获取登录信息伪代码
const onFinish = values => {
/**** 此处去获取登录信息并存放在全局 Store ****/
setLoginInfo({
username: '小A',
role: 1
});
history.push(redirectUrl);
};
return (
<div className="login layer">
<Form
name="basic"
onFinish={onFinish} >
<Form.Item
label="用户名"
name="username"
rules={[{ required: true, message: '输入用户名' }]} >
<Input />
</Form.Item>
<Form.Item
label="密码"
name="password"
rules={[{ required: true, message: '输入密码' }]} >
<Input.Password />
</Form.Item>
<Form.Item>
<Button type="primary" htmlType="submit">登陆</Button>
</Form.Item>
</Form>
</div>
);
};
const mapStateToProps = state => ({
loginStatus: state.login.loginStatus
});
const mapDispatchToProps = dispatch => ({
setLoginInfo: (...args) => dispatch(setLoginInfo(...args))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(Login);
Роль connect() заключается в соединении Store и Component. connect отвечает за считывание некоторых данных из дерева состояний Redux и предоставление этих данных компоненту для рендеринга через реквизиты. Также передайте функцию действия в реквизит.
Функция подключения получает два параметра: один mapStateToProps, который преобразует состояние Redux в реквизиты компонента, другой параметр — mapDispatchToprops,
Преобразуйте метод, который генерирует действия, в функцию свойства реквизита.
2. Управление статусом пользователя
store/login.js магазин
// 设置state初始值
const initState = {
loginStatus: false,
userInfo: {
username: '',
role: -1 // 用户权限标识
}
};
const SET_LOGIN = 'SET_LOGIN';
// action
export const setLoginInfo = (payload) => {
return {
payload,
type: SET_LOGIN
};
};
// reducer
export const loginReducer = (state = initState, action) => {
switch (action.type) {
case SET_LOGIN:
return {
...state,
loginStatus: true,
userInfo: action.payload
};
default:
return state;
}
};
store/index.js
import { createStore, combineReducers } from 'redux';
import { loginReducer } from './login';
const allReducers = {
login: loginReducer
};
const reducers = combineReducers(allReducers);
const store = createStore(reducers);
export default store;
Запись index.js добавляет поставщика для распространения Store
import React from 'react';
import ReactDom from 'react-dom';
import { BrowserRouter as Router } from 'react-router-dom';
import { Provider } from 'react-redux';
import store from './redux';
import routeChildren from './router';
ReactDom.render(
<Provider store={store}>
<Router>
{routeChildren}
</Router>
</Provider>,
document.getElementById('app')
);
Роль провайдера состоит в том, чтобы сделать Магазин доступным для всего Приложения.
3. Проверка входа
Нам необходимо проверить статус входа пользователя перед доступом ко всем страницам, чтобы избежать повторных входов в систему; Наш макет управляет всеми записями страниц и нуждается в изменении layout.js
layout.js добавляет следующую логику:
const loginPath = '/login';
const { pathname } = location;
const redirectUrl = pathname === loginPath ? '/' : pathname;
useEffect(() => {
<!--校验是否登陆-->
if (loginStatus) {
history.push(redirectUrl);
} else {
history.push('/login', {
redirectUrl
});
}
}, []);
if (pathname === '/login') {
return <div>{children}</div>;
}
На этом шаге вам нужно взять текущую страницу как redirectUrl на страницу входа и вернуться к исходному пути после входа в систему.
Чтобы увидеть демонстрационный эффект, нам нужно немного изменить наш стиль, и эффект стиля добавится сам по себе.
3. Аутентификация пользователя
Аутентификация серверной системы — сложная и очень разносторонняя тема.Эта статья является лишь руководством.Чтобы облегчить понимание идей, представлена только простая схема авторизации.
Мы установили, что чем меньше идентификатор разрешения, тем выше разрешение, и связь между уровнями является инклюзивной.
Идея построения разрешений заключается в следующем:
Согласно этой схеме разрешений, menuConfig.js необходимо добавить идентификатор разрешения:
const menu = [
{
path: 'demo1',
name: '一级菜单A',
role: [4], // demo1 权限标识
children: [{
name: 'subnav1',
path: 'page1',
role: [2] // demo1/page1 权限标识
},
{
name: 'subnav2',
path: 'page2',
role: [2] // demo1/page2 权限标识
},
{
name: 'subnav3',
path: 'page3',
role: [3] // demo1/page3 权限标识
},
{
name: 'subnav4',
path: 'page4',
role: [4] // demo1/page4 权限标识
}]
},
{
path: 'demo2',
name: '一级菜单B',
role: [4], // demo2 权限标识
children: [{
name: '测试',
path: 'page2',
role: [3] // demo1/page2 权限标识
}]
}
];
Layout.js добавляет перехват аутентификации, а остальная логика остается неизменной:
let authChildren = children;
const { role = -1 } = userInfo;
const [menuInfo, setMenuInfo] = useState({});
// 用户角色配置,预留
const filterMenu = menus => menus
.filter(item => (role !== -1 && item.role >= role))
.map((item) => {
if (item.children && item.children.length > 0) {
return { ...item, children: filterMenu(item.children) };
}
return item;
});
useEffect(() => {
// 过滤菜单权限
const newMenuInfo = filterMenu(menuConfig);
const curMenuInfo = onPathChange(pathname, newMenuInfo);
setMenuInfo(curMenuInfo);
}, [pathname]);
// 过滤路由权限
const curPathAuth = menuInfo.paths
? menuInfo.paths.find(item => item.path === pathname) : {};
// 路由权限拦截
if (JSON.stringify(curPathAuth) === '{}') {
authChildren = (
<div className="n-privileges">
<p>对不起你没有访问该页面的权限</p>
</div>
);
}
Чтобы продемонстрировать эффект разрешения, мы увеличиваем переключатель разрешения пользователя.
Каркасная структура в основном сформирована.
следовать за
Конечно, система нуждается в доработке более детально, и мы завершили только основной процесс.
Когда совместная система с несколькими людьми переходит на более позднюю стадию, нам необходимо учитывать проблемы с производительностью, междоменную конфигурацию, имитации данных, eslint и т. д. Контент, который не является частью основного процесса, обсуждается только здесь.
1. Загрузка по запросу
Рендеринг одностраничных приложений в верхней части страницы всегда был большой проблемой. Чтобы оптимизировать загрузку ресурсов, мы можем обратиться к новым функциям Suspense и lazy в React 16.3.0.
React.lazy предоставляет метод для загрузки компонентов по требованию, и синтаксис import() должен использоваться для импорта компонентов внутри метода в сочетании с функцией веб-пакета: когда встречается синтаксис import...from, зависимые пакеты будут быть объединены в bundle.js. Это можно сделать следующим образом:
const page1 = React.lazy(() => import(/* webpackChunkName: "page1" */'./page1'));
Вы можете упаковать page1 в файл с именем page1.js.
С помощью React.Suspense можно легко реализовать анимацию перехода с ленивой загрузкой.
2. Общее не найдено
Наш дизайн маршрутизации упрощает обработку ситуаций Not Found.
Добавьте path="*" в конце каждого уровня Switch, чтобы заблокировать все несопоставленные маршруты.
<Switch>
<Route path={`${match.path}`} exact component={Home} />
<Route path={`${match.path}/page1`} component={page1} />
<Route path={`${match.path}/page2`} component={page2} />
<Route path="*" component={NotFound} />
</Switch>
3. Междоменная конфигурация
Когда мы разрабатываем локально как сервисный прокси, мы обычно выбираем прокси на dev_server.
devServer: {
proxy: {
'/api': {
target: 'http://www.baidu.com/',
changeOrigin: true,
secure: false,
},
'/api2': {
.....
}
}
}
Однако этот метод недействителен в приложении, сгенерированном create-react-app. В этом случае, когда версия create-react-app ниже 2.0, вы можете добавить конфигурацию прокси в package.json. Конфигурация выглядит следующим образом :
"proxy": {
'/api': {
target: 'http://www.baidu.com/',
changeOrigin: true,
secure: false,
},
}
Если версия create-react-app выше версии 2.0, в package.json можно настроить только строковый тип, вместо этого вы можете рассмотреть возможность использования http-proxy-middleware.
src/setupProxy.js
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use(
'/api',
createProxyMiddleware({
target: 'http://localhost:5000',
changeOrigin: true,
})
);
};
Конечно, вы также можете выполнить команду npm run eject, чтобы открыть веб-пакет и другие конфигурации для изменения файла devServer.
4. Возможность имитации данных
При разработке проектов фронтенд-инженерам необходимо полагаться на интерфейс данных бэкэнд-инженеров и внутреннюю среду совместной отладки. Но на самом деле мы можем также имитировать данные для отладки в соответствии с документацией по внутреннему интерфейсу до того, как разработка интерфейса будет завершена, чтобы потребитель интерфейса мог развиваться независимо от производителя интерфейса.
Общие решения для имитации данных:
- Жестко запрограммировано на уровне кода
- Перехват во внешнем JS
- Прокси-программа (Fiddler, Charles)
- mock server
Эти решения либо нарушают код, либо данные невозможно отследить, либо их стоимость высока.
Cloud Music открыла фиктивную платформу с открытым исходным кодом, которая может помочь разработчикам управлять интерфейсами. Добро пожаловать в яму:NEI
Эта статья основана только на личном опыте. Если у вас есть какие-либо замечания и предложения по этой статье, вы можете обсудить их.
Эта статья была опубликована сКоманда внешнего интерфейса NetEase Cloud Music, Любое несанкционированное воспроизведение статьи запрещено. Мы всегда нанимаем, если вы готовы сменить работу и вам нравится облачная музыка, тоПрисоединяйтесь к нам!