初探create-react-app

230 阅读11分钟

1.创建项目

npx create-react-app my-app

2.将webpack配置提取出来

npm eject

3.删除src文件下除了index.js app.js 的所有文件

4.配置less,

1.安装less

npm i less less-loader --save-dev

2.在webpack.config文件里面添加

const cssRegex = /\.css$/;
const cssModuleRegex = /\.module\.css$/;
const sassRegex = /\.(scss|sass)$/;
const sassModuleRegex = /\.module\.(scss|sass)$/;

// 添加下面两行
const lessRegex = /\.(less)$/;
const lessModuleRegex = /\.module\.less$/;

3.接着配置loader,同样我们找到sass相关的写法,在后面添加:

 {
    test: sassModuleRegex,
    use: getStyleLoaders(
      {
        importLoaders: 3,
        sourceMap: isEnvProduction
          ? shouldUseSourceMap
          : isEnvDevelopment,
        modules: {
          getLocalIdent: getCSSModuleLocalIdent,
        },
      },
      'sass-loader'
    ),
  },
  // 添加 less 相关配置
  {
    test: lessRegex,
    exclude: lessModuleRegex,
    use: getStyleLoaders(
      {
        importLoaders: 2,
        sourceMap: isEnvProduction && shouldUseSourceMap,
        modules: {
          // getLocalIdent: getCSSModuleLocalIdent,
          localIdentName: '[local]_[hash:base64:5]'
        },
      },
      'less-loader'
    ),
    // Don't consider CSS imports dead code even if the
    // containing package claims to have no side effects.
    // Remove this when webpack adds a warning or an error for this.
    // See <https://github.com/webpack/webpack/issues/6571>
    sideEffects: true,
  },
  // Adds support for CSS Modules, but using LESS
  // using the extension .module.less or .module.less
  {
    test: lessModuleRegex,
    use: getStyleLoaders(
      {
        importLoaders: 2,
        sourceMap: isEnvProduction && shouldUseSourceMap,
        modules: {
          // getLocalIdent: getCSSModuleLocalIdent,
          localIdentName: '[local]_[hash:base64:5]'
        },
      },
      'less-loader'
    ),
  },
...

5.在src下添加global.less,并引入app.js

/* stylelint-disable selector-pseudo-element-colon-notation */
/* stylelint-disable rule-empty-line-before */
h1,
h2,
h6,
p,
th,
td {
  margin: 0;
  padding: 0;
}

a {
  text-decoration: none;
}

img {
  border: 0;
}

li {
  list-style: none;
}

html {
  height: 100%;
}

body {
  background: #f0f2f5;
  margin:0
}

#root {
  height: 100%;
}

*,
*:before,
*:after {
  box-sizing: border-box;
}
.ant-modal-title {
  font-weight: 550;
}

.ant-table-cell {
  a {
    margin-right: 10px;
    color: #06c;
  }
}

.ant-picker {
  width: 224px;
  margin: 0 10px 10px;
}

.ant-layout-content {
  position: relative;
}

.container {
  padding: 20px 10px;
  background-color: #fff;

  .formWrap {
    display: flex;
    justify-content: space-between;
  }

  .formWrapLeft {
    display: flex;
    flex-wrap: wrap;
    padding: 0 10px 10px;
    text-align: center;

    .dateText {
      margin-top: 4px;
      color: #666;
      font-size: 14px;
    }

    .select {
      width: 130px;
      margin: 0 20px 10px 10px;
    }
  }
}

.ant-menu-inline .ant-menu-item-selected::after {
  display: none;
}

.ant-select-selector {
  text-align: left;
}

.ant-rate {
  color: #ff8b30;
  font-size: 16px;
}

