后台管理系统vue.js步骤

这篇博客详细介绍了如何使用Vue.js构建一个后台管理系统,包括项目创建、清空工作、目录结构设置、使用stylus进行样式管理、一级路由配置、Header组件封装、导航方式、参数传递、axios数据交互、图片处理、用户注册与登录、轮播图、详情页、分类、购物车功能实现以及UI组件库Ant Design的应用。
摘要由CSDN通过智能技术生成

1.创建项目

create-react-app umall_app

2.清空工作

1.src删除除了App.js index.js 之外的所有的文件

2.App.js重置 (rfc)

3.index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

ReactDOM.render(
  <App />,
  document.getElementById('root')
);

3.目录

//1.assets 
import "./assets/css/reset.css"
import "./assets/js/rem"

//2.components 公共组件

// 3.pages 路由组件

// 4.filters 过滤器

// 5.utils/http.js ajax请求

// 6.store 

// 7.UI 框架

// 8.stylus 样式
react中使用stylus
1.安装stylus 依赖包
npm i stylus stylus-loader --save
2.package.json react-scripts版本号更改
“react-scripts:"3.2.0"
3.git 提交本地仓库
git add . 
git commit -m "123"
4.导出配置文件
npm run eject
5.配置stylus

reac使用stylus,先运行npm run eject,在wenpack.config.js文件,module.export->module->oneOf添加一下代码

        {   
            test: /\.styl$/,    
            use: [       
                  require.resolve('style-loader'),        
                  require.resolve('css-loader'),        
                  require.resolve('stylus-loader')    
         		] 
        },              
6.src/stylus
index.styl 整合css
color.styl color
size.styl 大小
form.styl form 

4.一级路由

1.创建相关组件

pages 下创建 login register index list detail

2.安装依赖包
npm i react-router-dom --save
3.路由模式 src/index.js
//配置路由模式 HashRouter:hash模式 BrowserRouter:history模式
import {HashRouter,BrowserRouter} from "react-router-dom"

ReactDOM.render(
  <HashRouter>
    <App />
  </HashRouter>
  ,
  document.getElementById('root')
);
4.路由出口 App.js Switch
import {Switch} from "react-router-dom"

export default function App() {
  return (
    <div>
      {/* 一级路由出口 */}
      <Switch>
       
      </Switch>
    </div>
  )
}

5.定义路由规则 App.js
import {Switch,Route,Redirect} from "react-router-dom"
 	<div>
      {/* 一级路由出口 */}
      <Switch>
        <Route path="/login" component={Login}></Route>
        <Route path="/register" component={Register}></Route>
        <Route path="/index" component={Index}></Route>
        <Route path="/detail" component={Detail}></Route>
        <Route path="/list" component={List}></Route>
        <Redirect to="/login"></Redirect>
      </Switch>
    </div>

5.封装了Header组件

1.pages/Header/Header.js

import React, { Component } from 'react'
import "./Header.styl"
export default class Header extends Component {
    render() {
        let { title, back, register } = this.props
        return (
            <div className="header">
                {back ? <span className="header-back">返回</span> : null}
                <div className="header-title">{title}</div>
                {register ? <span className="header-register">注册</span> : null}
            </div>
        )
    }
}

2.Header.styl

@import("../../stylus/index.styl");
.header
    width: 100vw 
    height $headerHeight
    position fixed
    left 0
    top: 0
    background: $primary
    .header-back
        position absolute 
        left 0
        top: 0
        margin-left: $margin
        font-size: $h2
        color: $font-fff
        line-height: $headerHeight
        z-index 2
    .header-title
        width: 100vw
        height: $headerHeight
        text-align: center 
        line-height: $headerHeight
        font-size: $h2
        color: $font-fff
        z-index: 1
    .header-register
        position absolute
        right: 0 
        top: 0 
        margin-right $margin
        font-size: $h2
        color: $font-fff
        line-height: $headerHeight
        z-index: 2

6.Index.js

1.底部导航
render() {
        return (
            <div className="index">
                {/* 二级路由出口 */}
                <Switch>
                    <Route path="/index/home" component={Home}></Route>
                    <Route path="/index/cate" component={Cate}></Route>
                    <Route path="/index/shop" component={Shop}></Route>
                    <Route path="/index/mine" component={Mine}></Route>
                    <Redirect to="/index/home"></Redirect>
                </Switch>
                <footer className="index-footer">
                    {/* 底部导航,NavLink有activeClassName,Link没有 */}
                    <NavLink to="/index/home" activeClassName="select">首页</NavLink>
                    <NavLink to="/index/cate" activeClassName="select">分类</NavLink>
                    <NavLink to="/index/shop" activeClassName="select">购物车</NavLink>
                    <NavLink to="/index/mine" activeClassName="select">我的</NavLink>
                </footer>
            </div>
        )
     }

7.导航的方式

1.组件导航

import { Link, NavLink } from "react-router-dom"
<Link to="/index/shop">购物车</Link>
<NavLink to="/index/shop">购物车</NavLink>
注意:NavLink有activeClassName,Link没有

