buildAdmin开源项目引入四种图标方式详解

目录
  • 正文
  • 引入Element-Plus图标库
  • 引入Iconfont图标库
  • 引入FontAwesome图标库
  • 引入本地svg图标

正文

在项目开发中,我们经常使用可能都是UI组件库里的图标,当然由于业务需要,可能当前图标库没有我们需要的图标这时候就需要引入其它图标库的图标,比如iconfont、FontAweSome、本地图标库。在了解引入这些图标库之前,我们先学习一下各种图标库的引入使用:

Element-Plus:由于elemen官方已经把图标封装成了组件,所以当我们引入图标的时候,需要全局声明组件。

import * as Icons from '@element-plus/icons';
const app = createApp(App);
// 全局注册图标,牺牲一点性能
for (let i in Icons) {
// 官方图标名称首字母都是大写,所以转为小写,并命名组件未el-icon-图标名
app.component(`el-icon-${toLine(i)}`, (Icons as any)[i]);
}
// 组件中使用图标
<el-icon-user />

Iconfont:阿里巴巴图标库,通过创建一个项目目录,然后把我们需要的图标添加进去,然后在项目中引入图标目录的cdn(三种方式之一:css代码、css链接、js链接)就可以使用了,如果没有特殊处理一般是在项目的index.html中引入相关链接,css代码可以在根目录的样式文件中引入。然后就可以在项目中使用:

<i class="iconfont icon-user"></i>

FontAwesome:一个比较好用的字体图标库,可以直接通过cdn引入,也可以通过安装package包引入,然后就可以使用了:

英文官网:fontawesome.com/search

中文网:fontawesome.com.cn/

<i class="fa fa-user"></i>

引用本地图标:一般使用svg格式图标,因为svg性能好,相对于其它格式,它体积更小,可以任意放大图形显示,不以牺牲图标质量为代价,项目中是不能直接加载svg格式,需要额外插件实现(后面会详细介绍)。

<svg class="svg-icon icon" style="width: 1em;height: 1em;color: black;">
<use href="#local-vue" rel="external nofollow"  rel="external nofollow"  />
</svg>

为了方便维护以及扩展,我们可以把四种图标封装为统一组件使用,在封装前我们需要明确三点:

  • 获取所有图标。
  • 实现图标可复制,复制就可用的原则。
  • 图标使用统一组件。

在学习各类的图标库之前我们先了解一下如何封装一下图标共用组件,它向外暴露的名称是Icon:

实现组件健壮性、易维护:支持图标名称(name)、图标颜色(color)、图标大小(size)三要素的自定义。四种图标格式引入为element-plus(el-icon-iconName)、iconfont(iconfont iconName)、fontawesome(fa fa-iconName)、本地图标(local-iconName),iconName是图标名称。

props: {
name: {
  type: String,
  required: true,
},
size: {
  type: String,
  default: '30px',
},
color: {
  type: String,
  default: '#00000',
},
},
// 处理样式,去掉多余px命名
const iconStyle = computed((): CSSProperties => {
  const { size, color } = props;
  let s = `${size.replace('px', '')}px`;
  return {
    fontSize: s,
    color: color,
  };
});

兼容上面四种图标实现:通过Vue3的setup的返回值中使用渲染函数实现,不需要在template中定义标签使用,分三种情况。

createVNode函数:创建虚拟节点,从左到右有三个参数:html标签名称或组件(String)、标签属性(Object)、嵌套标签定义(Array)。

对于element-plus图标的渲染:官方是通过el-icon标签内直接使用图标组件,所以创建虚拟节点标签就是el-icon,由于图标组件是嵌套的,所以需要用到第三参数。

setup(props) {
    // 当前引入的是element-plus图标
    if (props.name.indexOf('el-icon-') === 0) {
      return () =>
        createVNode(
          'el-icon',
          { class: 'icon el-icon', style: iconStyle.value },
          [createVNode(resolveComponent(props.name))]
        );
    }
 }

对于iconfont、fontawesome图标的渲染:由于使用这两种的图标的标签都是i,它们唯一不同就是图标名称的命名所以可以共用同一个渲染函数。

