• vite+vue3 2


    原本要搞一下算法和Asp.NetCore,但是想到vite+vue3还有几个插件没有记录,总是感觉怪怪的,所以今天下午把eslint+prettier、postcss和svgIcon这四个插件试验性的做了个Demo,以下记录这四个的使用过程。

    一、开始工作

    1.eslint+prettier

    1.1.eslint

    1.1.1.简要说明:eslint的作用就是约束代码规范的,不论是个人项目还是多人合作,规范的代码风格都是一种保证,对可读性,避免语法错误等有很大的帮助。

    1.1.2.步骤过程

        a)安装eslint:npm i eslint -D

                b)配置eslint:执行npx eslint --init命令,然后按照提示完成一系列操作来创建配置文件

                    问:How would you like to use ESLint? (你想如何使用 ESLint?)

                    答:选择To check syntax, find problems, and enforce code style(检查语法、发现问题并强制执行代码风格)

                    问:What type of modules does your project use?(你的项目使用哪种类型的模块?)

                    答:选择 JavaScript modules (import/export)

                    问:Which framework does your project use? (你的项目使用哪种框架?)

                    答:选择 Vue.js

                    问:Does your project use TypeScript?(你的项目是否使用 TypeScript?)

                    答:选择No

                    问:Where does your code run?(你的代码在哪里运行?)

                    答:选择 Browser 和 Node

                    问:How would you like to define a style for your project?(你想怎样为你的项目定义风格?)

                    答:选择 Use a popular style guide(使用一种流行的风格指南)

                    问:Which style guide do you want to follow?(你想遵循哪一种风格指南?)

                    答:选择 Airbnb

                    问:What format do you want your config file to be in?(你想你的配置文件使用什么格式?)

                    答:选择JavaScript

                    问:Would you like to install them now with npm?(你想现在就用 NPM 安装它们吗?)

                    答:选择Yes

                c)在VSCode使用ESlint,需要安装插件:ESLint

    1.1.3.配置信息

      1 module.exports = {
      2   env: {
      3     browser: true,
      4     es2021: true,
      5     'vue/setup-compiler-macros': true
      6   },
      7   extends: [
      8     'plugin:vue/essential',
      9     'airbnb-base',
     10     'plugin:prettier/recommended' // 添加 prettier 插件
     11   ],
     12   parserOptions: {
     13     ecmaVersion: 'latest',
     14     sourceType: 'module'
     15   },
     16   plugins: ['vue'],
     17   rules: {
     18     /*
     19      * "off" 或 0 - 关闭规则
     20      * "warn" 或 1 - 开启规则,使用警告级别的错误:warn (不会导致程序退出)
     21      * "error" 或 2 - 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出)
     22      */
     23     'vue/no-multiple-template-root': 'off', // 关闭多根节点的校验
     24     'vue/multi-word-component-names': 'off', // 关闭组件命名规则
     25     'vue/singleline-html-element-content-newline': 'off',
     26     'vue/multiline-html-element-content-newline': 'off',
     27     'vue/name-property-casing': ['error', 'PascalCase'],
     28     'vue/no-v-html': 'off',
     29 
     30     'import/no-unresolved': 'off',
     31     'import/extensions': 'off',
     32     'import/no-absolute-path': 'off',
     33     'import/no-extraneous-dependencies': 'off',
     34 
     35     'accessor-pairs': 2, // 定义对象的set存取器属性时,强制定义get
     36     'arrow-spacing': [2, { before: true, after: true }], // =>的前/后括号
     37     'block-spacing': [2, 'always'], // 块是否需要空格
     38     'brace-style': [2, '1tbs', { allowSingleLine: true }], // if while function 后面的{必须与if在同一行,java风格
     39     camelcase: [0, { properties: 'always' }], // 强制驼峰法命名
     40     'comma-dangle': [2, 'never'], // 数组和对象键值对最后一个逗号,never:不能带末尾的逗号, always:必须带末尾的逗号,always-multiline:多行模式必须带逗号,单行模式不能带逗号
     41     'comma-spacing': [2, { before: false, after: true }], // 控制逗号前后的空格
     42     'comma-style': [2, 'last'], // 控制逗号在行尾出现还是在行首出现
     43     'constructor-super': 2, // 强制在子类构造函数中用super()调用父类构造函数,TypeScript的编译器也会提示
     44     curly: [2, 'multi-line'], // 强制所有控制语句使用一致的括号风格
     45     'dot-location': [2, 'property'], // 强制object.key中.的位置,参数:property:'.'号应与属性在同一行, object:'.'号应与对象名在同一行
     46     'eol-last': 2, // 文件末尾强制换行
     47     eqeqeq: ['error', 'always', { null: 'ignore' }], // 使用 === 替代 ==
     48     'generator-star-spacing': [2, { before: true, after: true }], // 生成器函数*的前后空格
     49     'handle-callback-err': [2, '^(err|error)$'], // nodejs 处理错误
     50     indent: [2, 2, { SwitchCase: 1 }], // 缩进风格
     51     'jsx-quotes': [2, 'prefer-single'], // JSX 属性中一致使用双引号或单引号
     52     'key-spacing': [2, { beforeColon: false, afterColon: true }], // 对象字面量中冒号的前后空格
     53     'keyword-spacing': [2, { before: true, after: true }], // 对象字面量中冒号的前后空格
     54     'new-cap': [2, { newIsCap: true, capIsNew: false }], // 函数名首行大写必须使用new方式调用,首行小写必须用不带new方式调用
     55     'new-parens': 2, // new时必须加小括号
     56     'no-array-constructor': 2, // 禁止使用数组构造器
     57     'no-caller': 2, // 禁止使用arguments.caller或arguments.callee
     58     'no-console': 'off', // 禁用 console
     59     'no-class-assign': 2, // 禁止给类赋值
     60     'no-cond-assign': 2, // 禁止在条件表达式中使用赋值语句
     61     'no-const-assign': 2, // 禁止修改const声明的变量
     62     'no-control-regex': 0, // 禁止在正则表达式中使用控制字符
     63     'no-delete-var': 2, // 不能对var声明的变量使用delete操作符
     64     'no-dupe-args': 2, // 函数参数不能重复
     65     'no-dupe-class-members': 2, // 不允许类中出现重复的声明
     66     'no-dupe-keys': 2, // 在创建对象字面量时不允许键重复 {a:1,a:1}
     67     'no-duplicate-case': 2, // switch中的case标签不能重复
     68     'no-empty-character-class': 2, // 正则表达式中的[]内容不能为空
     69     'no-empty-pattern': 2, // 禁止使用空解构模式
     70     'no-eval': 2, // 禁止使用eval
     71     'no-ex-assign': 2, // 禁止给catch语句中的异常参数赋值
     72     'no-extend-native': 2, // 禁止扩展native对象
     73     'no-extra-bind': 2, // 禁止不必要的函数绑定
     74     'no-extra-boolean-cast': 2, // 禁止不必要的bool转换
     75     'no-extra-parens': [2, 'functions'], // 禁止非必要的括号
     76     'no-fallthrough': 2, // 禁止switch穿透
     77     'no-floating-decimal': 2, // 禁止省略浮点数中的0 .5 3.
     78     'no-func-assign': 2, // 禁止重复的函数声明
     79     'no-implied-eval': 2, // 禁止使用隐式eval
     80     'no-inner-declarations': [2, 'functions'], // 禁止在块语句中使用声明(变量或函数)
     81     'no-invalid-regexp': 2, // 禁止无效的正则表达式
     82     'no-irregular-whitespace': 2, // 不能有不规则的空格
     83     'no-iterator': 2, // 禁止使用__iterator__ 属性
     84     'no-label-var': 2, // label名不能与var声明的变量名相同
     85     'no-labels': [2, { allowLoop: false, allowSwitch: false }], // 禁止标签声明
     86     'no-lone-blocks': 2, // 禁止不必要的嵌套块
     87     'no-mixed-spaces-and-tabs': 2, // 禁止混用tab和空格
     88     'no-multi-spaces': 2, // 不能用多余的空格
     89     'no-multi-str': 2, // 字符串不能用\换行
     90     'no-multiple-empty-lines': [2, { max: 1 }], // 空行最多不能超过1行
     91     'no-native-reassign': 2, // 不能重写native对象
     92     'no-negated-in-lhs': 2, // in 操作符的左边不能有!
     93     'no-new-object': 2, // 禁止使用new Object()
     94     'no-new-require': 2, // 禁止使用new require
     95     'no-new-symbol': 2, // 禁止使用new symbol
     96     'no-new-wrappers': 2, // 禁止使用new创建包装实例,new String new Boolean new Number
     97     'no-obj-calls': 2, // 不能调用内置的全局对象,比如Math() JSON()
     98     'no-octal': 2, // 禁止使用八进制数字
     99     'no-octal-escape': 2, // 禁止使用八进制转义序列
    100     'no-path-concat': 2, // node中不能使用__dirname或__filename做路径拼接
    101     'no-proto': 2, // 禁止使用__proto__属性
    102     'no-redeclare': 2, // 禁止重复声明变量
    103     'no-regex-spaces': 2, // 禁止在正则表达式字面量中使用多个空格 /foo bar/
    104     'no-return-assign': [2, 'except-parens'], // return 语句中不能有赋值表达式
    105     'no-self-assign': 2, // 自我分配
    106     'no-self-compare': 2, // 不能比较自身
    107     'no-sequences': 2, // 禁止使用逗号运算符
    108     'no-shadow-restricted-names': 2, // 严格模式中规定的限制标识符不能作为声明时的变量名使用
    109     'no-spaced-func': 2, // 函数调用时 函数名与()之间不能有空格
    110     'no-sparse-arrays': 2, // 禁止稀疏数组, [1,,2]
    111     'no-this-before-super': 2, // 在调用super()之前不能使用this或super
    112     'no-throw-literal': 2, // 禁止抛出字面量错误 throw "error"
    113     'no-trailing-spaces': 2, // 一行结束后面不要有空格
    114     'no-undef': 2, // 不能有未定义的变量
    115     'no-undef-init': 2, // 变量初始化时不能直接给它赋值为undefined
    116     'no-unexpected-multiline': 2, // 避免多行表达式
    117     'no-unmodified-loop-condition': 2, // 检查引用是否在循环中被修改
    118     'no-unneeded-ternary': [2, { defaultAssignment: false }], // 禁止可以在有更简单的可替代的表达式时使用三元操作符
    119     'no-unreachable': 2, // 不能有无法执行的代码
    120     'no-unsafe-finally': 2, // 禁止对关系运算符的左操作数使用否定操作符
    121     'no-unused-vars': [2, { vars: 'all', args: 'none' }], // 不能有声明后未被使用的变量或参数
    122     'no-useless-call': 2, // 禁止不必要的call和apply
    123     'no-useless-computed-key': 2, // 没有必要使用带文字的计算属性
    124     'no-useless-constructor': 2, // 可以在不改变类的工作方式的情况下安全地移除的类构造函数
    125     'no-useless-escape': 0, // 禁用不必要的转义字符
    126     'no-whitespace-before-property': 2, // 禁止属性前有空白
    127     'no-with': 2, // 禁用with
    128     'one-var': [2, { initialized: 'never' }], // 连续声明
    129     'operator-linebreak': [2, 'after', { overrides: { '?': 'before', ':': 'before' } }], // 换行时运算符在行尾还是行首
    130     'padded-blocks': [2, 'never'], // 块语句内行首行尾是否要空行
    131     'space-before-blocks': [2, 'always'], // 不以新行开始的块{前面要不要有空格
    132     'space-before-function-paren': [2, 'never'], // 函数定义时括号前面要不要有空格
    133     'space-in-parens': [2, 'never'], // 小括号里面要不要有空格
    134     'space-infix-ops': 2, // 中缀操作符周围要不要有空格
    135     'space-unary-ops': [2, { words: true, nonwords: false }], // 一元运算符的前/后要不要加空格
    136     // 注释风格不要有空格什么的
    137     'spaced-comment': [
    138       2,
    139       'always',
    140       { markers: ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ','] }
    141     ],
    142     'template-curly-spacing': [2, 'never'], // 要求或禁止模板字符串中的嵌入表达式周围空格的使用
    143     'use-isnan': 2, // 禁止比较时使用NaN,只能用isNaN()
    144     'valid-typeof': 2, // 必须使用合法的typeof的值
    145     'wrap-iife': [2, 'any'], // 立即执行函数表达式的小括号风格
    146     'yield-star-spacing': [2, 'both'], // 强制在 yield* 表达式中 * 周围使用空格
    147     yoda: [2, 'never'], // 禁止尤达条件
    148 
    149     'prefer-const': 2, // 首选const
    150     'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0, // 禁用 debugger
    151     'object-curly-spacing': [0, 'always', { objectsInObjects: false }], // 大括号内是否允许不必要的空格
    152     'array-bracket-spacing': [2, 'never'], // 是否允许非空数组里面有多余的空格
    153 
    154     'no-restricted-syntax': 0, // 禁止使用特定的语法
    155     'no-loop-func': 0, // 禁止循环中存在函数
    156     'consistent-return': 0, // 要求 return 语句要么总是指定返回的值,要么不指定
    157     'import/prefer-default-export': 0, // 希望导出default,即export default xxx
    158 
    159     quotes: [2, 'single', { avoidEscape: true, allowTemplateLiterals: true }], // 引号类型 `` "" ''
    160     semi: [2, 'never'], // 语句强制分号结尾
    161     'semi-spacing': [2, { before: false, after: true }] // 分号前后空格
    162   }
    163 }
    View Code

    1.1.4.使用问题

             a)在VSCode下ESlint插件不生效,如何排查问题

                   1.确保eslint配置文件和node_modules在根目录下

                   2.确定安装了vscode eslint插件

                   3.确认package.json中安装了 eslint和eslint-plugin等

                   4.vscode 按下f1

                   5.输入eslint

                   6.选择ESLint: Show Output Channel查看eslint报错信息

                   7.按照错误信息,去解决

            b)defineProps' is not defined

                  1.定位问题:defineProps 属于 Vue3 的规则校验,需要在 eslint-plugin-vue官方指南中寻找对应配置。

                  2.解决问题:打开.eslintrc.js文件,在env配置项中添加“'vue/setup-compiler-macros': true”

    1.2.prettier 

    1.2.1.简要说明:它是一款强大的代码格式化工具,支持JavaScript、Typescript、Css、Scss、Less、JSX、Angular、Vue、GraphQL、JSON、Markdown等,基本上前端能用到的文件格式都可以搞定。

    1.2.2.步骤过程

         a)安装prettier:npm i prettier -D

              b)创建 Prettier 配置文件,在./src下创建.prettierrc文件,文件内容如下:

     1 {
     2   "useTabs": false,
     3   "tabWidth": 2,
     4   "printWidth": 100,
     5   "singleQuote": true,
     6   "trailingComma": "none",
     7   "bracketSpacing": true,
     8   "semi": false,
     9   "endOfLine": "auto"
    10 }
    View Code

              c)使用其命令格式化代码文件

                    # 格式化所有文件 (. 表示所有文件)

                    npx prettier --write .

             d)使用VSCode编辑器,安装Prettier插件:Prettier - Code formatter

    1.3.兼容问题

    1.3.1.基于个人观点,其实使用eslint基本上已经满足需求了,使用这种组合方式反而会出现很多兼容性问题要解决。看到网友都推荐eslint+prettier组合,就记录一下吧。

    1.3.2.解决eslint和prettier冲突

              a)安装插件:npm i eslint-plugin-prettier eslint-config-prettier -D

              b)修改.eslintrc.js配置文件,添加prettier插件

    1 module.exports = {
    2   ...
    3   extends: [
    4     'plugin:vue/essential',
    5     'airbnb-base',
    6     'plugin:prettier/recommended' // 添加 prettier 插件
    7   ],
    8   ...
    9 }
    View Code

             c)插件功能说明:

                  eslint-plugin-prettier 将 Prettier 的规则设置到 ESLint 的规则中。

                  eslint-config-prettier 关闭 ESLint 中与 Prettier 中会发生冲突的规则。

            d)特别说明:即便配置上解决规则冲突的设置,还是会出现很多兼容性问题。

    2.postcss

    2.1.简要说明:postcss是一种对css编译的工具,类似于babel处理js,主要功能:1.使用下一代css语法,2.自动补全浏览器前缀,3.自动把px替换为rem,4.css代码压缩等。

    2.2.步骤过程

      a).安装postcss和postcss-preset-env插件:npm install postcss postcss-preset-env -D

      b).配置vite.config.js文件:

     1 import { defineConfig } from 'vite'
     2 import vue from '@vitejs/plugin-vue'
     3 import postcssPresetEnv from 'postcss-preset-env'
     4 
     5 // https://vitejs.dev/config/
     6 export default defineConfig({
     7   base: './',
     8   publicDir: 'public', // 静态资源服务的文件夹
     9   logLevel: 'info', // 控制台输出的级别 info 、warn、error、silent
    10   clearScreen: true, // 设为false 可以避免 vite 清屏而错过在终端中打印某些关键信息
    11   css: {
    12     postcss: {
    13       plugins: [postcssPresetEnv]
    14     }
    15   }
    16 })
    View Code

           c).修改App.vue文件,编写测试示例:

     1 <template>
     2   <img alt="Vue logo" src="@/assets/logo.png" />
     3 
     4   <div class="title">Hello Vite!</div>
     5 
     6   <router-view />
     7 </template>
     8 
     9 <script>
    10 
    11 export default {
    12   name: 'App'
    13 }
    14 </script>
    15 
    16 <style type="text/css">
    17 .title {
    18   font-size: 30px;
    19   color: yellow;
    20   user-select: none;
    21 }
    22 </style>
    View Code

    2.3.查看效果:启动项目,命令:npm run dev。我们重点关注样式title的user-select: none;打开浏览器,你会看到user-select:none;多出了好几处有前缀的属性项,如:-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;

    2.4.注意事项

          2.4.1.上述过程中,使用了postcss-preset-env与postcss搭配,你也可以使用其他的插件,如autoprefixer等

          2.4.2.由于vite自身已经集成了postcss,所以不要在根目录再创建postcss.config.js文件。如果创建了这个文件可能还会出错,因为vite是基于esmodule管理的,所有文件都会转换为module。

    3.svgIcon

    3.1.简要说明:svg图标是基于xml定义可缩放的矢量图形,由于其不会图形质量不会因分辨率导致失真,所以被大量应用于程序编码中。

    3.2.步骤过程

            a)创建目录和文件结构:

                 目录:./src/icons

                 目录:./src/icons/svg

                 文件:./src/icons/index.vue

                 文件:./src/icons/svgBuilder.js

            b)在./src/icons/svg目录里添加测试图标login-user.svg

            c)安装svg插件:npm install svg-sprite-loader -D

            d)编写./src/icons/index.vue文件

     1 <template>
     2   <div
     3     v-if="isExternal"
     4     :style="styleExternalIcon"
     5     class="svg-external-icon svg-icon"
     6     v-on="$attrs"
     7   />
     8   <svg v-else :class="svgClass" aria-hidden="true" v-on="$attrs">
     9     <use :xlink:href="iconName" />
    10   </svg>
    11 </template>
    12 <script>
    13 /**
    14  * 名称:SvgIcon
    15  * @param iconClass String required
    16  * @param className String
    17  * 依赖:src/icons/svgBuilder.js 需要在vite中配置
    18  * 使用方式:
    19  * 在 template 中使用 <svg-icon icon-class="login-user"/>
    20  */
    21 export default {
    22   name: 'SvgIcon',
    23   props: {
    24     iconClass: {
    25       type: String,
    26       required: true
    27     },
    28     className: {
    29       type: String,
    30       default: ''
    31     }
    32   },
    33   computed: {
    34     isExternal() {
    35       return /^(https?:|mailto:|tel:)/.test(this.iconClass)
    36     },
    37     iconName() {
    38       return `#icon-${this.iconClass}`
    39     },
    40     svgClass() {
    41       if (this.className) {
    42         return `svg-icon ${this.className}`
    43       }
    44       return 'svg-icon'
    45     },
    46     styleExternalIcon() {
    47       return {
    48         mask: `url(${this.iconClass}) no-repeat 50% 50%`,
    49         '-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
    50       }
    51     }
    52   }
    53 }
    54 </script>
    55 
    56 <style scoped>
    57 .svg-icon {
    58    1em;
    59   height: 1em;
    60   vertical-align: -0.15em;
    61   fill: currentColor;
    62   overflow: hidden;
    63 }
    64 
    65 .svg-external-icon {
    66   background-color: currentColor;
    67   mask-size: cover !important;
    68   display: inline-block;
    69 }
    70 </style>
    View Code

            e)引入./src/icons/index.vue文件,在main.js文件中

    1 import * as Vue from 'vue'
    2 
    3 import SvgIcon from './icons/index.vue'
    4 
    5 import App from './App.vue'
    6 
    7 const app = Vue.createApp(App)
    8 app.component('svg-icon', SvgIcon)
    9 app.mount('#app')
    View Code

            f)编写./src/icons/svgBuilder.js文件,需要安装fs模块:npm install fs

     1 import { readFileSync, readdirSync } from 'fs'
     2 
     3 let idPerfix = ''
     4 const svgTitle = /<svg([^>+].*?)>/
     5 const clearHeightWidth = /(width|height)="([^>+].*?)"/g
     6 const hasViewBox = /(viewBox="[^>+].*?")/g
     7 const clearReturn = /(\r)|(\n)/g
     8 
     9 function svgFind(dir) {
    10   const svgRes = []
    11   const dirents = readdirSync(dir, {
    12     withFileTypes: true
    13   })
    14   for (const dirent of dirents) {
    15     if (dirent.isDirectory()) {
    16       svgRes.push(...svgFind(`${dir + dirent.name}/`))
    17     } else {
    18       const svg = readFileSync(dir + dirent.name)
    19         .toString()
    20         .replace(clearReturn, '')
    21         .replace(svgTitle, ($1, $2) => {
    22           let width = 0
    23           let height = 0
    24           let content = $2.replace(clearHeightWidth, (s1, s2, s3) => {
    25             if (s2 === 'width') {
    26               width = s3
    27             } else if (s2 === 'height') {
    28               height = s3
    29             }
    30             return ''
    31           })
    32           if (!hasViewBox.test($2)) {
    33             content += `viewBox="0 0 ${width} ${height}"`
    34           }
    35           return `<symbol id="${idPerfix}-${dirent.name.replace('.svg', '')}" ${content}>`
    36         })
    37         .replace('</svg>', '</symbol>')
    38       svgRes.push(svg)
    39     }
    40   }
    41   return svgRes
    42 }
    43 
    44 export const svgBuilder = (path, perfix = 'icon') => {
    45   if (path === '') return
    46   idPerfix = perfix
    47   const res = svgFind(path)
    48 
    49   return {
    50     name: 'svg-transform',
    51     transformIndexHtml(html) {
    52       return html.replace(
    53         '<body>',
    54         `
    55           <body>
    56             <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="position: absolute;  0; height: 0">
    57               ${res.join('')}
    58             </svg>
    59         `
    60       )
    61     }
    62   }
    63 }
    View Code

           g)配置vite.config.js文件,使svgBuilder.js文件功能启用

     1 import { defineConfig } from 'vite'
     2 import vue from '@vitejs/plugin-vue'
     3 import { svgBuilder } from './src/icons/svgBuilder'
     4 
     5 // https://vitejs.dev/config/
     6 export default defineConfig({
     7   base: './',
     8   plugins: [
     9     vue(),
    10     svgBuilder('./src/icons/svg/') // 这里已经将src/icons/svg/下的svg全部导入
    11   ]
    12 })
    View Code

           h)修改App.vue文件,编写测试示例

     1 <template>
     2   <img alt="Vue logo" src="@/assets/logo.png" />
     3   <div>
     4     <svg-icon icon-class="login-user" />
     5   </div>
     6   <router-view />
     7 </template>
     8 
     9 <script>
    10 export default {
    11   name: 'App'
    12 }
    13 </script>
    View Code

    3.3.查看效果:启动项目,命令:npm run dev。

    二、总结

    通过《vite+vue3》和《vite+vue3 2》两篇文章的记录,基本上把web开发中使用的基础模块和常用插件都记录了。

    三、参考信息

    1.https://blog.csdn.net/z591102/article/details/106787171/

    2.https://juejin.cn/post/6991233820410249252

    3.https://juejin.cn/post/6973288527802925092

  • 相关阅读:
    CentOS 7系统安装nginx+php
    LINUX VSFTP配置及安装
    linux的mount(挂载)命令详解
    nginx和tomcat的区别
    Linux上安装mysql5.7
    初学Java 二维数组找出最近的两个点
    初学Java 数组统计字母
    Struts2中获取Web元素request、session、application对象的四种方式
    jsp自定义标签
    自定义el函数
  • 原文地址:https://www.cnblogs.com/Jkinbor/p/16138418.html
Copyright © 2020-2023  润新知