【单页面博客从前端到后端】基于 DVA+ANTD 搭建博客前后台界面

在上篇文章我们已经搭建好了基础的开发环境,接下来会介绍如何引入 DVA 和 ANTD ,以及在引入过程中需要注意的问题。这里只会详细的书写部分组件,其他的组件都是大同小异。你可以在 github仓库 中找到这些组件。

博客的原型图

这里我简单的画了一个博客的轮廓图。这样在写组件的过程中有助于有个整体性的思路,不迷路…

添加目录结构

blog 
├─ dist           # 输出目录
├─ task           # 这里来放webpack处理和配置文件
├─ src
|  ├─ assets      # 静态文件文件夹
|  ├─ components  # 组件
|  |  ├─ Home     # Home 页面的文件夹
|  |  ├─ Archive 
|  |  ├─ About
|  |  ├─ Admin    # 后台界面文件夹
|  |  ├─ Header.js    # 公共的 Header 组件
|  |  ├─ Footer.js    # 公共的 Footer 组件
|  |  ├─ UserCard.js  # 公共的 UserCard 组件
|  |  ├─ Login.js     # 公共的 Login 组件
|  ├─ containers  # Redux 的容器组件
|  |  ├─ Home.js      # Home 组件的容器
|  |  ├─ Archive.js
|  |  ├─ About.js
|  |  ├─ Admin        # 后台各界面的容器文件夹
|  ├─ router.js   # React 路由
|  └ index.js     # 入口文件
| package.json

引入 DVA 和 ANTD

DVA 的简单引入

Lightweight front-end framework based on redux,redux-saga and react-router@2.x. (Inspired by elm and choo)

要知道 dva 是对 redux,redux-saga,react-router 的封装,使用上有点像 express.js ,那么你就要多少对他们有所了解,dvagithub 仓库 有详细的入门指南、概念和示例,可以先去了解一下 。

更改入口文件 src/index.js

import dva from 'dva'
const app = dva()

app.router(require('./router'))
app.start('#root')

新建路由文件 src/router.js

import React from 'react'
import { Router,Route,IndexRoute,IndexRedirect } from 'dva/router'

import AppLayout from './container/App'
import Home from './container/Home'
import Archive from './container/Archive'
import About from './container/About'
import Article from './container/Article'
import AdminArticles from './container/Admin/Articles'
import AdminKeywrods from './container/Admin/Keywords'
import AdminEditor from './container/Admin/Editor'
import AdminLayout from './container/Admin/Admin'

export default ({history,app}) => {
    return (
        <Router history={history}>
            <Route path="/" component={AppLayout}>
                <IndexRoute component={Home} />
                <Route path="archive" component={Archive} />
                <Route path="about" component={About} />
                <Route path="article/:id" component={Article} />
                <Route path="admin" component={AdminLayout}>
                    <IndexRedirect to="articles" />
                    <Route path="articles" component={AdminArticles} />
                    <Route path="keywords" component={AdminKeywrods} />
                    <Route path="editor" component={AdminEditor} />
                </Route>
            </Route>
        </Router>
    )
}

从这里可以看出, dva 自己在内部引入 react-router-redux ,然后使用 react-router-redux 提供的 combineReducers routerRedux 合并到用户的 reducers

限于文章的篇幅,dvamodel 的设计会放到下一次的文章来描述

引入 ANTD

按需加载

在引入 ANTD 之前,我们先来实现 按需加载 。其实概念很简单,就是我们在引入一个样式库的时候,往往只会用到这个样式库的部分组件,但是工具会把整个组件库都打包到我们的项目中,这是我们不想看到的。按需加载 就是用来打包我们引入的组件,可以使用 babel-plugin-import 来具体实现。

task/config.jsbabel-loader 的 plugins 配置中添加:
["import",{ "libraryName": "antd","style": true }]

自定义主题

由脚手架 atool-build官网介绍,我们已经自己配置并新建好了主题文件 theme.js

添加 less-loader 处理样式文件