.ant-table {
  color: #fff;
  background: none;
}
.ant-table-thead > tr > th {
  padding: 10px 0px 10px 10px;
  color: #fff;
  background: none;
  border: none;
}
.ant-table-tbody > tr > td {
  padding: 10px 0px 10px 10px;
  border-bottom: 1px solid rgb(41, 127, 203, 0.5);
}
.ant-table-tbody > tr.ant-table-row:hover > td {
  background: rgba(27, 87, 144, 0.3);
  border-top: 1px solid #297fcb;
  border-bottom: 1px solid #297fcb;
}
.ant-select-dropdown {
  background: rgba(109, 185, 249, 0.2);
}
.ant-select-item-option-selected:not(.ant-select-item-option-disabled) {
  color: #fff;
  background: rgba(109, 185, 249, 0.6);
}
.ant-select-item {
  color: #fff;
}
.ant-select-item-option-active:not(.ant-select-item-option-disabled) {
  background: rgba(109, 185, 249, 0.6);
}
.amap-logo {
  display: none !important;
}

6.配置代理

npm i axios

在pages/utils下创建reauest.js


// import { history } from 'umi';
// import { message } from 'antd';
const api = axios.create({
  baseURL: '/api',
  //   baseURL: '/mock/api',
//   withCredentials: true,
  // timeout: 500
});

// 请求拦截
api.interceptors.request.use(
  (config) => {
    let token = localStorage.getItem('sid');
    if (!config.login && token) {
      config.headers['token'] = token; // 设置请求头
    }
    if (config.download) {
      // download设置responseType
      config.responseType = 'blob';

        }
        console.log(api,'api')
    if (config.upload) {
      config.headers['Content-Type'] = 'multipart/form-data';
    }
    return config;
  },
  (error) => {
    return Promise.reject(error);
  },
);

// 返回拦截
api.interceptors.response.use(
  (response) => {
    if (response.status === 200) {
      if (response.config.download) {
        // download
        let objectUrl = URL.createObjectURL(new Blob([response.data])); // 转换文件下载路径
        let fileName = decodeURI(response.headers['content-disposition'].split('=')[1]); // 获取文件名
        const link = document.createElement('a');
        link.download = fileName;
        link.href = objectUrl;
        link.click();
        return Promise.resolve(response);
      }
      return Promise.resolve(response.data);
    } else {
      return Promise.reject(response);
    }
  },
  (error) => {
    if (error.response.status === 401) {
      localStorage.removeItem('sid');
      localStorage.removeItem('userName');
    //   history.push('/?overtime=true');
    }
    return Promise.reject(error.response);
  },
);

export default api;

在webpackDevServer.config下修改proxy为后并重启项目

      // '/api/test': {
      //   target: 'http://2.0.0.1:3090/',
      //   changeOrigin: true,
      //   pathRewrite: {
      //     '^/api/test': ''
      //   }
      // },
      '/api': {
        target: 'http://127.0.0.1:3000/',
        changeOrigin: true,
        pathRewrite: { '^/api': '/' },
      },

    },

7.配置绝对路径

      alias: {
        '@@': path.resolve(__dirname, '../src'),
      },
    },

8.配置路由

1.在src下创建routers文件夹

import { Outlet, useRoutes } from 'react-router-dom';


const Index = lazy(() => import('@/views/Index/index'));
const Information = lazy(() => import('@/views/Information/index'));
const Contacts = lazy(() => import('@/views/Contacts/index'));



const routes = [
  {
    path: '/index',
    element: <Suspense fallback={<div>稍等</div>}><Index /></Suspense> ,
  },
  {
    path: '/personal',
    element: <Outlet/>,
    children: [
      {
        path: 'information',
        // element: <Information />
        element: <Suspense fallback={<div>稍等</div>}><Information /></Suspense> ,
      },
      {
        path: 'contacts',
        // element: <Contacts />
        element: <Suspense fallback={<div>稍等</div>}><Contacts /></Suspense> ,
      }
    ]
  }
];

const WrappedRoutes = () => {
  return useRoutes(routes);
};

export default WrappedRoutes;

2.并在index.js导入

import { BrowserRouter } from "react-router-dom";并在return里面放在最外层

9.国际化配置

import zhCN from 'antd/lib/locale/zh_CN'

// 并在return里面包裹app组件
    <ConfigProvider locale={zhCN}>
      <App />
    </ConfigProvider>

10.配置导航栏

1.创建components文件 siders文件