setup(props){
 // 当前引入的是iconfont或fontawesome图标
 if (props.name.indexOf('local-') === 0 || isExternal(props.name)) {
 return () =>
    createVNode('i', {
      class: [props.name, 'icon'],
      style: iconStyle.value,
    });
  }
}

对于本地svg图标的渲染:直接引入本地封装的svg组件,把这个组件当作渲染标签,这里图标命名以local-iconName格式引入的。

setup(props){
 // 当前引入的是本地svg图标
 if (props.name.indexOf('local-') === 0 || isExternal(props.name)) {
  return () =>
    createVNode(svg, {
      name: props.name,
      size: props.size,
      color: props.color,
    });
  }
}

最终就可以通过这样使用图标:

<Icon name="" color="" size=""/>

其实上面就已经实现了四种图标的类型统一封装,一致使用。接下来为了更方便获取图标,我们把所有图标封装起来就可以直接cv使用了。

点击实现cv方式:通过点击图标传入我们想要复制的内容,一般都是整个组件的字符串。

export const useCopy = (text: string) => {
  let input = document.createElement('input'); // 创建输入框
  input.value = text; // 给输入框value赋值
  document.body.appendChild(input); // 追加到body里面去
  input.select(); // 选择输入框的操作
  document.execCommand('Copy'); // 执行复制操作
  document.body.removeChild(input); // 删除加入的输入框
  ElMessage.success('复制成功!');
};

引入Element-Plus图标库

import * as elIcons from '@element-plus/icons-vue';
// 获取所有Element-Plus图标组件名称,如搜索图标Search
export function getElementPlusIconfontNames() {
  return new Promise<string[]>((resolve, reject) => {
    nextTick(() => {
      const iconfonts = [];
      const icons = elIcons as any;
      // 遍历添加icons组件名称
      for (const i in icons) {
        iconfonts.push(icons[i].name);
      }
      if (iconfonts.length > 0) {
        resolve(iconfonts);
      } else {
        reject('No ElementPlus Icons');
      }
    });
  });
}

引入Iconfont图标库

先加载图标样式表:

const cssUrls: Array<string> = [
  '//at.alicdn.com/t/c/font_3846007_vf3shrhbpya.css', // 阿里图标库cs,每添加一次图标都需要更换
  '//cdn.bootcdn.net/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css', // font-awesome的css
];
export default function init() {
  // 遍历加载图标链接样式
  if (cssUrls.length > 0) {
    cssUrls.map((v) => {
      loadCss(v);
    });
  }
}
// 通过创建link标签引入样式链接
export function loadCss(url: string): void {
  const link = document.createElement('link'); // 创建link标签
  link.rel = 'stylesheet';
  link.href = url;
  // 是否采用跨域的方式加载。它可以取两个值
  // anonymous(跨域请求时,不发送用户凭证,主要是 Cookie)
  // use-credentials(跨域时发送用户凭证)。
  link.crossOrigin = 'anonmous';
  document.getElementsByTagName('head')[0].appendChild(link);
}

获取当前页面中从指定域名加载到的样式表内容:在调用这个函数之前必须要先引入样式。

// 获取样式表内容
function getStylesFromDomain(domain: string) {
  const sheets = [];
  const styles: StyleSheetList = document.styleSheets;
  for (const key in styles) {
    if (styles[key].href && (styles[key].href as string).indexOf(domain) > -1) {
      sheets.push(styles[key]);
    }
  }
  return sheets;
}

调用这个函数之后就可以获取到当前图标库相关样式表内容,我们的目的就是拿到图标名称,可以提取rules数组内的样式名称就可以拿到所有图标名称了。

// 获取所有iconfont图标库图标名称
export function getIconfontNames() {
  init();
  return new Promise<string[]>((resolve, reject) => {
    nextTick(() => {
      const iconfonts = [];
      const sheets = getStylesFromDomain('at.alicdn.com');
      for (const key in sheets) {
        const rules: any = sheets[key].cssRules;
        for (const k in rules) {
          // .表示匹配除换行符 \n 之外的任何单字符
          // *表示单个字符匹配任意次
          if (
            rules[k].selectorText &&
            /^\.icon-(.*)::before$/g.test(rules[k].selectorText)
          ) {
            // 去掉样式的.符号以及::before
            iconfonts.push(
              `${rules[k].selectorText
                .substring(1, rules[k].selectorText.length)
                .replace(/\:\:before/gi, '')}`
            );
          }
        }
      }
      if (iconfonts.length > 0) {
        resolve(iconfonts);
      } else {
        reject('No Iconfont style sheet');
      }
    });
  });
}

