Layout布局,侧边栏,引入echarts

父组件

import React,{useState,useEffect} from 'react'
import './Home.scss'
import { Input } from 'antd-mobile'
import {MailOutlined,CheckCircleOutlined ,PlusOutlined,
    DownloadOutlined,DeleteOutlined,BorderlessTableOutlined } from '@ant-design/icons';
import {  Menu} from 'antd';


import { Outlet, useNavigate} from 'react-router-dom'



export default function Home(props) {
  const navigate=useNavigate()
  const [value, setValue] = useState('')
  
  function getItem(label, key, icon, children) {
    return {
      key,
      icon,
      children,
      label,
    };
  }
  const items = [
    getItem('我的图', '/chart', <MailOutlined />),
    getItem('我的任务', '/list', <CheckCircleOutlined />),
    getItem('已归档', '3', <DownloadOutlined />),
    getItem('回收站', '4', <DeleteOutlined />),
  ];
  const items2 = [
    getItem('我指派给他人的项目', '1', <BorderlessTableOutlined />),
    getItem('我创建的任务', '2', <BorderlessTableOutlined />),
    getItem('我参与的任务', '3', <BorderlessTableOutlined />),
    getItem('添加捷径', 'add', <PlusOutlined />),
  ];

  return (
    <div className='container'>
        <div className="left">
            <div className="title">
                <h2>项目</h2>
            </div>
            <div className='input'>
                <Input
                    placeholder='搜索项目或任务'
                    value={value}
                    onChange={val => {
                        setValue(val)
                    }}
                    style={{background:'#eee',height:'45px',borderRadius:'8px'}}
                />
            </div>
            <div className="tab1">
                <Menu
                    style={{
                    width: 256,
                    border:'0'
                    }}
                    defaultSelectedKeys={['/chart']}
                    // defaultOpenKeys={['sub1']}
                    // mode={mode}
                    theme='light'
                    items={items}
                    onSelect={(key)=>navigate(key.key)}
                />
            </div>
            <div className="tab2">
                <div className='title'>
                    <h3>捷径</h3>
                    <h3>+</h3>
                </div>
                <Menu
                    style={{
                    width: 256,
                    border:'0'
                    }}
                    defaultSelectedKeys={['add']}
                    // defaultOpenKeys={['sub1']}
                    // mode={mode}
                    theme='light'
                    items={items2}
                />
            </div>


        </div>
        <div id="right">
          <Outlet></Outlet>
          

        </div>

    </div>
  )
}




.container{
    width: 100%;
    height: 100%;
    display: flex;
    .left{
        width: 20%;
        border-right: 1px solid #eee;
        padding: 20px 25px;
        box-sizing: border-box;
        .input{
            margin-top: 30px;
        }
        .tab1{
            margin-top: 20px;
        }
        .tab2{
            margin-top: 20px;
            .title{
                padding: 10px 10px;
                box-sizing: border-box;
                display: flex;
                justify-content: space-between;
            }

        }

    }
    #right{
        flex:1;
    }
}

子组件-echarts

import React,{useState,useEffect} from 'react'
import echarts from 'echarts/lib/echarts';
import 'echarts/lib/component/tooltip';
import 'echarts/lib/component/title';
import 'echarts/lib/component/legend'
import 'echarts/lib/chart/pie';
export default function Echarts() {
  
  let [main, setMain] = useState('')
  const option = {
    title: {
      text: '某站点用户访问来源',
      subtext: '纯属虚构',
      left: 'center'
    },
    tooltip: {
      trigger: 'item',
      formatter: '{a} <br/>{b} : {c} ({d}%)'
    },
    legend: {
      orient: 'vertical',
      left: 'left',
      data: ['直接访问', '邮件营销', '联盟广告', '视频广告', '搜索引擎']
    },
    series: [
      {
        name: '访问来源',
        type: 'pie',
        radius: '55%',
        center: ['50%', '60%'],
        data: [
          { value: 335, name: '直接访问' },
          { value: 310, name: '邮件营销' },
          { value: 234, name: '联盟广告' },
          { value: 135, name: '视频广告' },
          { value: 1548, name: '搜索引擎' }
        ],
        emphasis: {
          itemStyle: {
            shadowBlur: 10,
            shadowOffsetX: 0,
            shadowColor: 'rgba(0, 0, 0, 0.5)'
          }
        }
      }
    ]
  };
  useEffect(() => {
    var node = document.getElementById('main')
    setMain(node)
  }, [main])
  if (main !== "") {
    var myChart = echarts.init(main);
    myChart.setOption(option);
  }
  return (
    <div style={{ height: "500px", width: "600px" }} id='main'></div>
  )
}