import WrappedRoutes from '@@/routers/index';
import { Layout, Menu } from 'antd';
import { useLocation, useNavigate } from 'react-router-dom';
import {
    PieChartOutlined,
    PushpinOutlined,
    IdcardOutlined,
    ContactsOutlined
} from '@ant-design/icons';


const { Header, Content, Footer, Sider } = Layout;

const menuList = [{
    label: "首页",
    key: "/index",
      icon: <PieChartOutlined rev={undefined} />,
},
{
    label: "个人办公",
    key: "/personal",
      icon: <PushpinOutlined rev={undefined} />,
    children: [
        {
            label: "个人信息",
              icon: <IdcardOutlined rev={undefined} />,
            key: "/personal/information"
        },
        {
            label: "通讯录",
              icon: <ContactsOutlined rev={undefined} />,
            key: "/personal/contacts"
        }
    ]
}]
const App = () => {
    const navigate = useNavigate();
    const { pathname } = useLocation(); // 获取当前url

    const handleClick = (e) => {
        navigate(e.key); // 实现跳转
    }


    return (
        <Layout style={{ minHeight: '100vh' }}>
            <Sider>
                <div style={{ height: 90 }} />
                <Menu
                    theme="dark"
                    mode="inline"
                    selectedKeys={[pathname]}
                    items={menuList} onClick={handleClick}
                />
            </Sider>
            <Layout>
                <Content style={{ margin: 16 }}>
                    <WrappedRoutes />
                </Content>
            </Layout>
        </Layout>
    )
};

export default App;

2.将文件导入app,js

import { Layout } from 'antd';
import Siders from '@@/components/sider'
const App = () => {



  return (
    <Layout style={{ minHeight: '100vh' }}>
      <Siders></Siders>
    </Layout>
  )
};

export default App;

11.全局mobx

1.在src下新建store文件夹,存放状态,store下的index.js统一管理所有状态

import cart from '@@/store/cart'
import counter from '@@/store/counter'

// store/Counter.ts
class RootStore {
    cart = cart
    counter = counter
  }
  const store = new RootStore()
  
  // 创建一个上下文对象,用于跨级组件通讯
  // 如果 createContext 提供了默认值,不需要 Provider
  const Context = createContext(store)
  

export default store;

2.子状态文件

import { action, makeObservable, observable } from 'mobx'
import api from '@@/utils/request.js'
class Counter {
    count = 0
    data = []
    constructor() {
        // 参数1:target,把谁变成响应式(可观察)
        // 参数2:指定哪些属性或者方法变成可观察
        makeObservable(this, {
            count: observable,
            data: observable,
            increment: action.bound,
            decrement: action.bound,
            reset: action.bound,
            apiFn: action.bound,
       
        })
    }

    increment() {
        this.count++
    }
    decrement() {
        this.count--
    }
    reset() {
        this.count = 0
       
    }
    async apiFn() {
        await api.get('/daxia/daxia').then(value => {
            this.data = value.value
        })
    }

}
const counter = new Counter()
export default counter

3.视图文件

import { observer,inject } from 'mobx-react'
import { useEffect} from 'react'
import { Space, Table, Tag } from 'antd';

const Text = ({store}) => {
    const  {counter}  = store
    useEffect(() => {
        counter.apiFn()
    },[])
    const columns = [
        {
          title: 'bspPath',
          dataIndex: 'bspPath',
          key: 'bspPath',
          render: (text) => <a>{text}</a>,
        },
        {
          title: 'bspName',
          dataIndex: 'bspName',
          key: 'bspName',
        },
        {
          title: 'objName',
          dataIndex: 'objName',
          key: 'objName',
        },
      ];

    return (
        <div>
            <h3>计数器案例</h3>
            <div>点击次数:{counter.count}</div>
            <button onClick={counter.increment}>加1</button>
            <button onClick={counter.decrement}> 减1</button >
            <button onClick={counter.reset}>重置</button>
            <Table columns={columns} dataSource={counter.data} />

        </div >
    )
}
export default inject('store')(observer(Text));

4.index.js文件传入store