引入FontAwesome图标库

先加载图标样式表:也就是直接调用init函数,加载相应的样式链接。

获取当前页面中从指定域名加载到的样式表内容:如下图所示。

export function getAwesomeIconfontName() {
  init();
  return new Promise<string[]>((resolve, reject) => {
    nextTick(() => {
      const iconfonts = [];
      // 获取所有图标名称
      const sheets = getStylesFromDomain(
        'cdn.bootcdn.net/ajax/libs/font-awesome/'
      );
      for (const key in sheets) {
        const rules: any = sheets[key].cssRules;
        // 处理方法与iconfont一致,只不过名称不一样
        for (const k in rules) {
          if (
            rules[k].selectorText &&
            /^\.fa-(.*)::before$/g.test(rules[k].selectorText)
          ) {
            if (rules[k].selectorText.indexOf(', ') > -1) {
              // selectorText里有多个图标,只提取第一个
              const iconNames = rules[k].selectorText.split(', ');
              iconfonts.push(
                `${iconNames[0]
                  .substring(1, iconNames[0].length)
                  .replace(/\:\:before/gi, '')}`
              );
            } else {
              iconfonts.push(
                `${rules[k].selectorText
                  .substring(1, rules[k].selectorText.length)
                  .replace(/\:\:before/gi, '')}`
              );
            }
          }
        }
      }
      if (iconfonts.length > 0) {
        resolve(iconfonts);
      } else {
        reject('No AwesomeIcon style sheet');
      }
    });
  });
}

引入本地svg图标

在引入本地svg图标之前,我们先了解一下svg标签的相关知识:

什么是svg?

svg:即 Scalable Vector Graphics,是一种用来绘制矢量图的 HTML5 标签,与canvas有点类似,它可以像HTML画布一样用于制作图形和动画。

svg标签常见属性有:

svg标签内部常见的绘制标签有:

  • x: x轴协调图像的位置。
  • y: y轴协调图像的位置。
  • width: 图像的宽度。
  • height: 图片的高度。
  • viewBox: SVG元素的界限。
  • id、class属性
  • fill:svg元素的填充颜色。
  • stroke:svg 元素的描边颜色,例如线条、文本等描边颜色。
  • ....
  • <line> 标签:绘制一条直线。
  • <rect> 标签:绘制一个矩形。
  • <polygon> 标签:绘制一个多边形。
  • <circle> 标签:绘制一个圆形。
  • <ellipse> 标签:绘制一个椭圆。
  • <path> 标签:于绘制路径,其是 svg 基本形状中最强大的一个,你可以用它创建线条,曲线,弧形,圆等各种形状,其具有 d 属性,用于指定一系列绘制的命令,命令后面接坐标。

如何加载svg?

在html中如何定义svg:在svg标签内定义绘制图形的标签。

// 方式一:只能定义一个svg图标
<svg class="hamburger" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="64" height="64">
<path
  d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
</svg>
/* 方式二:可定义多个svg图标,需要symbol标签配合,把绘制标签定义在symbol标签内 */
/* 一般是在index.html文件中body标签下定义 */
<svg>
   // 一个symbol定义代表一个图标
   <symbol id="local-vue"></symbol>
   <symbol id="local-logo"></symbol>
   ...
</svg>
/* 然后就可以在组件中实例化使用 */
<svg><use href="#local-vue" rel="external nofollow"  rel="external nofollow" ></use></svg>

封装加载svg插件?

去掉svg标签,只取svg标签内部的绘制内容。