2.编程式导航

this.props.history.push() //添加新的历史记录
this.props.history.replace()//是用新的记录替换当前历史记录
this.props.history.go(-1);//返回
路由组件可以直接使用编程式导航,非路由组件需要通过设置withRouter()
import { withRouter } from "react-router-dom"
class Nav {
    
}
export default withRouter(Nav)

8.list->detail 问号传参

1.src/pages/home/components/list/list.js

<div className="list">
            {
                goods.map(item=>{
                    return (
                        <Link to={"/detail?id="+item.id} className="list-item" key={item.id}>
                            <h3>{item.name}</h3>
                            <div className="btn">立即抢购</div>
                        </Link>
                    )
                })
            }
            
        </div>

2.detail.js 接收参数

import querystring from "querystring"
 componentDidMount(){
        let str=this.props.location.search;
    		//'?id=1&a=10&b=20&c=30'-->{id:"1",a:"10",b:"20",c:"30"}
        let result=querystring.parse(str.slice(1))
        console.log(result);
        //ajax

  }

9.axios

1.配置代理

package.json

{
	"proxy":"http://localhost:3000"
}
2.安装
cnpm i axios qs --save

10.图片

1.assets/img

import logo from "../../../../assets/img/logo.jpg"
export default function Info() {
    return (
        <div>
            <img src={logo} alt=""/>
        </div>
    )
}

注意:css不能用该图片。

如果要使用背景图,使用定位处理。

2.将图片放到服务器,使用网址

<img src="https://dss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=1301561917,1696120670&fm=26&gp=0.jpg" alt=""/>

这种路径可以作为背景图

3.vue中使用图片

<template>
<div>
    <img :src="logo" alt=""/>