import ReactDOM from 'react-dom/client';
import App from './App';
import { BrowserRouter } from "react-router-dom";
import { ConfigProvider } from 'antd'
import zhCN from 'antd/lib/locale/zh_CN'
import { Provider } from 'mobx-react'
import store from '@@/store'

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(

  <ConfigProvider locale={zhCN}>
    <Provider store={store}>
      <BrowserRouter>
        <App />
      </BrowserRouter>
    </Provider>
  </ConfigProvider>

);

12.增加services层

1.创建services文件夹,引入request,导出api接口,让视图层更加专注渲染页面,状态层分离

export async function deleteFun(options) {
    try {
      let response = await requset.delete('', {
        params: options,
      });
      return response;
    } catch (error) {
      return error;
    }
  }

  
export async function postFun(options) {
    try {
      let response = await requset.post('', options);
      return response;
    } catch (error) {
      return error;
    }
  }

  export async function getFun(options) {
    try {
      let response = await requset.get('/daxia/daxia', {
        params: options,
      });
      console.log('response')
      return response;
    } catch (error) {
      return error;
    }
  }
  export async function putFun(options) {
    try {
        let response = await requset.put('', options);
        return response;
    } catch (error) {
        return error;
    }
}

2.修改store里面


...
async apiFn(options = {}) {
        await getFun(options).then(value => {
            this.data = value.value
        })
        console.log(this,'this')
    }
...

3.修改视图层增加传参

counter.apiFn({参数})

13.增加登陆页面

1.在view下面新增login文件夹

import { Card, Col, Row, Button, message, Form, Input } from 'antd'
import logo from '@@/assets/icon.png'
//useNavigate必须在函数组件中使用,函数组件未大写也报错了
import { useNavigate } from 'react-router-dom'


const Login = () => {
    const navigate = useNavigate()
    const onFinish = (values) => {
        console.log('Success:', values);


   
        message.success('登陆成功')
        navigate('/index')

    };
    const onFinishFailed = (errorInfo) => {
        console.log('Failed:', errorInfo);
    };
    return (
        <Row>
            <Col
                md={{
                    span: 8,
                    push: 8
                }}
                xs={{
                    span: 22,
                    push: 1
                }}
            >
                <img src={logo}
                    style={{
                        display: 'block',
                        margin: '20px auto',
                        borderRadius: '16px',
                        width: '200px'
                    }}></img>
                <Card title='练习管理平台'>
                    <Form
                        name="basic"
                        style={{
                            maxWidth: 600,
                        }}
                        initialValues={{
                            remember: true,
                        }}
                        onFinish={onFinish}
                        onFinishFailed={onFinishFailed}
                        autoComplete="off"
                    >
                        <Form.Item
                            label="用户名"
                            name="username"
                            rules={[
                                {
                                    required: true,
                                    message: '请输入用户名!',
                                },
                            ]}
                        >
                            <Input />
                        </Form.Item>

                        <Form.Item
                            label="密码"
                            name="password"
                            rules={[
                                {
                                    required: true,
                                    message: '请输入密码!',
                                },
                            ]}
                        >
                            <Input.Password />
                        </Form.Item>

                        <Form.Item
                            wrapperCol={{
                                offset: 8,
                                span: 16,
                            }}
                        >
                            <Button type="primary" htmlType="submit">
                                登录
                            </Button>
                        </Form.Item>
                    </Form>
                </Card>
            </Col>
        </Row>

    )
}


export default Login

2.修改index.js文件,增加登陆页面路由

import { lazy, Suspense } from "react";
import ReactDOM from 'react-dom/client';
import { BrowserRouter, Route, Routes } from "react-router-dom";
import { ConfigProvider } from 'antd'
import zhCN from 'antd/lib/locale/zh_CN'
import { Provider } from 'mobx-react'
import store from '@@/store'
const Login = lazy(() => import('@@/views/Login/index'));
const App = lazy(() => import('@@/App'));
const Loading = lazy(() => import('@@/views/loading/index'));

const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(

  <ConfigProvider locale={zhCN}>
    <Provider store={store}>
      <BrowserRouter>
        <Routes>
          <Route path='/' element={<Suspense fallback={<Loading />}><Login /></Suspense>}></Route>
          <Route path='/*' element={<Suspense fallback={<Loading />}><App /></Suspense>}></Route>
        </Routes>
      </BrowserRouter>
    </Provider>
  </ConfigProvider>

);