let idPrefix = '';
const iconNames: string[] = [];
const svgTitle = /<svg([^>+].*?)>/;
const clearHeightWidth = /(width|height)="([^>+].*?)"/g;// 清空宽高
const hasViewBox = /(viewBox="[^>+].*?")/g;// 是否有ViewBox属性
const clearReturn = /(\r)|(\n)/g; // 清空换行符
const clearFill = /(fill="[^>+].*?")/g; // 清理 svg 的 fill
// 查找svg所有文件
function findSvgFile(dir: string = '../../../assets/icons/'): string[] {
  const svgRes = [];
  // readdirSync,返回一个包含“指定目录下所有文件名称”的数组对象
  // [ Dirent { name: 'vue.svg', [Symbol(type)]: 1 } ]
  const dirents = readdirSync(dir, {
    withFileTypes: true,
  });
  console.log(dirents);
  for (const dirent of dirents) {
    iconNames.push(`${idPrefix}-${dirent.name.replace('.svg', '')}`); // [ 'local-vue' ]
    // 如果path表示的是一个目录则返回true
    if (dirent.isDirectory()) {
      svgRes.push(...findSvgFile(dir + dirent.name + '/'));
    } else {
      const svg = readFileSync(dir + dirent.name)
        .toString().replace(clearReturn, '').replace(clearFill,
        'fill=""'.replace(svgTitle, ($1, $2) => {
          let width = 0;
          let height = 0;
          let content = $2.replace(clearHeightWidth,
            (s1: string, s2: string, s3: number) => {
              if (s2 === 'width') {
                width = s3;
              } else if (s2 === 'height') {
                height = s3;
              }
              return '';
            }
          );
          if (!hasViewBox.test($2)) {
            content += `viewBox="0 0 ${width} ${height}"`;
          }
          // 去掉扩展名
          return `<symbol id="${idPrefix}-${dirent.name.replace(
            '.svg',
            ''
          )}" ${content}>`;
        })
        .replace('</svg>', '</symbol>');// 替换尾部标签
      svgRes.push(svg);
    }
  }
  return svgRes;
}

转化为真正渲染的html,在vite.config中的plugin插件属性中引入svgBuilder并传入存放svg图标的路径。

/**
 *
 * @param path // 所有svg图标存放地址
 * @param perfix // 图标自定义前缀
 * @returns
 */
export const svgBuilder = (path: string, perfix = 'local') => {
  if (path === '') return;
  idPrefix = perfix;
  // 每个图标都是symbol标签,去掉了svg标签,只包含的svg内部嵌套标签,res是一个数组,每个元素就是一个图标
  const res = findSvgFile(path);
  return {
    name: 'svg-transform',
    transformIndexHtml(html: string) {
      /* eslint-disable */
      return html.replace(
        '<body>',
        `
        <body>
        <svg id="local-icon" data-icon-name="${iconNames.join(',')}"
        xmlns="http://www.w3.org/2000/svg"
        xmlns:xlink="http://www.w3.org/1999/xlink"
        style="position: absolute; width: 0; height: 0">
        ${res.join('')}
        </svg>
        `
      );
      /* eslint-enable */
    },
  };
};

获取所有本地图标名称通过定义id,由于封装插件的时候已经定义了元素id="local-icon",所以可以全局定义获取。下面获取到的svgEl值如图所示。

export function getLocalIconfontNames() {
  return new Promise<string[]>((resolve, reject) => {
    nextTick(() => {
      let iconfonts: string[] = [];
      const svgEl = document.getElementById('local-icon');
      // 判断DOMStringMap对象内的iconName属性是否有值
      if (svgEl?.dataset.iconName) {
        iconfonts = (svgEl?.dataset.iconName as string).split(',');
      }
      if (iconfonts.length > 0) {
        resolve(iconfonts);
      } else {
        reject('No Local Icons!');
      }
    });
  });
}

参考资料

以上就是buildAdmin开源项目引入四种图标方式详解的详细内容,更多关于buildAdmin引入图标的资料请关注我们其它相关文章!

(0)

相关推荐

  • 基于Vue实现自定义组件的方式引入图标

    前言 在项目开发中,使用图标的方式有很多种,可以在iconfont上面找到合适的图标,通过http或者直接下载使用,这里我分享一种通过实现自定义组件的方式引入图标. 搭建环境 这里通过@vue/cli 4.5.13新建项目,并且需要安装依赖svg-sprite-loader,用来处理对应的svg图标,方便我们使用. 安装: npm install --save-dev svg-sprite-loader 配置vue.config.js 在安装svg-sprite-loader后,新建vue.co

  • 微信小程序里引入SVG矢量图标的方法

    引言 因为微信小程序的限制,引入外部图片或者矢量图,只能通过设置背景图片background-image : url("base64转码后的代码");的方式来进行操作.同时还是因为微信小程序的限制,我们要先把svg的xml编码转码为base64编码 首先,说明以下我们常见的svg矢量图是什么?下面引用百度百科的话: svg是基于可扩展标记语言(标准通用标记语言的子集),用于描述二维矢量图形的一种图形格式 可能还是比较迷糊,那我们来看看,用记事本打开一个svg,里面的编码是什么: <

  • vue项目引入svg图标的完整步骤

    目录 1. 安装svg依赖 2. 创建svg文件夹存放svg图标 3. vue.config.js 中配置svg图片 4. 创建index.js 导入所有svg图标 5. main.js中引入icons/index.js 6. 创建SvgIcon公用组件 总结 1. 安装svg依赖 在vue中首先需要安装可以加载svg的依赖. npm安装:npm install svg-sprite-loader --save-dev 2. 创建svg文件夹存放svg图标 创建icons文件夹,在icons文件

  • Vant的Tabbar标签栏引入自定义图标方式

    目录 Tabbar标签栏引入自定义图标 vant自义定Tabbar图标和颜色 Tabbar标签栏引入自定义图标 **使用*van-tabbar*组件** *v-model*绑定的是对应的Tabbar下标 *active-color*是未选中的文字颜色 *inactive-color*是已选中的文字颜色 **route**这个要特别注意,我就是在这踩了坑,我没有加这个参数,但是能正常跳转路由,但是图标选中会出现问题,每次都需要双击.一直以为是插槽的问题,后面才发现官方api的这个参数 *van-t

  • Vue中引入svg图标的两种方式

    Vue中引入svg图标的方式 Vue中引入svg图标的方式一 安装 yarn add svg-sprite-loader --dev svg组件 index.vue <!-- svg组件 --> <template> <svg class="svg-icon" :class="svgClass" aria-hidden="true"> <use :xlink:href="iconName&quo

  • flutter项目引入iconfont阿里巴巴图标

    目录 下载图标 使用图标 注意 下载图标 这里直接去iconfont阿里巴巴矢量图标库,选好自己需要的图标,点击如下图所示[添加到库] 然后选择头像左侧的购物车图标 然后点击下载代码 引入图标 解压完打开文件夹可以看到如下文件列表,我们将.ttf文件放在项目的静态资源文件夹中[我直接放在asset文件夹下] 接着我们在项目的pubspec.yaml文件夹下引入字体文件,并设置字体族名称 fonts: - family: Iconfont fonts: - asset: asset/fonts/i

  • buildAdmin开源项目引入四种图标方式详解

    目录 正文 引入Element-Plus图标库 引入Iconfont图标库 引入FontAwesome图标库 引入本地svg图标 正文 在项目开发中,我们经常使用可能都是UI组件库里的图标,当然由于业务需要,可能当前图标库没有我们需要的图标这时候就需要引入其它图标库的图标,比如iconfont.FontAweSome.本地图标库.在了解引入这些图标库之前,我们先学习一下各种图标库的引入使用: Element-Plus:由于elemen官方已经把图标封装成了组件,所以当我们引入图标的时候,需要全局

  • Android开发之基本控件和四种布局方式详解

    Android中的控件的使用方式和iOS中控件的使用方式基本相同,都是事件驱动.给控件添加事件也有接口回调和委托代理的方式.今天这篇博客就总结一下Android中常用的基本控件以及布局方式.说到布局方式Android和iOS还是区别挺大的,在iOS中有Frame绝对布局和AutoLayout相对布局.而在Android中的布局方式就比较丰富了,今天博客中会介绍四种常用的布局方式.先总结一下控件,然后再搞一搞基本方式,开发环境还是用的Mac下的Android Studio.开始今天的正题, 虽然A

  • Spring Data Jpa的四种查询方式详解

    这篇文章主要介绍了Spring Data Jpa的四种查询方式详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一.调用接口的方式 1.基本介绍 通过调用接口里的方法查询,需要我们自定义的接口继承Spring Data Jpa规定的接口 public interface UserDao extends JpaRepository<User, Integer>, JpaSpecificationExecutor<User> 使用这

  • Java二叉树的四种遍历方式详解

    二叉树的四种遍历方式: 二叉树的遍历(traversing binary tree)是指从根结点出发,按照某种次序依次访问二叉树中所有的结点,使得每个结点被访问依次且仅被访问一次. 四种遍历方式分别为:先序遍历.中序遍历.后序遍历.层序遍历. 遍历之前,我们首先介绍一下,如何创建一个二叉树,在这里用的是先建左树在建右树的方法, 首先要声明结点TreeNode类,代码如下: public class TreeNode { public int data; public TreeNode leftC

  • Java动态代理四种实现方式详解

    代理模式也是一种非常常见的设计模式.了解Spring框架的都知道,Spring AOP 使用的就是动态代理模式.今天就来系统的重温一遍代理模式. 在现实生活中代理是随处可见的,当事人因某些隐私不方便出面,或者当事人不具备某些相关的专业技能,而需要一个职业人员来完成一些专业的操作, 也可能由于当事人没有时间处理事务,而聘用代理人出面.而在软件设计中,使用代理模式的地方也很多,由于安全原因,屏蔽客户端直接访问真实对象, 或者为了提升系统性能,使用代理模式实现延迟加载,还有就是AOP,对委托类的功能进

  • Spring bean 四种注入方式详解

    目录 一.Set方式注入 pojo层: 1.xml 文件 test测试 二.构造函数方式注入 pojo层 2.xml文件 test测试 三.注解注入 pojo层 3.xml文件 test测试 四.JavaConfig 方式注入 pojo层 JavaConfig 类 xml文件 扫描包 测试: 五.Service层注入详解 service serviceImpl xml配置文件 总结 一.Set方式注入 pojo层: /** * @Author: crush * @Date: 2021-06-17

  • Spring中Bean的三种实例化方式详解

    目录 一.环境准备 二.构造方法实例化 三.分析Spring的错误信息 四.静态工厂实例化 4.1 工厂方式创建bean 4.2 静态工厂实例化 五.实例工厂与FactoryBean 5.1 环境准备 5.2 实例工厂实例化 5.3 FactoryBean的使用 六.bean实例化小结 一.环境准备 准备开发环境 创建一个Maven项目 pom.xml添加依赖 resources下添加spring的配置文件applicationContext.xml 最终项目的结构如下: 二.构造方法实例化 在

  • 关于react-router的几种配置方式详解

    本文介绍关于react-router的几种配置方式详解,分享给大家,具体如下: 路由的概念 路由的作用就是将url和函数进行映射,在单页面应用中路由是必不可少的部分,路由配置就是一组指令,用来告诉router如何匹配url,以及对应的函数映射,即执行对应的代码. react-router 每一门JS框架都会有自己定制的router框架,react-router就是react开发应用御用的路由框架,目前它的最新的官方版本为4.1.2.本文给大家介绍的是react-router相比于其他router

  • Python selenium 三种等待方式详解(必会)

    很多人在群里问,这个下拉框定位不到.那个弹出框定位不到-各种定位不到,其实大多数情况下就是两种问题:1 有frame,2 没有加等待.殊不知,你的代码运行速度是什么量级的,而浏览器加载渲染速度又是什么量级的,就好比闪电侠和凹凸曼约好去打怪兽,然后闪电侠打完回来之后问凹凸曼你为啥还在穿鞋没出门?凹凸曼分分中内心一万只羊驼飞过,欺负哥速度慢,哥不跟你玩了,抛个异常撂挑子了. 那么怎么才能照顾到凹凸曼缓慢的加载速度呢?只有一个办法,那就是等喽.说到等,又有三种等法,且听博主一一道来: 1. 强制等待

  • JSP中九大内置对象和四种属性范围详解

    JSP中九大内置对象和四种属性范围详解 一般对象需要实例化才可以调用,而JSP的内置对象是不用实例化就可以直接调用的对象. 总共有9个,对应如下表: 序号 对象 类型 1 pageContext javax.servlet.jsp.PageContext 2 request javax.servlet.http.HttpServletRequest 3 response javax.servlet.http.HttpServletResponse 4 session javax.servlet.

随机推荐