</div>
</template>
<script>
import logo from "../../../../assets/img/logo.jpg"
export default {
    data(){
        return {
            logo:logo
        }
    }
</script>

11.注册

1.http.js

//注册
export const reqRegister = (user) => {
    return axios({
        url: "/api/register",
        method: "post",
        data: qs.stringify(user)
    })
}

2.register.js

export default class Register extends Component {
    constructor(){
        super()
        this.state={
            user:{
                phone:"",
                nickname:"",
                password:""
            }
        }
    }
    changeUser(e,key){
        this.setState({
            user:{
                ...this.state.user,
                [key]:e.target.value
            }
        })
    }
    submit(){
        reqRegister(this.state.user).then(res=>{
            if(res.data.code===200){
                successAlert(res.data.msg)
                this.props.history.push("/login")
            }
        })
    }
    render() {
        return (
            <div>
                <Header title="注册" back></Header>
                <div>手机号:<input type="text" onChange={(e)=>this.changeUser(e,"phone")}/></div>
                <div>昵称:<input type="text" onChange={(e)=>this.changeUser(e,"nickname")}/></div>
                <div>密码:<input type="text" onChange={(e)=>this.changeUser(e,"password")}/></div>
                <div className="btn" onClick={()=>this.submit()}>注册</div>
            </div>
        )
    }
}

3.utils/alert.js

export const successAlert = (msg) => {
    alert(msg)
}

4.统一处理失败请求 utils/http.js

axios.interceptors.response.use(res => {
    console.log("本次请求地址:" + res.config.url);
    console.log(res);
    //统一处理失败
    if (res.data.code !== 200) {
        successAlert(res.data.msg)
    }
    return res
})

12.登录

1.http.js

//登录
export const reqLogin = (user) => {
    return axios({
        url: "/api/login",
        method: "post",
        data: qs.stringify(user)
    })
}

2.login.js

export default class Login extends Component {
    constructor(){
        super()
        this.state={
            user:{
                phone:"",
                password:""
            }
        }
    }
    changeUser(e,key){
        this.setState({
            user:{
                ...this.state.user,
                [key]:e.target.value
            }
        })
    }
    login(){
        reqLogin(this.state.user).then(res=>{
            if(res.data.code===200){
                //弹成功
                successAlert(res.data.msg)
                //存用户信息
                sessionStorage.setItem("userInfo",JSON.stringify(res.data.list))
                //跳页面
                this.props.history.push("/index")
            }
        })
    }
    render() {
        return (
            <div>
                <Header title="登录" register></Header>
                <div>
                    账号:<input type="text"  onChange={(e)=>this.changeUser(e,"phone")}/>
                </div>
                <div>
                    密码:<input type="text" onChange={(e)=>this.changeUser(e,"password")}/>
                </div>
                <div className="btn" onClick={()=>this.login()}>登录</div>

                <Link to="/index">大首页</Link>
                <NavLink to="/index">大首页</NavLink>
            </div>
        )
    }
}

13.轮播图

1.http.js


//首页商品banner
export const reqHomeBanner = () => {
    return axios({
        url: "/api/getbanner",
        method: "get"
    })
}

2.Home.js 初始化数据

 this.state={
            //1.轮播图
            banner:[]
        }

3.发请求

componentDidMount(){
       
        // 2.发请求
        reqHomeBanner().then(res=>{
            this.setState({
                banner:res.data.list
            })
        })
    }

4.传递给banner组件

 <Banner banner={banner}></Banner>

14.详情页

1.http.js

//商品详情
export const reqDetail = (id) => {
    return axios({
        url: "/api/getgoodsinfo",
        method: "get",
        params:{
            id:id
        }
    })
}

2.detail.js

 constructor() {
        super()
        //1.初始化
        this.state = {
            detail: {}
        }

        this.des = React.createRef()
    }

3.发请求

 componentDidMount() {
        let str = this.props.location.search;//'?id=1&a=10&b=20&c=30'-->{id:"1",a:"10",b:"20",c:"30"}
        let result = querystring.parse(str.slice(1))

        //2.ajax
        reqDetail(result.id).then(res => {
            let list=res.data.list[0]
            list.specsattr=JSON.parse(list.specsattr)
            this.setState({
                detail: list
            },()=>{
                console.log(this.state.detail);
                this.des.current.innerHTML=this.state.detail.description
            })
            
        })

    }

4.展示数据

render() {
        let { detail } = this.state;
        return (
            <div>
                <Header title="商品详情" back></Header>
                {/* 图片 */}
                <img src={detail.img} alt="" />

                {/* 商品信息 */}
                {detail.goodsname ? <Info detail={detail}></Info> : null}

                {/* 商品描述 */}
                <div ref={this.des}></div>
            </div>
        )
    }

15.分类 Cate

1.静态页面

 <div>
                <Header title="分类"></Header>
                <div className="cate">
                    <div className="left">
                        {
                            data.map((item, index) => {
                                return <div onClick={() => this.changeN(index)} className={index === n ? 'select' : ''} key={item.id}>{item.catename}</div>
                            })
                        }
                    </div>
                    <div className="right">
                        {
                            rightList.map(item => {
                                return (
                                    <div className="item" key={item.id} onClick={()=>this.toList(item.catename,item.id)}>
                                        <div className="con">
                                            <img src={item.img} alt="" />
                                            <div>{item.catename}</div>
                                        </div>
                                    </div>
                                )
                            })
                        }
                    </div>
                </div>
            </div>

2.http.js

//分类
export const reqCate = () => {
    return axios({
        url: "/api/getcatetree",
        method: "get",
    })
}

3.初始化数据

constructor() {
        super()
        this.state = {
            data: [],
            n: 0
        }
    }

4.发请求

 componentDidMount() {
        reqCate().then(res => {
            this.setState({
                data: res.data.list
            })
        })
    }

5.页面展示

6.修改n

//修改n
    changeN(index) {
        this.setState({
            n: index
        })
    }

7.跳转到list

//跳转到list
    toList(name,id){
        this.props.history.push("/list/"+name+"/"+id)
    }

8.修改list的路由规则 (App.js)

<Route path="/list/:name/:id" component={List}></Route>

16.分类列表

1.http.js

//分类商品
export const reqCateGoods = (id) => {
    return axios({
        url: "/api/getgoods",
        method: "get",
        params:{
            fid:id
        }
    })
}

2.list.js

import List from "../Home/components/List/List"
export default class BigList extends Component {
    constructor() {
        super()
        this.state = {
            list: []
        }
    }
    componentDidMount() {
        reqCateGoods(this.props.match.params.id).then(res => {
            this.setState({
                list: res.data.list
            })
        })
    }
    render() {
        return (
            <div className="list">
                <Header back title={this.props.match.params.name}></Header>
                <List goods={this.state.list}></List>
            </div>
        )
    }
}

17.购物车

1.详情页 加入购物车

  1. detail.js弹框状态
this.state = {
            detail: {},
            //控制弹框的状态
            isshow: false
        }

2.点了 按钮,出现弹框


<div className="btn" onClick={() => this.show()}>加入购物车</div>
//弹框出现
    show() {
        this.setState({
            isshow: true
        })
    }
{/* 弹框 */}
{detail.goodsname && isshow ? <Picker detail={detail} hide={() => this.hide()}></Picker> : null}

3.picker 点击加入购物车

 //加入购物车
    add(){
        reqShopAdd({
            uid:JSON.parse(sessionStorage.getItem("userInfo")).uid,
            goodsid:this.props.detail.id,
            num:1
        }).then(res=>{
            if(res.data.code===200){
                successAlert(res.data.msg)
                this.props.hide()
            }
        })
    }

2.购物车 + - 删除 全选 反选 查看 shop.js 1-15

18.UI

ant design :PC端

https://ant.design/index-cn

ant design mobile :移动端

https://mobile.ant.design/index-cn

1.安装
npm install antd-mobile --save
2.public/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>
3.src/index.js 入口文件引入样式

// 7.UI 框架
import 'antd-mobile/dist/antd-mobile.css'; 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wx:a917107110

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值