子组件---2

import React,{useState} from 'react'
import './List.scss'
import { Input } from 'antd-mobile'
export default function List() {
  const [value, setValue] = useState('')
  const [flag,setFlag]=useState(false)
  const [list,setlist]=useState([])
  const [flag2,setFlag2]=useState(false)
  function sub(){
    let obj={
      id:list.length+1,
      checked:false,
      title:value
    }
    let arr=[...list]
    arr.push(obj)
    setlist(arr)
    setValue('')
  }

  function changeState(id){
    let idx=list.findIndex(item=>item.id==id)
    if(idx>-1){
      let arr=[...list]
      arr[idx].checked=!arr[idx].checked
      setlist(arr)
    }
  }

  function del(id){
    let idx=list.findIndex(item=>item.id==id)
    if(idx>-1){
      let arr=[...list]
      arr.splice(idx,1)
      setlist(arr)
    }
  }
  

  function changeContent(e,id){
    console.log(111);
    console.log(e,'eeeeeeee');
    let idx=list.findIndex(item=>item.id==id)
    if(idx>-1){
      let arr=[...list]
      arr[idx].title=e.target.value
      setlist(arr)
      console.log(arr,'arr');
    } 
  }


  function int(ev){
    if(ev.keyCode==13){
      setFlag2(false)
    }
  }

  return (
    <div className='list'>
      <div className="top">
        <h3>我的任务</h3>
        <div></div>
        

        
      </div>
      <div className='input'>
          
          <input type="text" placeholder='你想做点什么?'
            value={value}
            onClick={()=> setFlag(!flag)}
            onChange={(e)=>setValue(e.target.value)}
            
          />
           
     
      </div>
      {
        flag?<div className="btn"><button className={value==''?'obtn':'nbtn'} onClick={sub}>新建</button></div>:<></>
      } 

      <div className="list">
          <div className="item1">
            {
              list.filter(i=>i.checked==false).map(item=><div className="item11" key={item.id}>
              <input type="checkbox" checked={item.checked} onChange={()=>{changeState(item.id)}}/>
              <div>
                
                 
                {/* div和input切换 */}
                {
                  flag2==false?(
                    <div onClick={()=>setFlag2(!flag2)}>{item.title}</div>
                  ):(
                  <div>
                    <input type="text" value={item.title} 
                    onChange={(ev)=>{changeContent(ev,item.id)}}
                    onKeyDown={(ev)=>{int(ev)}}
                    />
                  </div>
                  )
                }
                
              </div>
              <button onClick={()=>{del(item.id)}}>删除</button>
            </div>)
            }
            
          </div>
          <div className="item1">
            {
              list.filter(i=>i.checked).length>0?
              <div>
                <div>已完成</div>
                {
                  list.filter(i=>i.checked).map(item=><div className="item11" key={item.id}>
                  <input type="checkbox" checked={item.checked} onChange={()=>{changeState(item.id)}}/>
                  <div>{item.title}</div>
                </div>)
                }
              </div>:<></>
            }
            
            
          </div>

        </div>


    </div>
  )
}




.list{
    width:'100%';
    height:'100%';
    .top{
        height: 50px;
        line-height: 50px;
        display: flex;
        h3{
            margin-left: 200px;
        }   
    }

    .input{
        padding: 10px 200px;
        box-sizing: border-box;
        height: 60px;

        input{
            width: 99.5%;
            height: 100%;
            border-radius:5px ;
        }
    }

    .btn{
        height: 70px;
        line-height: 70px;
        .obtn{
            margin-left: 475px;
            height: 25px;
            width: 120px;
            border: 0;
            background: #929292;
            color: #fff;
        }

        .nbtn{
            margin-left: 475px;
            height: 25px;
            width: 120px;
            border: 0;
            background: #3287db;
            color: #fff;
        }
    }

    .list{
        padding: 10px 200px;
        box-sizing: border-box;
        .item1{
            .item11{
                display: flex;
                height: 50px;
                div{
                    width: 540px;
                    height: 100%;
                    line-height: 50px;
                    
                }
                button{
                    color: #3287db;
                    border: 0;
                    background-color: #fff;
                }
            }

        }

    }
}

