Адрес переднего склада проекта:GitHub.com/Nick930826/…
Адрес склада серверов проектов:GitHub.com/Nick930826/…
1. Базовое введение в Egg.js
1. Объяснение построения среды разработки Egg.js и создания каталога проекта
2. Разберитесь с механизмом маршрутизации Egg.js
3. Напишите простые интерфейсы GET и POST
4. Как использовать шаблоны внешнего интерфейса в Egg.js
2. Интерфейс журнала React
1. Создайте среду разработки React и получите доступ к Ant Design Mobile.
2. Адаптировать решение мобильного терминала через vw
3. Разработка страницы списка дневника
4. Разработка страницы подробностей дневника
5. Разработка страницы редактирования дневника
3. Разработка сервера Egg.js
1. Установите базу данных Mysql локально
2. Navicat использует базу данных для создания журнальной таблицы.
3. Написать добавить интерфейс журнала, обновить интерфейс журнала
4. Напишите интерфейс для получения списка дневника, интерфейс для получения деталей дневника и интерфейс для удаления дневника.
5. Совместный интерфейс отладки
4. Резюме
Начало работы с основами Egg.js
Введение
Что такое Egg.js? яйца? Просто шучу. Egg.js — это архитектура верхнего уровня, основанная на Koa.Проще говоря, Egg.js — это решение для внутреннего узла, основанное на вторичной разработке Koa. На данный момент (2020-01-06) последняя версия Eggv2.26.0
,GithubЗвезды на нем остаются высокими, и в настоящее время он достиг 14,6 тыс.+. Видно, как сильно все любят Яйцо.
Так почему же я выбрал Egg в качестве фреймворка для серверной разработки, а не Nest, Think.js, hapi и другие фреймворки? Во-первых, Egg разработан командой Ali и является ведущим отечественным производителем. Вам не нужно беспокоиться об экологии этого фреймворка, не говоря уже о том, что он будет остановлен на техническое обслуживание, потому что многие внутренние системы в Alibaba также сделаны с использованием этого фреймворка. Во-вторых, Egg проделал хорошую работу с документацией.Китайские и английские документы очень дружелюбны к китайцам.Честно говоря, мои знания английского языка ограничены.Хотя чтение английских документов не является большой проблемой, все же кажется немного сложным . Когда вы сталкиваетесь с проблемами, вы также можете обратиться в сообщество или техническую группу, чтобы сказать несколько слов, и друзья, столкнувшиеся с подобными проблемами, не пожалеют усилий, чтобы поддержать вас. (Обычные мелкие разработчики не любят распыляться слегка)
Есть еще очень важная причина, Egg наследует Koa, и в его базовую модель внесены некоторые усовершенствования, которые, можно сказать, очень удобны в написании. Напротив, Koa по-прежнему базовый, и слишком много вещей нуждаются во вторичной упаковке. Вы увидите силу яйца в более позднем развитии.
Создание среды разработки Egg.js и объяснение генерации каталога проекта
моя среда:
- Операционная система: macOS
- версия узла: 12.6.0
- версия нпм: 6.9.0
Инициализируйте проект следующим скриптом:
mkdir egg-demo && cd egg-demo
npm init egg
// 选择 simple 模式的
npm install
Рекомендуется установить пряжу, если npm недоступен.
Инициализируйте каталог проекта следующим образом:
Анализ файловой структуры проекта
Здесь я выбираю важные, потому что мы не часто модифицируем их в каком-то развитии, поэтому нам не нужно тратить слишком много сил, чтобы понять.Конечно, заинтересованные друзья могут изучить более тщательно.
- **папка приложения: **Наша основная логика почти вся завершена в этой папке.Контроллер - это папка контроллера, которая в основном записывает некоторые бизнес-коды.После этого в папке приложения будет создана новая сервисная папка, которая специально используется для работы с базой данных, бизнес-логики «разделяй и властвуй» и операций с базой данных, и код будет намного понятнее.
- **Общая папка: **Общая папка, поместите некоторые общедоступные ресурсы в эту папку.
- папка конфигурации:Здесь хранятся некоторые конфигурации проекта, такие как междоменная конфигурация, конфигурация базы данных и так далее.
- папка журналов:Папку журнала не нужно изменять или просматривать в обычных условиях.
- **Папка запуска: **При запуске проекта сгенерированный файл конфигурации в основном не изменяет файлы внутри.
- тестовая папка:Некоторые файлы конфигурации, используемые в тесте, будут использоваться при тестировании интерфейса.
- .auto.conf.js:Файлы, автоматически созданные проектом, как правило, не требуют модификации.
- .eslintignore и .eslintrc:Файл конфигурации форматирования кода.
- .gitignore:Файлы, которые следует игнорировать при фиксации git.
- пакет.json:Файлы управления пакетами и файлы конфигурации команд необходимо часто изменять во время разработки.
Спецификация соглашения каталога Egg.js
Причина, по которой Koa не подходит для разработки командных проектов, заключается в отсутствии спецификации. Egg.js разработал некоторые спецификации на основе Koa, поэтому, когда мы размещаем некоторые файлы сценариев, мы должны следовать спецификациям Egg.js.
app/router.js
где находится маршрутизация
public
Папки для размещения некоторых общедоступных ресурсов, таких как изображения, общедоступные скрипты и т. д.
app/service
Папка для размещения содержимого операций базы данных
view
Папки — это, естественно, место для размещения интерфейсных шаблонов.
middleware
Это место, где размещается промежуточное программное обеспечение. Это очень важно. Такие операции, как аутентификация, могут быть добавлены к маршрутизации в виде промежуточного программного обеспечения, широко известного как защита маршрутизации.
Есть много спецификаций, которые я не буду здесь перечислять, вы можете двигаться дальше.официальная документация, китайский документ очень удобен, и студенты, которые хотят изучить его глубже, могут читать его ночью.
Сказав так много, я, кажется, забыл одну вещь, давайте запустим проект и посмотрим. Перед началом немного модифицируем контент:
// /app/controller/home.js
'use strict';
const Controller = require('egg').Controller;
class HomeController extends Controller {
async index() {
const { ctx } = this;
ctx.body = 'hi, egg';
}
async test() {
const { ctx } = this;
ctx.body = '测试接口';
}
}
module.exports = HomeController;
// app/router.js
'use strict';
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
router.get('/', controller.home.index);
router.get('/test', controller.home.test);
};
Перейдите в корневой каталог проекта, чтобы запустить проект, командная строка выглядит следующим образом:
npm run dev
// 或者
yarn dev
При нормальных обстоятельствах Egg.js по умолчанию запускает порт 7001. На рисунке ниже показано, что проект запущен успешно.
Просматриваем его через браузер следующим образом:
мы в/app/controller/home.js
написано в файлеtest
Метод был успешно выполнен.
Понять механизм маршрутизации Egg.js
Маршрут (маршрутизатор) в основном используется для описания соответствующей связи между URL-адресом запроса и контроллером, который конкретно отвечает за выполнение.app/router.js
файл используется для унификации всех правил маршрутизации.
Проще говоря, в приведенном выше примере мыapp/controller/home.js
написано наtest
метод, то вapp/router.js
документ будетtest
Метод выдает как GET. Это соответствие между URL и контроллером. Удобство Egg.js в том, что контекст для нас открыт, а приложение — это контекст глобального приложения. Маршруты и контроллеры хранятся в приложении глобального контекста приложения, поэтому вам нужно заботиться только о своей бизнес-логике и операциях с базой данных, и вам не нужно отвлекаться на другие тривиальные вещи.
Бизнес-логика в основном написана в контроллере. Давайте узнаем, как его назвать. Например, сейчас я хочу создать новый контроллер, связанный с пользователем. Мы можем написать это так:
// 在 app/controller/ 下新建 user.js
'use strict';
const Controller = require('egg').Controller;
class UserController extends Controller {
async index() {
const { ctx } = this;
ctx.body = '用户';
}
}
module.exports = UserController;
Первая буква в верблюжьем регистре пишется с заглавной буквы, UserController наследует Controller, а функции можно писать как async и await.
Напишите простые интерфейсы GET и POST
По сути, выше просто написано, как написать GET интерфейс, добавим сюда еще некоторые познания для получения параметров запроса на маршруте, а именно/user?username=nick
После приветствия идет параметр запроса, который получается с помощью следующего кода:
// 在 app/controller/user.js
'use strict';
const Controller = require('egg').Controller;
class UserController extends Controller {
async index() {
const { ctx } = this;
const { username } = ctx.query;
ctx.body = username;
}
}
module.exports = UserController;
Обратите внимание, что вам нужно добавить параметры маршрутизации
'use strict';
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
router.get('/', controller.home.index);
router.get('/test', controller.home.test);
router.get('/user', controller.user.index);
};
Снова зайдите в браузер, чтобы увидеть, могут ли отображаться параметры запроса:
Также есть способ получить параметры объявления, которые можно получить черезctx/params
получено:
// 在 app/controller/user.js
'use strict';
const Controller = require('egg').Controller;
class UserController extends Controller {
async index() {
const { ctx } = this;
const { username } = ctx.query;
ctx.body = username;
}
async getid() {
const { ctx } = this;
const { id } = ctx.params;
ctx.body = id;
}
}
module.exports = UserController;
'use strict';
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
router.get('/', controller.home.index);
router.get('/test', controller.home.test);
router.get('/user', controller.user.index);
router.get('/getid/:id', controller.user.getid);
};
как показано на рисунке,getid/999
Следующие 999 используются какctx.params
Идентификатор внутри возвращается на веб-страницу.
После завершения GET давайте поговорим о POST. При разработке проекта мы будем использовать интерфейс POST, когда нам нужно манипулировать содержимым. Поскольку пакеты данных, которые мы можем захотеть передать, относительно велики, мы не будем подробно останавливаться на GET и Интерфейсы POST здесь.Разница, иначе это станет курсом собеседования. Если я действительно хочу это сказать, то скажу одно, они ничем не отличаются, все они основаны на протоколе TCP.
Давайте посмотрим на применение интерфейса POST в Egg, как упоминалось выше.app/controller/user.js
Добавьте метод внутрь:
...
async add() {
const { ctx } = this;
const { title, content } = ctx.request.body;
// 框架内置了 bodyParser 中间件来对这两类格式的请求 body 解析成 object 挂载到 ctx.request.body 上
// HTTP 协议中并不建议在通过 GET、HEAD 方法访问时传递 body,所以我们无法在 GET、HEAD 方法中按照此方法获取到内容。
ctx.body = {
title,
content,
};
}
...
'use strict';
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
router.get('/', controller.home.index);
router.get('/test', controller.home.test);
router.get('/user', controller.user.index);
router.get('/getid/:id', controller.user.getid);
router.post('/add', controller.user.add);
};
POST-запрос не является удобным интерфейсом браузера, мы помогаем Почтальону отправить POST-запрос, студенты не могут загрузить загрузку для разработчиков, которые можно сказать, что Почтальон является важным инструментом для тестирования интерфейса, который очень прост в использовании. При нажатии кнопки Почтальон отправить запрос, вы не получите возврата, т.к. запросы междоменные, то нам нужноegg-cors
Этот пакет npm для решения междоменных проблем. Сначала установите его, затем вconfig/plugin.js
Вводится следующим образом:
// config/plugin.js
'use strict';
exports.cors = {
enable: true,
package: 'egg-cors',
};
затем вconfig/config.default.js
Добавьте следующий код в:
// config/config.default.js
config.security = {
csrf: {
enable: false,
ignoreJSON: true,
},
domainWhiteList: [ '*' ], // 配置白名单
};
config.cors = {
// origin: '*', //允许所有跨域访问,注释掉则允许上面 白名单 访问
credentials: true, // 允许 Cookie 跨域
allowMethods: 'GET,HEAD,PUT,POST,DELETE,PATCH,OPTIONS',
};
Моя текущая конфигурация доступна всем. Затем перезапустите проект, откройте интерфейс добавления запроса Postman, как показано ниже, обратите внимание, что тело запроса должноJSON(Application/json)
форма:
Говоря об этом, я должен упомянуть службу Service. Вышеупомянутая бизнес-логика интерфейса размещена в Контроллере.Если мне нужно управлять базой данных, нам нужно поместить метод работы с базой данных в Сервис.
Сначала создаем новую папкуapp/service
, создать новый в папкеuser.js
код показывает, как показано ниже:
'use strict';
const Service = require('egg').Service;
class UserService extends Service {
async user() {
return {
title: '你妈贵姓',
content: '免贵姓李',
};
}
}
module.exports = UserService;
затем перейтиapp/controller/user.js
вызывать:
...
async index() {
const { ctx } = this;
const { title, content } = await ctx.service.user.user();
ctx.body = {
title,
content,
};
}
...
// app/router.js
...
router.post('/getUser', controller.user.index);
Каждый раз, когда вы добавляете метод в контроллер, не забывайтеrouter,js
Добавьте маршрутизацию внутри.
Я еще не подключался к базе данных, поэтому давайте пока напишем так: при подключении к базе данных в сервисной папке будут создаваться некоторые скрипты для операций, связанных с базой данных, о чем будет рассказано позже.
Как использовать шаблоны внешнего интерфейса в Egg.js
Если некоторым студентам необходимо создать простые статические страницы, похожие на официальный веб-сайт компании, рекламные страницы и т. д., они могут рассмотреть возможность использования шаблонов внешнего интерфейса для написания страниц.
Сначала мы устанавливаем плагин шаблонаegg-view-ejs
:
npm install egg-view-ejs -save
затем вconfig/plugin.js
Он объявляет плагины, которые необходимо использовать.
exports.ejs = {
enable: true,
package: 'egg-view-ejs',
};
Тогда нам нужно идтиconfig/config.default.js
конфигурацияejs
, на этом шаге мы будем.ejs
суффикс к.html
суффикс.
config.view = {
mapping: {'.html': 'ejs'} //左边写成.html后缀,会自动渲染.html文件
};
существуетapp
Создано в каталогеview
папку и создать новуюindex.html
Файл выглядит так:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title><%-title%></title>
</head>
<body>
<!-- 使用模板数据 -->
<h1><%-title%></h1>
</body>
</html>
Исправлятьapp/controller/home.js
Скрипт выглядит так:
// app/controller/home.js
'use strict';
const Controller = require('egg').Controller;
class HomeController extends Controller {
async index() {
const { ctx } = this;
// index.html 默认回去 view 文件夹寻找,Egg 已经封装好这一层了
await ctx.render('index.html', {
title: '你妈贵姓',
});
}
async test() {
const { ctx } = this;
ctx.body = '测试接口';
}
}
module.exports = HomeController;
Перезапустите весь проект и просмотрите его в браузере.http://localhost:7001
Как показано ниже:
title
Переменные были загружены, и шаблон отображается нормально.
К этому моменту учащиеся прошли гладко и в основном имеют общее представление о Яйце. Конечно, понимания этих базовых знаний недостаточно для завершения написания всего проекта, но основа по-прежнему очень важна. В конце концов, Яйцо — это на основе Коа вторичный Инкапсулированный, многие встроенные элементы настройки необходимо ознакомить с небольшими вариантами использования.Я надеюсь, что студенты не будут ленивы.После следования вышеприведенному содержанию лучше не копировать и вставлять, а набирать построчно линия действительно может стать их собственным знанием.
Интерфейс журнала записи React
Введение
С момента выпуска React 16.8 в React появились хуки, которые поддерживают управление состоянием в функциональных компонентах. В чем заключается концепция Когда мы пишем код с помощью React, мы можем почти отказаться от предыдущего метода написания классов. Причина, по которой я говорю «почти», заключается в том, что есть места, где Class все еще нужен, но автор React Дэн сказал: «Будущее React — это хуки». Итак, на этот раз мы будем использовать метод письма Hooks и снова вводить элемент дневника.
Сборка среды разработки React и доступ к Ant Design Mobile
Для среды React этого курса мы используем официально предоставленную среду React.create-react-app
для инициализации, если вашnpm
Версии выше 5.2, вы можете использовать следующую командную строку для инициализации проекта:
npx create-react-app diary
cd diary
npm run start
Если запуск прошел успешно, по умолчанию запускается порт 3000, открывается браузер и вводитсяhttp://localhost:3000Вы увидите следующую страницу:
чистыйdiary
проектsrc
Некоторые файлы в каталоге, окончательная структура каталогов показана на следующем рисунке:
Далее мы вводимAnt Design Mobile
, сначала нам нужно загрузить его в проект, открыть инструмент командной строки и ввести следующую команду в корневой каталог проекта:
npm install antd-mobile --save
затем вdiary/src/index.js
Файлы стилей, которые импортируют и:
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import 'antd-mobile/dist/antd-mobile.css';
ReactDOM.render(<App />, document.getElementById('root'));
затем вdiary/src/App.js
Введите компонент, чтобы протестировать его:
// App.js
import React from 'react';
import { Button } from 'antd-mobile';
function App() {
return (
<div className="App">
<Button type='primary'>测试</Button>
</div>
);
}
export default App;
Затем перезапустите проект, откройте браузер и запустите мобильный режим, чтобы увидеть эффект:
При нажатии на мобильную веб-страницу будет задержка в 300 миллисекунд, поэтому нам нужноdiary/public/index.html
Добавьте код скрипта в файл:
// index.html
...
<script src="https://as.alipayobjects.com/g/component/fastclick/1.0.6/fastclick.js"></script>
<script>
if ('addEventListener' in document) {
document.addEventListener('DOMContentLoaded', function() {
FastClick.attach(document.body);
}, false);
}
if(!window.Promise) {
document.writeln('<script src="https://as.alipayobjects.com/g/component/es6-promise/3.2.2/es6-promise.min.js"'+'>'+'<'+'/'+'script>');
}
</script>
...
Стиль antd может загружаться по требованию. Если вы хотите узнать о загрузке по требованию, вы можете перейти кОфициальный сайтнаучиться вносить
Адаптировать мобильные решения через vw
Как мы все знаем, разрешение мобильного терминала постоянно меняется, и нам сложно идеально адаптироваться к идеальному отображению страницы под каждым разрешением. Если это не может быть идеально, по крайней мере, попробуйте добиться приблизительного результата и адаптируйте разрешение мобильного терминала через vw. Он может преобразовать единицу измерения px на странице в vw vh, чтобы адаптироваться к изменяющемуся разрешению мобильных телефонов. Учащиеся, которые не хотят заниматься адаптацией, также могут пропустить этот шаг и продолжить следующее обучение.
Во-первых, нам нужно освободить скрытую конфигурацию веб-пакета проекта с помощью следующей командной строки:
npm run eject
После завершения операции структура каталогов проекта показана на следующем рисунке:
Есть еще два элемента конфигурации, как показано на рисунке. Если работает
npm run eject
Если он не может быть выполнен, рекомендуется сначала.git
удаление файла,rm -rf .git
, затем снова запуститьnpm run eject
.
Затем установите еще несколько плагинов, инструкция следующая:
npm install postcss-aspect-ratio-mini postcss-px-to-viewport postcss-write-svg postcss-cssnext postcss-viewport-units cssnano cssnano-preset-advanced
После завершения установки откройтеdiary/config/webpack.config.js
сценарий, изменитьpostcss
плагин загрузчика.
Сначала импортируйте установленный выше пакет, который можно поместить ниже строки 28:
// 28 行
const postcssNormalize = require('postcss-normalize');
const postcssAspectRatioMini = require('postcss-aspect-ratio-mini');
const postcssPxToViewport = require('postcss-px-to-viewport');
const postcssWriteSvg = require('postcss-write-svg');
const postcssCssnext = require('postcss-cssnext');
const postcssViewportUnits = require('postcss-viewport-units');
const cssnano = require('cssnano');
const appPackageJson = require(paths.appPackageJson);
////
Затем перейдите к строке 100 и начните добавлять некоторую конфигурацию postcss:
{
// Options for PostCSS as we reference these options twice
// Adds vendor prefixing based on your specified browser support in
// package.json
loader: require.resolve('postcss-loader'),
options: {
// Necessary for external CSS imports to work
// https://github.com/facebook/create-react-app/issues/2677
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
require('postcss-preset-env')({
autoprefixer: {
flexbox: 'no-2009',
},
stage: 3,
}),
// Adds PostCSS Normalize as the reset css with default options,
// so that it honors browserslist config in package.json
// which in turn let's users customize the target behavior as per their needs.
postcssNormalize(),
postcssAspectRatioMini({}),
postcssPxToViewport({
viewportWidth: 750, // 针对 iphone6 的设计稿
viewportHeight: 1334, // 针对 iphone6 的设计稿
unitPrecision: 3,
viewportUnit: 'vw',
selectorBlackList: ['.ignore', '.hairlines', 'am'], // 这里添加 am 是因为引入了 antd-mobile 组件库,否则组件库内的单位都会被改为 vw 单位,样式会乱
minPixelValue: 1,
mediaQuery: false
}),
postcssWriteSvg({
utf8: false
}),
postcssCssnext({}),
postcssViewportUnits({}),
cssnano({
preset: "advanced",
autoprefixer: false,
"postcss-zindex": false
})
],
sourceMap: isEnvProduction && shouldUseSourceMap,
},
},
После добавления перезапустите проект и проверьте, изменился ли блок через браузер:
Точно так же и другие библиотеки компонентов могут быть адаптированы под мобильные проекты в таком виде, но следует отметить, что в атрибут selectorBlackList нужно добавить соответствующее имя библиотеки компонентов, чтобы избежать преобразования в vw
Разработка страницы со списком дневников
После еды мы разработаем несколько страниц, но перед разработкой страниц нам нужно добавить механизмы маршрутизации. пройти черезreact-router-dom
Плагин управляет маршрутизацией проекта, сначала установите его:
npm i react-router-dom -save
Затем мы изменяем структуру каталогов, сначала вsrc
новый каталогHome
папку, создайте новую папку в папкеindex.jsx
иstyle.css
, содержание следующее:
// Home/index.jsx
import React from 'react'
import './style.css'
const Home = () => {
return (
<div>
Home
</div>
)
}
export default Home
Далее редактируем страницу конфигурации маршрутизации, принцип маршрутизации собственно заключается в том, что страница динамически загружает страницу компонента соответствующую адресу браузера через изменение адреса браузера. Например, я сейчас даю/
Домашняя страница настроить одинHome
компонента, то при доступе браузераhttp://localhost:3000
, страница будет отображать соответствующийHome
компоненты. Тогда положимApp.js
изменить наRouter.js
код показывает, как показано ниже:
// Router.js
import React from 'react';
import Home from './Home';
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
const RouterMap = () => {
return <Router>
<Switch>
<Route exact path="/">
<Home />
</Route>
</Switch>
</Router>
}
export default RouterMap;
Чтобы немного объяснить,Switch
производительность иJavaScript
серединаswitch
Это почти то же самое, то есть, когда соответствующий маршрут сопоставляется, он больше не сопоставляется. Мы будемsrc/index.js
импортировать это в скриптRouterMap
, конкретный код выглядит следующим образом:
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import RouterMap from './Router';
import 'antd-mobile/dist/antd-mobile.css';
ReactDOM.render(<RouterMap />, document.getElementById('root'));
Затем перезапустите проект и проверьте работоспособность браузера:
мы вHome
Напишем в компоненте домашнюю страницу проекта дневника.Главную страницу будем отображать в виде списка, далее можно использоватьantd
серединаCard
Карточный компонент, давайте посмотрим, как реализован код:
// Home/index.jsx
import React from 'react'
import { Card } from 'antd-mobile'
import './style.css'
const list = [0,1,2,3,4,5,6,7,8,9]
const Home = () => {
return (
<div className='diary-list'>
{
list.map(item => <Card className='diary-item'>
<Card.Header
title="我和小明去捉迷藏"
thumb="https://gw.alipayobjects.com/zos/rmsportal/MRhHctKOineMbKAZslML.jpg"
extra={<span>晴天</span>}
/>
<Card.Body>
<div>{item}</div>
</Card.Body>
<Card.Footer content="2020-01-09" />
</Card>)
}
</div>
)
}
export default Home
// Home/style.css
.diary-list .diary-item {
margin-bottom: 20px;
}
.diary-item .am-card-header-content {
flex: 7 1;
}
Вы можете запрашивать элементы через браузер, например, изменять стили внутри компонента, например,.am-card-header-content
Измените ширину заголовка. Рациональное использование библиотеки компонентов помогает повысить эффективность работы. Хотя эта страница проста, ее также можно рассматривать как роль в привлечении нефрита.atnd
Этот набор библиотек компонентов был тщательно исследован, и при анализе потребностей бизнеса на работе его можно освоить, а продвижение по службе и повышение зарплаты не за горами.
Разработка страницы подробностей дневника
существуетsrc
Создайте новый в каталогеDetail
Папка, давайте напишем страницу деталей:
// Detail/index.jsx
import React from 'react'
import { NavBar, Icon, List } from 'antd-mobile'
const Detail = () => {
return (<div className='diary-detail'>
<NavBar
mode="light"
icon={<Icon type="left" />}
onLeftClick={() => console.log('onLeftClick')}
>我和小明捉迷藏</NavBar>
<List renderHeader={() => '2020-01-09 晴天'} className="my-list">
<List.Item wrap>
今天我和小明去西湖捉迷藏,
小明会潜水,躲进了湖底,我在西湖边找了半天都没找到,
后来我就回家了,不跟他嘻嘻哈哈的了。
</List.Item>
</List>
</div>)
}
export default Detail
используется на головеNavBar
Метка панели навигации с заголовком и кнопкой «Назад». Выбор контентаList
Компонент списка просто отображает содержательную часть дневника. не забудь пойтиRouter.js
добавить в скрипт маршрутизацииDetail
маршрут:
const RouterMap = () => {
return <Router>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route exact path="/detail">
<Detail />
</Route>
</Switch>
</Router>
}
ввод в браузереhttp://localhost:3000/detail
Проверьте эффект:
Мы связываем список домашней страницы и страницу сведений вместе, чтобы мы могли щелкнуть элемент списка домашней страницы, перейти на соответствующую страницу сведений, ввести параметр id в маршрут, а затем получить параметр id строки запроса браузера. через фильтрацию на странице сведений. Давайте сначала изменим код домашней страницы:
import React from 'react'
import { Card } from 'antd-mobile'
import { Link } from 'react-router-dom'
import './style.css'
const list = [0,1,2,3,4,5,6,7,8,9]
const Home = () => {
return (
<div className='diary-list'>
{
list.map(item => <Link to={{ pathname: 'detail', search: `?id=${item}` }}><Card className='diary-item'>
<Card.Header
title="我和小明去捉迷藏"
thumb="https://gw.alipayobjects.com/zos/rmsportal/MRhHctKOineMbKAZslML.jpg"
extra={<span>晴天</span>}
/>
<Card.Body>
<div>{item}</div>
</Card.Body>
<Card.Footer content="2020-01-09" />
</Card></Link>)
}
</div>
)
}
export default Home
вводитьLink
лейбл, будетCard
компоненты упакованы, черезto
Свойство устанавливает путь перехода и параметры, прикрепленные к пути, как показано в приведенном выше коде. Далее мыDetail
Этот параметр принимается в компоненте, мы получаем нужный параметр, написав инструментальный метод.src
создать новую папкуutils
, создать новый в папкеindex.js
Скрипт, код такой:
function getQueryString(name) {
var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
var r = window.location.search.substr(1).match(reg);
if(r != null) {
return unescape(r[2]);
} else{
return null
};
}
module.exports = {
getQueryString
}
Этот метод позволяет получить строку запроса браузера, а затем открытьDetail
комплектующие, импортutils
ПолучатьgetQueryString
метод, и нам нужно нажать кнопку «Назад» на странице сведений, запись хуковreact-router-dom
предоставляет намuseHistory
способ реализации отката, конкретный код выглядит следующим образом:
// Detail/index.jsx
import React from 'react'
import { NavBar, Icon, List } from 'antd-mobile'
import { useHistory } from 'react-router-dom'
import { getQueryString } from '../utils'
const Detail = () => {
const history = useHistory()
const id = getQueryString('id')
return (<div className='diary-detail'>
<NavBar
mode="light"
icon={<Icon type="left" />}
onLeftClick={() => history.goBack()}
>我和小明捉迷藏{id}</NavBar>
<List renderHeader={() => '2020-01-09 晴天'} className="my-list">
<List.Item wrap>
今天我和小明去西湖捉迷藏,
小明会潜水,躲进了湖底,我在西湖边找了半天都没找到,
后来我就回家了,不跟他嘻嘻哈哈的了。
</List.Item>
</List>
</div>)
}
export default Detail
получитьid
После атрибута отобразите его на заголовке, посмотрим на действие браузера:
Развитие страницы редактирования дневника
После игры в прятки с Сяо Мином в течение десяти дней мне стало очень скучно. Мы все же быстро написали страницу редактирования и добавили немного интересной информации в дневник. по-старому, мыsrc
новый каталогEdit
папку и начните писать наш компонент ввода журнала:
// Detail/index.jsx
import React, { useState } from 'react'
import { List, InputItem, TextareaItem, DatePicker, ImagePicker } from 'antd-mobile'
import './style.css'
const Edit = () => {
const [date, setDate] = useState()
const [files, setFile] = useState([])
const onChange = (files, type, index) => {
console.log(files, type, index);
setFile(files)
}
return (<div className='diary-edit'>
<List renderHeader={() => '编辑日记'}>
<InputItem
clear
placeholder="请输入标题"
>标题</InputItem>
<TextareaItem
rows={6}
placeholder="请输入日记内容"
/>
<DatePicker
mode="date"
title="请选择日期"
extra="请选择日期"
value={date}
onChange={date => setDate(date)}
>
<List.Item arrow="horizontal">日期</List.Item>
</DatePicker>
<ImagePicker
files={files}
onChange={onChange}
onImageClick={(index, fs) => console.log(index, fs)}
selectable={files.length < 1}
multiple={false}
/>
</List>
</div>)
}
export default Edit
// Detail/style.css
.diary-edit {
height: 100vh;
background: #fff;
}
Приведенный выше код добавляет четыре элемента контента, а именно заголовок, контент, дату и изображение. Расположение между компонентами является исключительно вашим собственным расположением. Учащиеся могут установить в соответствии с их любимым макетом набора. Обратите внимание, что после написания обязательно перейдите на страницу маршрутизации, чтобы добавить адрес маршрутизации:
// Router.js
import React from 'react';
import Home from './Home';
import Detail from './Detail';
import Edit from './Edit';
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
const RouterMap = () => {
return <Router>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route exact path="/detail">
<Detail />
</Route>
<Route exact path="/edit">
<Edit />
</Route>
</Switch>
</Router>
}
export default RouterMap;
Затем перейдите в браузер, чтобы просмотреть, как выглядит интерфейс:
Затем я могу снова записать счастливую историю с Сяохуном~~
Разработка сервера Egg.js
Помните, когда мы впервые создалиegg-demo
проект? Мы используем этот проект для серверной разработки. Первое, что нам нужно сделать, это установить его локальноMySQL
База данных, как установить, слушайте меня подробно.
Установить базу данных Mysql локально
1. Загрузите и установите MySQL
Входитьофициальный сайт MySQLСкачать версию для сообщества баз данных MySQL
Пожалуйста, выберите версию, которая вам подходит, автором является система MacOS, поэтому выберите первый установочный пакет, обратите внимание, чтобы не входить в систему для загрузки.
После завершения загрузки следуйте подсказкам навигации для установки, и когда пользователь root настроит пароль,обязательно запомните пароль, который будет использоваться позже:
После завершения установки вы можете войти в систему и настроить базу данных для запуска здесь:
База данных операций Navicat Создание таблицы журнала
Графический интерфейс очень удобен для новичков. Визуализация базы данных может повысить эффективность работы новичков. Я использую Navicat для MySQL, это облегченный инструмент визуализации базы данных. Адрес загрузки здесь не указан, потому что я боюсь, что меня засудят за нарушение. Вы можете самостоятельно отправиться в Интернет для поиска ресурсов для скачивания, их еще много, и вам еще нужно развивать эту способность.
В случае запуска БД открываем инструмент Navicat для привязки локальной БД, как показано на рисунке:
После сохранения в списке слева появится элемент тестовой базы данных, который станет зеленым после успешного связывания базы данных:
Мы можем видеть номер версии и номер порта моей локальной базы данных, поэтому мы подключаемся к локальной базе данных, а затем начинаем создавать базу данных дневника и создавать таблицу:
При создании новой таблицы обратите внимание, что мы сначала заполняем имя поля таблицы, а затем после сохранения заполняем имя таблицы. При написании слова «терминал» каждый должен обращать внимание на выбор набора символов слова «терминал».utf8mb4
, иначе китайский ввод не поддерживается:
Здесь конец слова идентификатора должен быть установлен на автоинкремент и использоваться в качестве первичного ключа:
Затем нажмите кнопку сохранения в верхнем левом углу, чтобы сохранить таблицу. Добавляем запись в таблицу дневника:
На этом наша работа с базой данных почти завершена.Студенты, которые не понимают, также могут написать мне лично, и я решу ваши проблемы лично.
Далее мы можем открытьegg-demo
проект, чтобы связать базу данных, нам нужно установитьegg-mysql
package, запустите следующую командную строку в корневом каталоге проекта:
npm i --save egg-mysql
Включите плагин:
// config/plugin.js
exports.mysql = {
enable: true,
package: 'egg-mysql',
};
// config/config.default.js
exports.mysql = {
// 单数据库信息配置
client: {
// host
host: 'localhost',
// 端口号
port: '3306',
// 用户名
user: 'root',
// 密码
password: '******',
// 数据库名
database: 'diary',
},
// 是否加载到 app 上,默认开启
app: true,
// 是否加载到 agent 上,默认关闭
agent: false,
};
Пароль должен заполнить пароль, который вы помните выше
мы идем на `сервер文件夹新建一个文件
diary.js` добавляет метод для поиска в списке:
// server/diary.js
'use strict';
const Service = require('egg').Service;
class DiaryService extends Service {
async list() {
const { app } = this;
try {
const result = await app.mysql.select('diary');
return result;
} catch (error) {
console.log(error);
return null;
}
}
}
module.exports = DiaryService;
затем вcontroller/home.js
Ссылка здесь добавляет новый метод для получения списка журналов:
'use strict';
const Controller = require('egg').Controller;
class HomeController extends Controller {
async list() {
const { ctx } = this;
const result = await ctx.service.diary.list();
if (result) {
ctx.body = {
status: 200,
data: result,
};
} else {
ctx.body = {
status: 500,
errMsg: '获取失败',
};
}
}
}
module.exports = HomeController;
Следует отметить, что каждый раз, когда вы добавляете новый метод, вам необходимо добавить соответствующий интерфейс в файл маршрутизации:
// router.js
'use strict';
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
router.get('/list', controller.home.list);
};
В этот момент перезапустите проект и выполните следующую командную строку:
npm run dev
После успешного запуска перейдите в браузер, чтобы получить этот интерфейс, чтобы увидеть, можно ли запросить данные.Успешное получение выглядит следующим образом:
В это время будет немного чувства достижения, поэтому мы просто сделаем это одним махом и напишем несколько других интерфейсов.
Добавить интерфейс журнала
Чтобы добавить интерфейс, нам нужно использовать метод запроса POST, я уже упоминал, как POST получает параметры, переданные в теле запроса, поэтому я не буду здесь вдаваться в подробности. Давайте напишем интерфейс напрямую, сначала откройтеservice/diary.js
Скрипт добавленadd
метод:
async add(params) {
const { app } = this;
try {
const result = await app.mysql.insert('diary', params);
return result;
} catch (error) {
console.log(error);
return null;
}
}
затем перейтиcontroller/home.js
Добавьте в скрипт интерфейсные операции:
async add() {
const { ctx } = this;
const params = {
...ctx.request.body,
};
const result = await ctx.service.diary.add(params);
if (result) {
ctx.body = {
status: 200,
data: result,
};
} else {
ctx.body = {
status: 500,
errMsg: '添加失败',
};
}
}
затем перейтиrouter.js
В сценарии маршрутизации добавьте конфигурацию маршрутизации:
'use strict';
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
router.get('/list', controller.home.list);
router.post('/add', controller.home.add);
};
Интерфейс POST должен пройти тест Postman:
После успешного добавления будет возвращен соответствующий id и другая информация записи.Проверим, будут ли в списке приобретения добавленные выше данные:
На этот раз он должен быть успешным, и добавление интерфейса завершено.
Изменить интерфейс журнала
Прежде всего, давайте проанализируем, если мы модифицируем дневник, нам нужно сначала найти его id, потому что id является первичным ключом, и мы используем id для обновления полей записи. тогда впередservice/diary.js
Метод добавления операции с базой данных:
async update(params) {
const { app } = this;
try {
const result = await app.mysql.update('diary', params);
return result;
} catch (error) {
console.log(error);
return null;
}
}
затем откройтеcontoller/home.js
Добавить метод модификации:
async update() {
const { ctx } = this;
const params = {
...ctx.request.body,
};
const result = await ctx.service.diary.update(params);
if (result) {
ctx.body = {
status: 200,
data: result,
};
} else {
ctx.body = {
status: 500,
errMsg: '编辑失败',
};
}
}
идти последнимrouter.js
Добавьте конфигурацию интерфейса:
'use strict';
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
router.get('/list', controller.home.list);
router.post('/add', controller.home.add);
router.post('/update', controller.home.update);
};
Перейдите в Postman и измените вторую запись:
Вторая запись была успешно изменена.
Получить интерфейс сведений о статье
Сначала нам нужно получить поле id для запроса содержимого записи соответствующего id или перейти кservice/diary.js
Добавить интерфейс:
async diaryById(id) {
const { app } = this;
if (!id) {
console.log('id不能为空');
return null;
}
try {
const result = await app.mysql.select('diary', {
where: { id },
});
return result;
} catch (error) {
console.log(error);
return null;
}
}
controller/home.js
async getDiaryById() {
const { ctx } = this;
console.log('ctx.params', ctx.params);
const result = await ctx.service.diary.diaryById(ctx.params.id);
if (result) {
ctx.body = {
status: 200,
data: result,
};
} else {
ctx.body = {
status: 500,
errMsg: '获取失败',
};
}
}
router.js
'use strict';
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
router.get('/list', controller.home.list);
router.post('/add', controller.home.add);
router.post('/update', controller.home.update);
router.get('/detail/:id', controller.home.getDiaryById);
};
удалить интерфейс
Удалить интерфейс относительно просто, находим соответствующую запись id и удаляем ее:
service/diary.js
async delete(id) {
const { app } = this;
try {
const result = await app.mysql.delete('diary', { id });
return result;
} catch (error) {
console.log(error);
return null;
}
}
controller/home.js
async delete() {
const { ctx } = this;
const { id } = ctx.request.body;
const result = await ctx.service.diary.delete(id);
if (result) {
ctx.body = {
status: 200,
data: result,
};
} else {
ctx.body = {
status: 500,
errMsg: '删除失败',
};
}
}
router.js
'use strict';
/**
* @param {Egg.Application} app - egg application
*/
module.exports = app => {
const { router, controller } = app;
router.get('/list', controller.home.list);
router.post('/add', controller.home.add);
router.post('/update', controller.home.update);
router.get('/detail/:id', controller.home.getDiaryById);
router.post('/delete', controller.home.delete);
};
После удаления остается только запись с id 2, далее интерфейсная часть в основном завершена, переходим на фронтенд для подключения соответствующего интерфейса.
Совместный интерфейс отладки
Старая линейка фронтенда, интерфейс отладки здесь. мы переключаемся наdiary
Интерфейсный проект, сначала установитеaxios
:
npm i axios --save
затем вutils
Добавьте скрипт в папкуaxios.js
, давайте инкапсулируем его во второй раз. Причина вторичной инкапсуляции в том, что когда мы единообразно обрабатываем возврат интерфейса, мы можем обрабатывать его в одном месте, вместо того, чтобы модифицировать его в том месте, где возвращается каждый запрос.
// utils/axios.js
import axios from 'axios'
import { Toast } from 'antd-mobile'
// 根据 process.env.NODE_ENV 环境变量判断开发环境还是生产环境,我们服务端本地启动的端口是 7001
axios.defaults.baseURL = process.env.NODE_ENV == 'development' ? '//localhost:7001' : ''
// 表示跨域请求时是否需要使用凭证
axios.defaults.withCredentials = false
axios.defaults.headers['X-Requested-With'] = 'XMLHttpRequest'
// post 请求是 json 形式的
axios.defaults.headers.post['Content-Type'] = 'application/json'
axios.interceptors.response.use(res => {
if (typeof res.data !== 'object') {
console.error('数据格式响应错误:', res.data)
Toast.fail('服务端异常!')
return Promise.reject(res)
}
if (res.data.status != 200) {
if (res.data.message) Toast.error(res.data.message)
return Promise.reject(res.data)
}
return res.data
})
export default axios
После завершения вторичной упаковки не забудьте
axios
выбросили.
Следующий шаг - перейти на домашнюю страницу, чтобы запросить интерфейс списка, открыть его.src/Home/index.jsx
:
// src/Home/index.jsx
import React, { useState, useEffect } from 'react'
import { Card } from 'antd-mobile'
import { Link } from 'react-router-dom'
import axios from '../utils/axios'
import './style.css'
const Home = () => {
// 通过 useState Hook 函数定义 list 变量
const [list, setList] = useState([])
useEffect(() => {
// 请求 list 接口,返回列表数据
axios.get('/list').then(({ data }) => {
setList(data)
})
}, [])
return (
<div className='diary-list'>
{
list.map(item => <Link to={{ pathname: 'detail', search: `?id=${item.id}` }}><Card className='diary-item'>
<Card.Header
title={item.title}
thumb={item.url}
extra={<span>晴天</span>}
/>
<Card.Body>
<div>{item.content}</div>
</Card.Body>
<Card.Footer content={item.date} />
</Card></Link>)
}
</div>
)
}
export default Home
.diary-list .diary-item {
margin-bottom: 20px;
}
.diary-item .am-card-header-content {
flex: 7 1;
}
.diary-item .am-card-header-content img {
width: 30px;
}
Откройте браузер и введитеhttp://localhost:3000
Дисплей выглядит так, как показано ниже:
Написание страницы сведений
Далее приходим к написанию страницы деталей, открываемsrc/Detail/index.jsx
:
import React, { useState, useEffect } from 'react'
import { NavBar, Icon, List } from 'antd-mobile'
import { useHistory } from 'react-router-dom'
import { getQueryString } from '../utils'
import axios from '../utils/axios'
const Detail = () => {
const [detail, setDetail] = useState({})
const history = useHistory()
const id = getQueryString('id')
useEffect(() => {
axios.get(`/detail/${id}`).then(({ data }) => {
if (data.length) {
setDetail(data[0])
}
})
}, [])
return (<div className='diary-detail'>
<NavBar
mode="light"
icon={<Icon type="left" />}
onLeftClick={() => history.goBack()}
>{detail.title || ''}</NavBar>
<List renderHeader={() => `${detail.date} 晴天`} className="my-list">
<List.Item wrap>
{detail.content}
</List.Item>
</List>
</div>)
}
export default Detail
отредактируйте страницу
Добавить страницу статьи, мы открываемsrc/Edit/index.jsx
:
import React, { useState } from 'react'
import { List, InputItem, TextareaItem, DatePicker, ImagePicker, Button, Toast } from 'antd-mobile'
import moment from 'moment'
import axios from '../utils/axios'
import './style.css'
const Edit = () => {
const [title, setTitle] = useState('') // 标题
const [content, setContent] = useState('') // 内容
const [date, setDate] = useState('') // 日期
const [files, setFile] = useState([]) // 图片文件
const onChange = (files, type, index) => {
console.log(files, type, index);
setFile(files)
}
const publish = () => {
if (!title || !content || !date) {
Toast.fail('请填写必要参数')
return
}
const params = {
title,
content,
date: moment(date).format('YYYY-MM-DD'),
url: files.length ? files[0].url : ''
}
axios.post('/add', params).then(res => {
Toast.success('添加成功')
})
}
return (<div className='diary-edit'>
<List renderHeader={() => '编辑日记'}>
<InputItem
clear
placeholder="请输入标题"
onChange={(value) => setTitle(value)}
>标题</InputItem>
<TextareaItem
rows={6}
placeholder="请输入日记内容"
onChange={(value) => setContent(value)}
/>
<DatePicker
mode="date"
title="请选择日期"
extra="请选择日期"
value={date}
onChange={date => setDate(date)}
>
<List.Item arrow="horizontal">日期</List.Item>
</DatePicker>
<ImagePicker
files={files}
onChange={onChange}
onImageClick={(index, fs) => console.log(index, fs)}
selectable={files.length < 1}
multiple={false}
/>
<Button type='primary' onClick={() => publish()}>发布</Button>
</List>
</div>)
}
export default Edit
Обратите внимание, что поскольку я не покупал услугу CDN, интерфейс загрузки ресурсов отсутствует, поэтому здесь мы используем хранилище base64 для изображений.
После успешного добавления просмотрите страницу со списком.
удалить статью
Нам нужно добавить кнопку на страницу сведений, так как у нас нет системы управления фоном Само собой разумеется, что эту кнопку удаления нужно разместить на странице управления фоном, но для удобства я написал все это в одном проект, потому что дневник для себя.Вот почему я говорю, что я пишу проект дневника вместо проекта блога, когда имя меняется, это проект блога.
Ставим кнопку удаления на страницу подробностей, чтобы посмотреть, открытьsrc/Detail/index.jsx
, добавить кнопку удаления в правую позицию головы, код такой:
import React, { useState, useEffect } from 'react'
import { NavBar, Icon, List } from 'antd-mobile'
import { useHistory } from 'react-router-dom'
import { getQueryString } from '../utils'
import axios from '../utils/axios'
const Detail = () => {
const [detail, setDetail] = useState({})
const history = useHistory()
const id = getQueryString('id')
useEffect(() => {
axios.get(`/detail/${id}`).then(({ data }) => {
if (data.length) {
setDetail(data[0])
}
})
}, [])
const deleteDiary = (id) => {
axios.post('/delete', { id }).then(({ data }) => {
// 删除成功之后,回到首页
history.push('/')
})
}
return (<div className='diary-detail'>
<NavBar
mode="light"
icon={<Icon type="left" />}
onLeftClick={() => history.goBack()}
rightContent={[
<Icon onClick={() => deleteDiary(detail.id)} key="0" type="cross-circle-o" />
]}
>{detail.title || ''}</NavBar>
<List renderHeader={() => `${detail.date} 晴天`} className="my-list">
<List.Item wrap>
{detail.content}
</List.Item>
</List>
</div>)
}
export default Detail
изменять статьи
Чтобы изменить статью, вам нужно только получить идентификатор статьи, а затем передать измененные параметры в интерфейс модификации.Сначала мы добавляем кнопку модификации на страницу сведений и открываем ее.src/Detail/index.jsx
, плюс кусок кода
<NavBar
mode="light"
icon={<Icon type="left" />}
onLeftClick={() => history.goBack()}
rightContent={[
<Icon style={{ marginRight: 10 }} onClick={() => deleteDiary(detail.id)} key="0" type="cross-circle-o" />,
<img onClick={() => history.push(`/edit?id=${detail.id}`)} style={{ width: 26 }} src="//s.weituibao.com/1578721957732/Edit.png" alt=""/>
]}
>{detail.title || ''}</NavBar>
Приведенный выше код добавляет тег img, щелкните, чтобы перейти на страницу редактирования, и, кстати, укажите соответствующий идентификатор. Мы можем получить детали через id на странице редактирования, назначить его переменной, а затем отредактировать, мы открываемsrc/Edit/index.jsx
страница:
import React, { useState, useEffect } from 'react'
import { List, InputItem, TextareaItem, DatePicker, ImagePicker, Button, Toast } from 'antd-mobile'
import moment from 'moment'
import axios from '../utils/axios'
import { getQueryString } from '../utils'
import './style.css'
const Edit = () => {
const [title, setTitle] = useState('')
const [content, setContent] = useState('')
const [date, setDate] = useState('')
const [files, setFile] = useState([])
const id = getQueryString('id')
const onChange = (files, type, index) => {
console.log(files, type, index);
setFile(files)
}
useEffect(() => {
if (id) {
axios.get(`/detail/${id}`).then(({ data }) => {
if (data.length) {
setTitle(data[0].title)
setContent(data[0].content)
setDate(new Date(data[0].date))
setFile([{ url: data[0].url }])
}
})
}
}, [])
const publish = () => {
if (!title || !content || !date) {
Toast.fail('请填写必要参数')
return
}
const params = {
title,
content,
date: moment(date).format('YYYY-MM-DD'),
url: files.length ? files[0].url : ''
}
if (id) {
params['id'] = id
axios.post('/update', params).then(res => {
Toast.success('修改成功')
})
return
}
axios.post('/add', params).then(res => {
Toast.success('添加成功')
})
}
return (<div className='diary-edit'>
<List renderHeader={() => '编辑日记'}>
<InputItem
clear
placeholder="请输入标题"
value={title}
onChange={(value) => setTitle(value)}
>标题</InputItem>
<TextareaItem
rows={6}
placeholder="请输入日记内容"
value={content}
onChange={(value) => setContent(value)}
/>
<DatePicker
mode="date"
title="请选择日期"
extra="请选择日期"
value={date}
onChange={date => setDate(date)}
>
<List.Item arrow="horizontal">日期</List.Item>
</DatePicker>
<ImagePicker
files={files}
onChange={onChange}
onImageClick={(index, fs) => console.log(index, fs)}
selectable={files.length < 1}
multiple={false}
/>
<Button type='primary' onClick={() => publish()}>发布</Button>
</List>
</div>)
}
export default Edit
После получения деталей они отображаются на странице ввода.
Интерфейсные и внутренние процессы всего проекта были пройдены.Хотя в базе данных есть только одна таблица, как программист, вы должны иметь возможность делать выводы о других вещах. Конечно, если вы хотите сделать проект более сложным, вам понадобится основа для проектирования базы данных.
Суммировать
В статье из 40 символов я увидел, что последний друг должен быть также человеком, который любит учиться и надеется улучшить себя. Пункты знаний, включенные в полный текст, могут быть относительно отрывочными, но все еще старая поговорка гласит, что мастер ведет дверь, а совершенствование зависит от человека. Другие хорошие статьи могут следовать за мнойличный блогхочу мойЗнай колонку. Если у вас есть какие-либо вопросы, вы можете добавить группу WeChat в мой личный блог, чтобы учиться и обсуждать. В этой длинной статье писали, что меня рвало кровью, надеюсь всем поможет.