14.增加退出登录功能,面包屑,页面刷新放丢失



import WrappedRoutes from '@@/routers/index';
import { Layout, Menu, Button, theme, Dropdown, message,Breadcrumb } from 'antd';
import { useLocation, useNavigate } from 'react-router-dom';
import {
    PieChartOutlined,
    PushpinOutlined,
    IdcardOutlined,
    ContactsOutlined,
    MenuUnfoldOutlined,
    MenuFoldOutlined
} from '@ant-design/icons';
import { useState, useEffect } from 'react'
import logo from '@@/assets/icon.png'
import styles from './index.less'


const { Content, Sider, Header } = Layout;

const menuList = [
    {
        label: "总览",
        title: "总览",
        key: "/index",
        icon: <PieChartOutlined rev={undefined} />,
    },
    {
        label: "个人办公",
        title: "个人办公",
        key: "/personal",
        icon: <PushpinOutlined rev={undefined} />,
        children: [
            {
                label: "个人信息",
                title: "个人信息",
                icon: <IdcardOutlined rev={undefined} />,
                key: "/personal/information"
            },
            {
                label: "通讯录",
                title: "通讯录",
                icon: <ContactsOutlined rev={undefined} />,
                key: "/personal/contacts"
            }
        ]
    }]

/**
* 处理刷新页面后menu返回第一个问题
* @param {*} key 
* @returns 
*/
const findOpenKeys = (key) => {
    // console.log(key, 'pathname')
    const result = []
    const findInfo = arr => {
        arr.forEach((item) => {
            if (key.includes(item.key)) {
                result.push(item.key)
                if (item.children) {
                    findInfo(item.children)
                }
            }
        })
    }
    findInfo(menuList)
    return result
}

/**
 * 获取当前选中的所有父节点
 * @param {*} key 
 * @returns 
 */
const findDeepPath = key => {
    const result = []
    const findInfo = arr => {
        arr.forEach(item => {
            const { children, ...info } = item
            result.push(info)
            if (children) {
                findInfo(children)
            }
        })
    }
    //数组扁平化
    findInfo(menuList)
    const tepData = result.filter(item => key.includes(item.key))
    if (tepData.length > 0) {
        //这里添加的key值不能和上面的重复,会报错
        return [{ title: '首页', key: '/admin/dashboard-admin' }, ...tepData]
    }
    // return []
}
const App = ({ children }) => {
    const [collapsed, setCollapsed] = useState(false);
    const navigate = useNavigate();
    const { pathname } = useLocation(); // 获取当前url
    const [breadcrumbs, setBreadcrumbs] = useState([])
    const {
        token: { colorBgContainer },
    } = theme.useToken();
    const handleClick = (e) => {
        navigate(e.key); // 实现跳转
    }
    useEffect(() => {
        setBreadcrumbs(findDeepPath(pathname))
    }, [pathname])

    const temOpenKeys = findOpenKeys(pathname)
    const items = [
        { label: '个人中心', key: 'userCenter' },
        { label: '退出', key: 'logout' }
    ]
    const onClick = (value) => {
        if (value.key === 'logout') {
            navigate('/')
        } else {
            message.info('暂未开通')
        }
        console.log('点击事件', value)
    }
    return (
        <Layout style={{ minHeight: '100vh' }}>
            <Sider trigger={null} collapsible collapsed={collapsed}>
                <div style={{ height: 90 }} />
                <Menu
                    theme="dark"
                    mode="inline"
                    defaultOpenKeys={temOpenKeys}
                    defaultSelectedKeys={temOpenKeys}
                    selectedKeys={[pathname]}
                    items={menuList}
                    onClick={handleClick}
                />
            </Sider>
            <Layout>
                <Header
                    style={{
                        padding: 0,
                        background: colorBgContainer,
                    }}
                >
                    <Button
                        type="text"
                        icon={collapsed ? <MenuUnfoldOutlined /> : <MenuFoldOutlined />}
                        onClick={() => setCollapsed(!collapsed)}
                        style={{
                            fontSize: '16px',
                            width: 64,
                            height: 64,
                        }}
                    />
                    <Dropdown
                        menu={{
                            items,
                            onClick
                        }}
                        placement="bottom"
                    >
                        <img src={logo} className={styles.logoOut}></img>
                    </Dropdown>
                </Header>
                <Content style={{ margin: 16 }}>
                    <Breadcrumb
                        items={breadcrumbs}
                    >
                    </Breadcrumb>
                    <WrappedRoutes />
                </Content>
            </Layout>
        </Layout>
    )
};