### 动态路由与侧边栏菜单的实现 在 Vue 和 React 中,通过 `layout` 布局可以轻松实现带有动态路由的侧边栏菜单。以下是两种框架的具体实现方式。 #### Vue 实现方案 在 Vue 项目中,可以通过组合 `router-view` 和自定义组件来构建带侧边栏布局结构。具体方法如下: 1. **创建 Layout 组件** 创建一个名为 `Layout.vue` 的文件作为全局布局容器,其中包含顶部导航和侧边栏区域。 ```vue <template> <div class="container"> <aside> <!-- Side Menu --> <ul> <li v-for="(route, index) in routes" :key="index"> <router-link :to="route.path">{{ route.name }}</router-link> </li> </ul> </aside> <main> <router-view></router-view> <!-- 渲染子路由位置 --> </main> </div> </template> <script> export default { data() { return { routes: [ { path: '/home', name: 'Home' }, { path: '/about', name: 'About' } ] }; } }; </script> ``` 2. **配置 Router 文件** 在 `router/index.js` 或类似的路由配置文件中设置嵌套路由,指定默认渲染的父级组件为 `Layout`. ```javascript import { createRouter, createWebHistory } from 'vue-router'; import Layout from '@/components/Layout.vue'; import Home from '@/views/Home.vue'; import About from '@/views/About.vue'; const routes = [ { path: '/', component: Layout, children: [ { path: '', redirect: '/home' }, // 默认重定向到 /home { path: 'home', component: Home }, { path: 'about', component: About } ] } ]; const router = createRouter({ history: createWebHistory(), routes }); export default router; ``` 上述代码实现了基于 `Layout` 的动态路由加载机制[^1]。 --- #### React 实现方案 React 使用 `react-router-dom` 来管理路由,并结合状态管理和条件渲染完成类似的功能。 1. **安装依赖** 安装必要的库: ```bash npm install react-router-dom ``` 2. **创建 Layout 组件** 构建一个通用的 `Layout` 组件用于包裹页面内容并显示侧边栏。 ```jsx import React from 'react'; import { BrowserRouter as Router, Route, Link, Switch } from 'react-router-dom'; function Sidebar({ routes }) { return ( <nav> <ul> {routes.map((route, idx) => ( <li key={idx}> <Link to={route.path}>{route.name}</Link> </li> ))} </ul> </nav> ); } function AppLayout({ routes }) { return ( <Router> <div className="app-container"> <Sidebar routes={routes} /> <Switch> {routes.map(({ path, Component }, idx) => ( <Route exact key={idx} path={path} component={Component} /> ))} </Switch> </div> </Router> ); } export default AppLayout; ``` 3. **配置路由数据** 将所有的路由路径集中存储在一个数组中以便于维护。 ```javascript const appRoutes = [ { path: '/', name: 'Dashboard', Component: () => <h1>Dashboard</h1> }, { path: '/settings', name: 'Settings', Component: () => <h1>Settings</h1> } ]; ``` 4. **应用入口** 在主程序入口引入 `AppLayout` 并传递路由表。 ```jsx import React from 'react'; import ReactDOM from 'react-dom'; import AppLayout from './AppLayout'; const appRoutes = [ { path: '/', name: 'Dashboard', Component: () => <h1>Dashboard</h1> }, { path: '/settings', name: 'Settings', Component: () => <h1>Settings</h1> } ]; ReactDOM.render(<AppLayout routes={appRoutes} />, document.getElementById('root')); ``` 此设计模式允许开发者灵活扩展新的路由项而无需修改核心逻辑[^2]。 --- ### 总结 无论是 Vue 还是 React,在实际开发过程中都可以借助各自的路由工具包快速搭建支持动态路由切换的侧边栏菜单系统。Vue 更倾向于声明式的模板语法配合 JavaScript 配置;而 React 则强调函数式编程风格以及 JSX 表达力强的特点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值