上节我们只是添加了对 .module.less 文件进行编译,在自定义主题时,需要对 less 变量进行覆盖,所以要求 babel-plugin-importstyle 选项设置为 true ,让它导出 antd 组件的 .less 样式文件才能进行变量覆盖操作。

task/config.jsmodule.rules 追加

{
    test: function(path){
        return /\.less$/.test(path) && !/\.module\.less$/.test(path)
    },loader: ExtractTextPlugin.extract({
        fallback: 'style-loader',use: [
            {
                loader: 'css-loader',},{
                loader: 'postcss-loader',options: {
                    plugins: postcssPlugins
                }
            },{
                loader: 'less-loader',options: {"modifyVars": theme}
            }
        ]
    })
},

注意 /\.less/ 至少会匹配到 .module.less.less 文件,所以要排除 .module.less ,因为它需要被 css-module 处理。

你也可能会通过添加 exclude,include 来对样式库中的 less 文件和自己编写的文件进行区别,毕竟样式库肯定都是从 node_modules 目录中加载,而自己的是从 src 目录下加载的。也正因为样式库是从 node_modules 目录下加载的,所以这样做可能会导致降低 webpack 的编译速度。

添加容器组件和展示组件

容器组件

/src/containers 下新建 App.js

import React,{ PropTypes } from 'react'
import { connect } from 'dva'
import { Layout,Menu,Breadcrumb,Row,Col,Icon } from 'antd'
import HeaderComponent from 'components/Header'
import FooterComponent from 'components/Footer'
import LoginModel from 'components/Login'
const { Header,Content,Footer } = Layout

const App = ({children,routes}) => {
    return (
        <Layout>
            <Header>
                <HeaderComponent routes={routes}>
                    <LoginModel doLogin={() => {}} />
                </HeaderComponent>
            </Header>
            <Content style={{ margin: '24px 100px 0',background: '#fff',minHeight: 280,overflow: 'hidden' }}>
                {children}
            </Content>
            <Footer>
                <FooterComponent />
            </Footer>
        </Layout>
    )
}

export default connect()(App)

因为 dva 封装了 redux源文件 中也是直接导出 react-reduxconnect 方法。所以在创建容器组件的时候还是等同于 react-redux

注意,这个 App组件是作为子路由组件的父组件,即 children 代表的就是那些子组件 Home,Archive

其他的展示组件,即 /src/containers 文件夹下面的组件,都是大同小异,就不一一赘述。

展示组件

我们看到 src/container/App.js 展示组件,引入了一个 HeaderComponent ,在 src/components 下面新建一个 Header.js

import React from 'react'
import { Layout,Col } from 'antd'
import { Router,Link } from 'dva/router'

const HeaderComponent = (props) => {
    const { children,routes } = props
    const routePath = (routes[routes.length - 1] || {}).path || '/'
    return (
        <div>
            <Row>
                <Col span={16}>
                    <Menu
                        mode="horizontal"
                        defaultSelectedKeys={[routePath]}
                        style={{ lineHeight: '64px',backgroundColor: 'transparent' }}
                    >
                        <Menu.Item key="/"><Link to="/">Home</Link></Menu.Item>
                        <Menu.Item key="archive"><Link to="archive">Archive</Link></Menu.Item>
                        <Menu.Item key="about"><Link to="about">About me</Link></Menu.Item>
                    </Menu>
                </Col>
                <Col span={8}>
                    <div style={{ lineHeight: '64px',float: 'right',padding: '0 20px' }}>
                        {children}
                    </div>
                </Col>
            </Row>
        </div>
    )
}

export default HeaderComponent

这就是个普通的 React 的展示组件没什么好说的,这些组件可以直接在 Antd 的官网上找到用法,而且都有示例代码。

const routePath = (routes[routes.length - 1] || {}).path || '/'
找到路由路径中的最后一个名称,如 /home 中的 home ,作为 Menu 的默认选中项,这样在当前页面刷新,就可以让当前页面对应的导航高亮。

其他的展示型组件也都是大同小异,你可以在 github仓库 中找到它们的实现。

