From 5910b2f56009f2271a386c770e52e2cededca8e9 Mon Sep 17 00:00:00 2001 From: wzhqwq Date: Sun, 10 Oct 2021 23:16:19 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E4=B8=BB=E9=A1=B5=E7=9A=84?= =?UTF-8?q?=E5=BE=AE=E5=8D=9A=E5=8C=96=E6=94=B9=E9=80=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ImagePreview/ImagePreview.css | 8 ++ src/components/ImagePreview/ImagePreview.js | 69 ++++++++++++++++ src/components/Spinner/spinner.css | 8 ++ src/helper/axios.js | 3 +- src/index/index.css | 85 +++++++++++--------- src/index/index.js | 70 +++++++--------- 6 files changed, 161 insertions(+), 82 deletions(-) create mode 100644 src/components/ImagePreview/ImagePreview.css create mode 100644 src/components/ImagePreview/ImagePreview.js diff --git a/src/components/ImagePreview/ImagePreview.css b/src/components/ImagePreview/ImagePreview.css new file mode 100644 index 0000000..02c5342 --- /dev/null +++ b/src/components/ImagePreview/ImagePreview.css @@ -0,0 +1,8 @@ +.preview { + width: 200px; + height: 200px; +} +.preview > img { + height: 200px; + cursor: zoom-in; +} \ No newline at end of file diff --git a/src/components/ImagePreview/ImagePreview.js b/src/components/ImagePreview/ImagePreview.js new file mode 100644 index 0000000..705399c --- /dev/null +++ b/src/components/ImagePreview/ImagePreview.js @@ -0,0 +1,69 @@ +import './ImagePreview.css'; + +import { useCallback, useRef, useState, useEffect, Fragment } from 'react'; +import Spinner from '../Spinner/Spinner'; + +export default function ImagePreview({ image }) { + const [isScaled, setIsScaled] = useState(false); + const [transform, setTransform] = useState(''); + const imgRef = useRef(null); + const [loading, setLoading] = useState(false); + const imgWidth = useRef(0), imgHeight = useRef(0); + + useEffect(() => { + setLoading(true); + let img = new Image(); + img.onload = () => { + setLoading(false); + imgWidth.current = img.width; + imgHeight.current = img.height; + }; + img.src = image; + }, [image]); + + const scale = useCallback(() => { + if (isScaled) return; + let el = imgRef.current; + let { x, y } = el.getBoundingClientRect(); + let { innerWidth, innerHeight } = window; + let initialScale = 200 / imgHeight.current, + terminalScale = Math.min(1, Math.min((innerWidth - 10) / imgWidth.current, (innerHeight - 10) / imgHeight.current)); + setTransform(`translate(${x + (imgWidth.current * initialScale - innerWidth) / 2}px, ${y + (200 - innerHeight) / 2}px) scale(${initialScale})`); + setIsScaled(true); + setTimeout(() => { + setTransform(`translate(0, 0) scale(${terminalScale})`); + }, 0); + }, [isScaled]); + + const unscale = useCallback(() => { + if (!isScaled) return; + let el = imgRef.current; + let { x, y } = el.getBoundingClientRect(); + let { innerWidth, innerHeight } = window; + let initialScale = 200 / imgHeight.current; + setTransform(`translate(${x + (imgWidth.current * initialScale - innerWidth) / 2}px, ${y + (200 - innerHeight) / 2}px) scale(${initialScale})`); + setIsScaled(true); + setTimeout(() => { + setIsScaled(false); + }, 300); + }, [isScaled]); + + return ( +
+ { + loading ? ( +
+ +
+ ) : ( + + 图片 +
+ 图片 +
+
+ ) + } +
+ ); +} \ No newline at end of file diff --git a/src/components/Spinner/spinner.css b/src/components/Spinner/spinner.css index 92481c2..ad430c3 100644 --- a/src/components/Spinner/spinner.css +++ b/src/components/Spinner/spinner.css @@ -9,6 +9,14 @@ animation: spin 1s steps(8, start) infinite; } +.spinner-wrap { + width: 100%; + height: 100%; + display: flex; + justify-content: center; + align-items: center; +} + @keyframes spin { from { transform: rotate(0deg); diff --git a/src/helper/axios.js b/src/helper/axios.js index 1f326c9..32d6f44 100644 --- a/src/helper/axios.js +++ b/src/helper/axios.js @@ -84,8 +84,9 @@ async function send(xhr, retryConf) { return failData; } - if (!waitToSend.length) return failData; + if (waitToSend.length) return failData; waitToSend.push(retryConf); + console.log(err); // 等待列表不为空时弹框要么出现了要么就是在消失的路上,没有办法给予用户点击重试的机会,所以交由外部逻辑处理 // 注意,理论上带有时间戳的请求是不可以重试的,但是这里不做那方面考虑,如果未来有需要,可以自己实现一个刷新时间戳重试的逻辑 diff --git a/src/index/index.css b/src/index/index.css index eab8d65..f70d343 100644 --- a/src/index/index.css +++ b/src/index/index.css @@ -1,15 +1,20 @@ +.index-container { + background-color: #F4F4F4; + min-height: 100vh; +} + .poster { width: 100%; height: 400px; background-color: #84000B; + background-position: center; + background-size: contain; + background-repeat: no-repeat; display: flex; flex-direction: column; align-items: center; position: relative; } -.img-poster { - height: 100%; -} .index-btns { position: absolute; right: 40px; @@ -20,7 +25,6 @@ .index-btns > .user { margin-right: 10px; } -/* 这里的卡片和分栏结构就比较接近bootstrap了,可惜视觉做的太古板,如果愿意的话改成Material Design就更好了 */ .split-lg > .card { width: 440px; flex-shrink: 0; @@ -29,7 +33,7 @@ .card-header { padding: .5em; font-size: 20px; - border-bottom: 1px solid #e6e6e6; + font-weight: bold; } .card-body { padding: 10px 5px; @@ -41,42 +45,47 @@ flex-wrap: wrap; } -.img-list { - width: 100%; - display: flex; - flex-wrap: wrap; - margin: -3px -5px; - align-items: flex-start; -} -.img-list > img { - width: 200px; - margin: 3px 5px; -} - -.message-list { - margin: 0; - padding-left: 0; - list-style: none; -} -.message-list > li { - line-height: 20px; - padding: 8px 0; - position: relative; -} -/* list disk */ -.message-list > li::before { - content: ""; - width: 8px; - height: 8px; - background-color: #DADADA; - margin-right: 10px; - border-radius: 50%; - display: inline-block; -} - @media (max-width: 980px) { .split-lg > .card { width: 100%; margin-bottom: 20px; } +} + +.posts { + +} +.post { + padding: 10px; + border-radius: 12px; + background-color: white; + margin-bottom: 10px; + box-shadow: 2px 2px 4px #0001; +} +.post > p { + padding-left: 40px; +} +.post-header { + padding: 5px; + display: flex; + align-items: center; + border-bottom: 1px solid #eee; +} +.post-body { + padding: 5px; +} +.post-avatar { + width: 40px; + height: 40px; + border-radius: 20px; + margin-right: 10px; +} +.post-username { +} +.post-time { + color: #888; +} +.post-image { + width: 200px; + height: 200px; } \ No newline at end of file diff --git a/src/index/index.js b/src/index/index.js index 17972c8..341dd87 100644 --- a/src/index/index.js +++ b/src/index/index.js @@ -1,4 +1,5 @@ import { Component } from 'react'; +import ImagePreview from '../components/ImagePreview/ImagePreview'; import { Link } from '../components/SingleRouter/SingleRouter'; import Spinner from '../components/Spinner/Spinner'; import UserControl from '../components/UserControl/UserControl'; @@ -12,8 +13,7 @@ export class AppContainer extends Component { constructor(props) { super(props); this.state = { - essentialMessages: [], - essentialImages: [], + posts: [], fetchingEssential: false, }; } @@ -25,26 +25,20 @@ export class AppContainer extends Component { this.setState({ fetchingEssential: false }); if (networkStatus !== 200) return; if (!status) return alert('获取精选列表失败:' + data + ',请刷新重试'); - let messages = [], images = []; - data.forEach(post => { - if (post.content) messages.push(post.content); - if (post.image) images.push(post.image); - }); - this.setState({ essentialMessages: messages, essentialImages: images }); + this.setState({ posts: data }); }); } render() { return (
-
- 海报 +
点击参加
-
+
精选留言 @@ -56,43 +50,33 @@ export class AppContainer extends Component {
) : ( - this.state.essentialMessages.length === 0 + this.state.posts.length === 0 ? (
暂时没有精选留言
) : ( -
    +
    { - this.state.essentialMessages.map((msg, i) => ( -
  • - )) - } -
- ) - ) - } -
-
-
-
- 精选图片 -
-
- { - this.state.fetchingEssential - ? ( -
- ) - : ( - this.state.essentialImages.length === 0 - ? ( -
暂时没有精选图片
- ) - : ( -
- { - this.state.essentialImages.map((src, i) => ( - 精选图片 + this.state.posts.map((post, i) => ( +
+
+ 头像 +
+
{post.realName}
+
于{new Date(post.time * 1000).toLocaleString()}发布
+
+
+
+

+ { + post.image && ( +
+ +
+ ) + } +
+
)) }