export default App;

15.全局高度撑满问题,需要在antd的Layout组件添加style={{ minHeight: '100vh' }}

16.关闭eslint配置

在webpack.config里面添加

// 关闭eslint
const disableESLintPlugin = true;

17.webpack增加编译进度条展示

//编译进度条
const WebpackBar = require('webpackbar')
// Some apps do not need the benefits of saving a web request, so not inlining the chunk
// makes for a smoother build process.

//增加plugin
 new webpack.ProgressPlugin(),//自带的
 new WebpackBar()

18.webpack优化,分析包内容,显示打包体积大小

//1.分析包内容,显示打包的文件大小
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin

//2.增加plugins
  //显示页面打包文件大小
      new BundleAnalyzerPlugin({
        analyzerMode: 'disabled', // 不启动展示打包报告的http服务器
        generateStatsFile: false, // 是否生成stats.json文件
      }), // 使用默认配置
      // 默认配置的具体配置项
      // new BundleAnalyzerPlugin({
      //   analyzerMode:'server', // 可以是 server、static、json、disabled。在server模式下,分析器将启动HTTP服务器来显示软件包报告。在“静态”模式下,会生成带有报告的单个HTML文件。在disabled模式下,你可以使用这个插件来将generateStatsFile设置为true来生成Webpack Stats JSON文件。
      //   analyzerHost: '127.0.0.1', // 将在“服务器”模式下使用的端口启动HTTP服务器
      //   analyzerPort: 8888, // 端口号
      //   reportFilename: 'report.html', // 路径捆绑,将在static模式下生成的报告文件。相对于捆绑输出目录
      //   defaultSizes: 'parsed', // 默认显示在报告中的模块大小匹配方式。应该是stat,parsed或者gzip中的一个
      //   openAnalyzer: false, // 在默认浏览器中是否自动打开报告,默认 true
      //   generateStatsFile: false, // 如果为true,则Webpack Stats JSON文件将在bundle输出目录中生成
      //   statsFilename: 'stats.json', // 相对于捆绑输出目录
      //   statsOptions: null, //stats.toJson()方法的选项。例如,您可以使用source:false选项排除统计文件中模块的来源。在这里查看更多选项:https://github.com/webpack/webpack/blob/webpack-1/lib/Stats.js#L21
      //   logLevel: 'info', // 日志级别,可以是info, warn, error, silent
      //   excludeAssets:null, // 用于排除分析一些文件
      // }),

  //3.在pacgage.json添加
"generateAnalyzFile": "webpack --profile --json > stats.json",
"analyz": "webpack-bundle-analyzer --port 8888 ./stats.json"

//4.先执行npm run generateAnalyzFile
//5.在执行npm run analyz

19.webpack费时优化,显示打包时间

//$ npm i mini-css-extract-plugin@1.3.6 -D  需要回退版本
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin()


// smp.wrap(
  //解决显示打包时间和css文件提取冲突问题
const wrapConfig = process.env.NODE_ENV !== 'development' ? smp.wrap : (config) => config;

module.exports = wrapConfig((webpackEnv)=> {webpack配置})

20.webpack报警告,无法映射源文件

在最外层添加文件.env

GENERATE_SOURCEMAP=false

21.增加eslint效验