引入 url-loader 来处理文件路径

task/config.js 中的 module.rules 追加:

{
    test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,loader: 'url-loader',options: {
        limit: 10000,name: 'img/[name].[hash:7].[ext]'
    }
},{
    test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,name: 'fonts/[name].[hash:7].[ext]'
    }
},

关于 url-loader 的配置方法,可以在 webpack 的文档中查看

小结

这篇文章主要是引入了两个重要的库 dvaantd ,以及编写部分展示组件。接下来,我们会对 dva 的数据层,已经后台初步搭建,同步进行前后端的开发。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如果组件之中有复用的代码,需要重新创建一个父类,父类中存储公共代码,返回子类,同时把公用属性...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例如我们的 setState 函数式同步执行的,我们的事件处理直接绑定在了 dom 元素上,这些都跟 re...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom 转为真实 dom 进行挂载。其实函数是组件和类组件也是在这个基础上包裹了一层,一个是调...
react 本身提供了克隆组件的方法,但是平时开发中可能很少使用,可能是不了解。我公司的项目就没有使用,但是在很多三方库中都有使用。本小节我们来学习下如果使用该...
mobx 是一个简单可扩展的状态管理库,中文官网链接。小编在接触 react 就一直使用 mobx 库,上手简单不复杂。
我们在平常的开发中不可避免的会有很多列表渲染逻辑,在 pc 端可以使用分页进行渲染数限制,在移动端可以使用下拉加载更多。但是对于大量的列表渲染,特别像有实时数据...
本小节开始前,我们先答复下一个同学的问题。上一小节发布后,有小伙伴后台来信问到:‘小编你只讲了类组件中怎么使用 ref,那在函数式组件中怎么使用呢?’。确实我们...
上一小节我们了解了固定高度的滚动列表实现,因为是固定高度所以容器总高度和每个元素的 size、offset 很容易得到,这种场景也适合我们常见的大部分场景,例如...
上一小节我们处理了 setState 的批量更新机制,但是我们有两个遗漏点,一个是源码中的 setState 可以传入函数,同时 setState 可以传入第二...
我们知道 react 进行页面渲染或者刷新的时候,会从根节点到子节点全部执行一遍,即使子组件中没有状态的改变,也会执行。这就造成了性能不必要的浪费。之前我们了解...
在平时工作中的某些场景下,你可能想在整个组件树中传递数据,但却不想手动地通过 props 属性在每一层传递属性,contextAPI 应用而生。
楼主最近入职新单位了,恰好新单位使用的技术栈是 react,因为之前一直进行的是 vue2/vue3 和小程序开发,对于这些技术栈实现机制也有一些了解,最少面试...
我们上一节了了解了函数式组件和类组件的处理方式,本质就是处理基于 babel 处理后的 type 类型,最后还是要处理虚拟 dom。本小节我们学习下组件的更新机...
前面几节我们学习了解了 react 的渲染机制和生命周期,本节我们正式进入基本面试必考的核心地带 -- diff 算法,了解如何优化和复用 dom 操作的,还有...
我们在之前已经学习过 react 生命周期,但是在 16 版本中 will 类的生命周期进行了废除,虽然依然可以用,但是需要加上 UNSAFE 开头,表示是不安...
上一小节我们学习了 react 中类组件的优化方式,对于 hooks 为主流的函数式编程,react 也提供了优化方式 memo 方法,本小节我们来了解下它的用...
开源不易,感谢你的支持,❤ star me if you like concent ^_^
hel-micro,模块联邦sdk化,免构建、热更新、工具链无关的微模块方案 ,欢迎关注与了解
本文主题围绕concent的setup和react的五把钩子来展开,既然提到了setup就离不开composition api这个关键词,准确的说setup是由...
ReactsetState的执行是异步还是同步官方文档是这么说的setState()doesnotalwaysimmediatelyupdatethecomponent.Itmaybatchordefertheupdateuntillater.Thismakesreadingthis.staterightaftercallingsetState()apotentialpitfall.Instead,usecom