1.增加.eslintrc.js文件

    "env": {
        "browser": true,
        "es2021": true
    },
    "extends": [
        "eslint:recommended",
        "plugin:react/recommended"
    ],
    "overrides": [
    ],
    
    "parserOptions": {
        "ecmaVersion": "latest",
        "sourceType": 'module',
        "parser":"babel-eslint",
    },
    "plugins": [
        "react"
    ],
    "rules": {
        "no-console": 1,
        "semi":2
    }
}

2.增加.eslintignore文件

/node_moduls
/config
.eslintrc.js
/scripts

3.修改webpack.config.js配置


!disableESLintPlugin &&
      new ESLintPlugin({
        // Plugin options
        context: path.resolve(__dirname,'../src'),  //指定文件根目录,类型为字符串
 
      }),

4.删除package.json的eslintConfig配置

5.eslint关闭效验

/* eslint-disable */some code
some code
/* eslint-enable */

2.关闭当前行效验
some code // eslint-disable-line

3.关闭下一行效验
// eslint-disable-next-line
some code

4.关闭整个行效验
/* eslint-disable */

22.配置stylelint

作用:css的书写顺序很重要,会影响浏览器的渲染。正确的书写可以减少浏览器的回流,提升浏览器的dom渲染。

1.安装依赖

npm i stylelint stylelint-config-standard stylelint-order -D

2.增加.stylelintrc.js

    extends: ['stylelint-config-standard'],
    plugins: ['stylelint-order'],
    rules: {
        'no-descending-specificity': null,
        'function-url-quotes': 'always',
        'string-quotes': 'double',
        indentation: 4,
        'unit-case': null,
        'color-hex-case': 'lower',
        'color-hex-length': 'long',
        'rule-empty-line-before': 'never',
        'font-family-no-missing-generic-family-keyword': null,
        'block-opening-brace-space-before': 'always',
        'property-no-unknown': null,
        'no-empty-source': null,
        'selector-pseudo-class-no-unknown': [
            true,
            {
                ignorePseudoClasses: ['deep'],
            },
        ],
        'order/properties-order': [
            'position',
            'top',
            'right',
            'bottom',
            'left',
            'z-index',
            'display',
            'justify-content',
            'align-items',
            'float',
            'clear',
            'overflow',
            'overflow-x',
            'overflow-y',
            'margin',
            'margin-top',
            'margin-right',
            'margin-bottom',
            'margin-left',
            'padding',
            'padding-top',
            'padding-right',
            'padding-bottom',
            'padding-left',
            'width',
            'min-width',
            'max-width',
            'height',
            'min-height',
            'max-height',
            'font-size',
            'font-family',
            'font-weight',
            'border',
            'border-style',
            'border-width',
            'border-color',
            'border-top',
            'border-top-style',
            'border-top-width',
            'border-top-color',
            'border-right',
            'border-right-style',
            'border-right-width',
            'border-right-color',
            'border-bottom',
            'border-bottom-style',
            'border-bottom-width',
            'border-bottom-color',
            'border-left',
            'border-left-style',
            'border-left-width',
            'border-left-color',
            'border-radius',
            'text-align',
            'text-justify',
            'text-indent',
            'text-overflow',
            'text-decoration',
            'white-space',
            'color',
            'background',
            'background-position',
            'background-repeat',
            'background-size',
            'background-color',
            'background-clip',
            'opacity',
            'filter',
            'list-style',
            'outline',
            'visibility',
            'box-shadow',
            'text-shadow',
            'resize',
            'transition',
        ],
    },
}

3.下载vscode插件stylelint

        "source.fixAll.eslint": true,
      	//增加如下代码
        "source.fixAll.stylelint": true,
    },

4.在parkage.json的scripts里面增加

"style": "stylelint 'src/**/*.(css|less)' --fix"

5.忽略检查写法

/* stylelint-disable */
div{
    width:100px;
}

2.忽略多行
/* stylelint-disable */
div {
    color: red;
}
/* stylelint-enable */

3.忽略一行, 在样式前加入 /* stylelint-disable-next-line */ 以忽略该行
#id {
    /* stylelint-disable-next-line */
    color: pink !important;
  }

  4.在 .stylelintrc.json 內设定需要忽略的文件
  {
    ignoreFiles: ["dist/**/*", "src/assets/scss/abc.scss"]
  }