胖蔡叨叨叨
你听我说

使用docxjs实现前端的word生成

胖蔡阅读(1360)

Docx 可以帮助我们实现ts/js代码生成*.docx文件的功能,它可以同时被运用于Node端和浏览器端。使用docx基本可以实现大多数Microsoft Word文档英文版的绝大数API操作,但由于Microsoft Word文档中英文版本的差异,对于中文版本的功能、属性控制还是得需要通过自定义xml的方式来实现。本篇文章简单介绍下如何使用docxjs实现word文档的生成。

2c26b65871ed768

可访问官网查看官方文档:https://docx.js.org/   。我始终坚持认为,官方文档是最能帮助开发者的。

安装

$ npm install -s docx

基本用法

import * as fs from "fs"; 
import { Document, Packer, Paragraph, TextRun } from "docx";

 // 文档类Document中包含章节数组sections,可向其中添加多个章节 
const doc = new Document({ 
      sections: [{ 
          properties: {}, 
          children: [ new Paragraph({ 
             children: [ new TextRun("Hello World"), 
                  new TextRun({ text: "Foo Bar", bold: true, }),
                  new TextRun({ text: "\tGithub is the best", bold: true, }), ], }), ], }], }); 

// 通过fs实现将docx从buffer流转化成*.docx文件

 Packer.toBuffer(doc).then((buffer) => { fs.writeFileSync("My Document.docx", buffer); }); // 完成下载


通过上方的示例,可以发现docx将整个文档拆分成多个区域块,然后通过组合、包含区域块的方式实现文档的输出。下面,简单介绍下docx中常用的几个模块类。

Document

Document可以说是docx梦开始的地方。其实,我们也可以将其理解为docx文档本生。一个docx文档有且仅有一个document生成。可以通过如下方式生成一个基本的document对象。
const doc = new docx.Document();
document很重要,包含的属性有如下:
  • creator
  • description
  • title
  • subject
  • keywords
  • lastModifiedBy
  • revision
  • externalStyles
  • styles
  • numbering
  • footnotes
  • hyperlinks
  • background
  • sections
这里重点介绍externalStyles、styles。

externalStyles

这个属性对于我们的中文用户来说尤为重要,这或许也是docx作者考虑可能属性覆盖不全,所以特意留下的一个自定义属性样式的窗口。功能可以说是及其省事。我们完全可以通过解压docx文档,将其中的xml属性配置文件拿出来做些微的修改来实现我们的功能。大致就像下面这样。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:styles xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
    xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
    xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml"
    xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" mc:Ignorable="w14 w15">
    <w:docDefaults>
        <w:rPrDefault>
            <w:rPr>
                <w:rFonts w:asciiTheme="minorHAnsi" w:eastAsiaTheme="minorHAnsi" w:hAnsiTheme="minorHAnsi" w:cstheme="minorBidi"/>
                <w:sz w:val="22"/>
                <w:szCs w:val="22"/>
                <w:lang w:val="en-GB" w:eastAsia="en-US" w:bidi="ar-SA"/>
            </w:rPr>
        </w:rPrDefault>
        <w:pPrDefault>
            <w:pPr>
                <w:spacing w:after="160" w:line="259" w:lineRule="auto"/>
            </w:pPr>
        </w:pPrDefault>
    </w:docDefaults>

 

    <w:style w:type="paragraph" w:default="1" w:styleId="Normal">
        <w:name w:val="Normal"/>
        <w:qFormat/>
        <w:rsid w:val="000D2D99"/>
        <w:rPr>
            <w:rFonts w:ascii="MV Boli" w:hAnsi="MV Boli"/>
            <w:color w:val="C45911" w:themeColor="accent2" w:themeShade="BF"/>
        </w:rPr>
    </w:style>

    <w:style w:type="paragraph" w:styleId="Heading1">
        <w:name w:val="heading 1"/>
        <w:basedOn w:val="Normal"/>
        <w:next w:val="Normal"/>
        <w:link w:val="Heading1Char"/>
        <w:uiPriority w:val="9"/>
        <w:qFormat/>
        <w:rsid w:val="000D2D99"/>
        <w:pPr>
            <w:keepNext/>
            <w:keepLines/>
            <w:spacing w:before="240" w:after="0"/>
            <w:outlineLvl w:val="0"/>
        </w:pPr>
        <w:rPr>
            <w:rFonts w:ascii="Impact" w:eastAsiaTheme="majorEastAsia" w:hAnsi="Impact" w:cstheme="majorBidi"/>
            <w:color w:val="538135" w:themeColor="accent6" w:themeShade="BF"/>
            <w:sz w:val="32"/>
            <w:szCs w:val="32"/>
        </w:rPr>
    </w:style>

    <w:style w:type="character" w:default="1" w:styleId="DefaultParagraphFont">
        <w:name w:val="Default Paragraph Font"/>
        <w:uiPriority w:val="1"/>
        <w:semiHidden/>
        <w:unhideWhenUsed/>
    </w:style>

    <w:style w:type="table" w:default="1" w:styleId="TableNormal">
        <w:name w:val="Normal Table"/>
        <w:uiPriority w:val="99"/>
        <w:semiHidden/>
        <w:unhideWhenUsed/>
        <w:tblPr>
            <w:tblInd w:w="0" w:type="dxa"/>
            <w:tblCellMar>
                <w:top w:w="0" w:type="dxa"/>
                <w:left w:w="108" w:type="dxa"/>
                <w:bottom w:w="0" w:type="dxa"/>
                <w:right w:w="108" w:type="dxa"/>
            </w:tblCellMar>
        </w:tblPr>
    </w:style>

    <w:style w:type="table" w:customStyle="1" w:styleId="MyCustomTableStyle">
        <w:name w:val="My Custom TableStyle"/>
        <w:uiPriority w:val="99"/>
        <w:rsid w:val="00C36BA2"/>
        <w:pPr>
            <w:spacing w:after="0" w:line="240" w:lineRule="auto"/>
        </w:pPr>
        <w:rPr>
            <w:rFonts w:ascii="Comic Sans MS" w:hAnsi="Comic Sans MS"/>
            <w:szCs w:val="20"/>
            <w:lang w:val="en-US"/>
        </w:rPr>

        <w:tcPr>
            <w:shd w:val="clear" w:color="auto" w:fill="auto"/>
        </w:tcPr>

        <w:tblStylePr w:type="firstRow">

            <w:rPr>
                <w:b/>
                <w:bCs/>
                <w:color w:val="FFFFFF" w:themeColor="background1"/>
            </w:rPr>

            <w:tblPr/>

            <w:tcPr>
                <w:tcBorders>
                    <w:tl2br w:val="none" w:sz="0" w:space="0" w:color="auto"/>
                    <w:tr2bl w:val="none" w:sz="0" w:space="0" w:color="auto"/>
                </w:tcBorders>
                <w:shd w:val="clear" w:color="auto" w:fill="4472C4" w:themeFill="accent1"/>
            </w:tcPr>

        </w:tblStylePr>

    </w:style>

    <w:style w:type="numbering" w:default="1" w:styleId="NoList">
        <w:name w:val="No List"/>
        <w:uiPriority w:val="99"/>
        <w:semiHidden/>
        <w:unhideWhenUsed/>
    </w:style>

    <w:style w:type="paragraph" w:customStyle="1" w:styleId="CustomStyle">
        <w:name w:val="Custom Style"/>
        <w:basedOn w:val="Normal"/>
        <w:link w:val="CustomStyleChar"/>
        <w:rsid w:val="00B557A5"/>
        <w:rPr>
            <w:sz w:val="72"/>
        </w:rPr>
    </w:style>

    <w:style w:type="character" w:customStyle="1" w:styleId="CustomStyleChar">
        <w:name w:val="Custom Style Char"/>
        <w:basedOn w:val="DefaultParagraphFont"/>
        <w:link w:val="CustomStyle"/>
        <w:rsid w:val="00B557A5"/>
        <w:rPr>
            <w:rFonts w:ascii="MV Boli" w:hAnsi="MV Boli"/>
            <w:color w:val="C45911" w:themeColor="accent2" w:themeShade="BF"/>
            <w:sz w:val="72"/>
        </w:rPr>
    </w:style>

    <w:style w:type="character" w:customStyle="1" w:styleId="Heading1Char">
        <w:name w:val="Heading 1 Char"/>
        <w:basedOn w:val="DefaultParagraphFont"/>
        <w:link w:val="Heading1"/>
        <w:uiPriority w:val="9"/>
        <w:rsid w:val="000D2D99"/>
        <w:rPr>
            <w:rFonts w:ascii="Impact" w:eastAsiaTheme="majorEastAsia" w:hAnsi="Impact" w:cstheme="majorBidi"/>
            <w:color w:val="538135" w:themeColor="accent6" w:themeShade="BF"/>
            <w:sz w:val="32"/>
            <w:szCs w:val="32"/>
        </w:rPr>
    </w:style>

    <w:style w:type="paragraph" w:customStyle="1" w:styleId="MyFancyStyle">
        <w:name w:val="MyFancyStyle"/>
        <w:basedOn w:val="Normal"/>
        <w:link w:val="MyFancyStyleChar"/>
        <w:qFormat/>
        <w:rsid w:val="008802A5"/>
        <w:rPr>
            <w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman"/>
            <w:color w:val="FF0000"/>
            <w:sz w:val="144"/>
        </w:rPr>

    </w:style>

    <w:style w:type="paragraph" w:customStyle="1" w:styleId="subject">
        <w:name w:val="subject"/>
        <w:basedOn w:val="Normal"/>
        <w:link w:val="subjectChar"/>
        <w:qFormat/>
        <w:rsid w:val="008802A5"/>
        <w:textAlignment w:val="center"/>
        <w:rPr>
            <w:rFonts w:hint="eastAsia" w:ascii="仿宋_GB2312" w:hAnsi="仿宋_GB2312" w:eastAsia="仿宋_GB2312" w:cs="仿宋_GB2312"/>
            <w:sz w:val="24"/>
            <w:szCs w:val="24"/>
            <w:lang w:val="en-US" w:eastAsia="zh-CN"/>
             <w:color w:val="FF0000"/>
        </w:rPr>

    </w:style>

     <w:style w:type="character" w:customStyle="1" w:styleId="subjectChar">
        <w:name w:val="subject Char"/>
        <w:basedOn w:val="DefaultParagraphFont"/>
        <w:link w:val="subject"/>
        <w:rsid w:val="008802A5"/>

        <w:rPr>
           <w:rFonts w:hint="eastAsia" w:ascii="仿宋_GB2312" w:hAnsi="仿宋_GB2312" w:eastAsia="仿宋_GB2312" w:cs="仿宋_GB2312"/>
            <w:sz w:val="24"/>
            <w:szCs w:val="24"/>
            <w:lang w:val="en-US" w:eastAsia="zh-CN"/>
             <w:color w:val="FF0000"/>

        </w:rPr>

    </w:style>

    <w:style w:type="character" w:customStyle="1" w:styleId="MyFancyStyleChar">
        <w:name w:val="MyFancyStyle Char"/>
        <w:basedOn w:val="DefaultParagraphFont"/>
        <w:link w:val="MyFancyStyle"/>
        <w:rsid w:val="008802A5"/>

        <w:rPr>
            <w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman"/>
            <w:color w:val="FF0000"/>
            <w:sz w:val="144"/>
        </w:rPr>
    </w:style>

</w:styles>
import * as fs from "fs"; 
import { Document, Packer, Paragraph, TextRun } from "docx";
import  { xmlStyles } from './xmlStyles';

 // 文档类Document中包含章节数组sections,可向其中添加多个章节 
const doc = new Document({ 
      externalStyles:xmlStyles,
      sections: [{ 
          properties: {}, 
          children: [ new Paragraph({ 
             children: [ new TextRun("Hello World"), 
                  new TextRun({ text: "Foo Bar", bold: true, }),
                  new TextRun({ text: "\tGithub is the best", bold: true, }), ], }), ], }], }); 

// 通过fs实现将docx从buffer流转化成*.docx文件

 Packer.toBuffer(doc).then((buffer) => { fs.writeFileSync("My Document.docx", buffer); }); // 完成下载


styles

styles也属于样式自定义的一种方式,但这里的方式定义方式是局限于当前docx提供的属性,我们可以在docx的section、Paragraph、Text、Header等中使用。
import * as fs from "fs"; 
import { Document, Packer, Paragraph, TextRun } from "docx";


/**  * 获取自定义段落格式  */ 

function getParagraphStyles() {   
  return [ {        
     id: 'tips', // 温馨提示      
     name: 'tips',           
     basedOn: "Normal",          
     next: "Normal",            
     quickFormat: true,            
     paragraph: {
                 border: {
                     top: borderStyle,
                     left: borderStyle,
                     right: borderStyle, 
                    bottom: borderStyle
                 }
             }
         }, 
 {
             id: 'section', // 题型段落
             name: 'section',
             basedOn: "Normal",
             next: "Normal", 
            quickFormat: true,
             paragraph: { 
                indent: indent,
                spacing: {
                    before: '2pc'
                 }, 
            }
         },
     ]
 }

 // 文档类Document中包含章节数组sections,可向其中添加多个章节 
const doc = new Document({ 
      sections: [{ 
          properties: {}, 
          children: [ new Paragraph({ 
             children: [ new TextRun("Hello World"), 
                  new TextRun({ text: "Foo Bar", bold: true, }),
                  new TextRun({ text: "\tGithub is the best", bold: true, }), ], }), ], }], }); 

// 通过fs实现将docx从buffer流转化成*.docx文件

 Packer.toBuffer(doc).then((buffer) => { fs.writeFileSync("My Document.docx", buffer); }); // 完成下载


React使用Ant Design Pro框架导致首屏加载缓慢问题

胖蔡阅读(431)

存在问题

React项目中使用Ant Design pro框架,发现编译后前端应用的首屏加载过于缓慢,针对该问题,对改应用的生成包进行分析并优化,使其加载速度提升,用户体验更好。整个优化的思路过程如下。

1、网页登录后,首次刷新【存在路由】,加载时长过大,用户体验不佳

0
0

存在的相关关键指标:

  • DOMCOntentLoaded:7.32s
  • Load:32.21s
  • Finish:32.90s
  • layout.async.js:23.29s
  • misc.async.js:14.53s

解决思路

根据上面出现的问题分析可以通过如下几个方面对包的大小和加载的必要性进行拆分优化:
  1. 拆出页面包
  2. 裁剪vendors,将@ant-design、antd、docx包单独拆出一个文件,降低load的响应时间,
  3. 替换@ant-design/chats 为 @antv/g2plot,减少可视化组件包的大小
const webpackPlugin = config => {   // optimize chunks   config.optimization // share the same chunks across different modules     .runtimeChunk(false)     .splitChunks({       // chunks: 'async',       name: 'vendors',       chunks: 'async',       minSize: 20000,       minChunks: 1,       maxAsyncRequests: 30,       maxInitialRequests: 30,       cacheGroups: {         vendors: {           test: module => {             const packageName = getModulePackageName(module) || '';             // console.log('get splitChunks vendors:',packageName)             if (packageName) {               return [                 '@antv',                 '@ant-design',                 'antd',                 'docx',                 'l7',                 'gg-editor-core',                 'bizcharts-plugin-slider',               ].includes(packageName);             }             return false;           },           name(module) {             const packageName = getModulePackageName(module);             if (packageName) {               // console.log('get splitChunks name:', packageName);               if (['@ant-design', 'antd'].indexOf(packageName) >= 0) {                 return 'ant-design'; // visualization package               } else if (['docx'].indexOf(packageName) >= 0) {                 // 单独拆开                 return 'docx';               }             }             return 'misc';           },         },       },     }); };

结果

1、gzip降低

22165adbf146e2b
原始的
51433a6450391ca
总包大小以及layout.async.js、vendors.async.js大小均有显著缩小

2、请求数据

cd2907c13172429

存在的相关关键指标:

  • DOMCOntentLoaded:7.72s
  • Load:13.96s
  • Finish:14.68s
  • misc.async.js:3.57s
  • umi.js:7.30s

Webpack 项目添加 eslint 实现代码检测功能

胖蔡阅读(282)

项目环境及相关资料

依赖库

1、eslint-loader
想要 webpack 实现 eslint 的检测,首先需要安装 loader eslint-loader ,并在配置文件中添加加载规则:


// 使用npm
npm install --save-dev eslint-loader

// 使用yarn
$yarn add -D eslint-loader
// webpack.config.js

{
...
  module: {
    rules: [
      {
        test/\.js$/,
        loader"eslint-loader",
         exclude/node_modules/,
        enforce"pre",
        include: [path.resolve(__dirname, "src")], // 指定检查的目录
        options: {
          // 这里的配置项参数将会被传递到 eslint  CLIEngine
          formatterrequire("eslint-friendly-formatter"), // 指定错误报告的格式规范
      //  fix: true, // 自动修正,会改变文件内容,根据需要配置
        },
      },
    ];
  }
  ...
}

2、 eslint

为了能使项目具有eslint检测功能,我们需要安装eslint依赖库,并生成配置eslint配置文件.

// npm 
npm install --save-dev eslint

// yarn
yarn add -D eslint

eslint的配置文件有很多类型,可以是 .eslintrc,也可以是 .eslint.js又或者是 .eslint.json,这里以.eslintrc.js为例,给出一个示例配置:

这里需要注意的是eslint的配置,需要配置一个错误级别,通常错误级别有三个类别:

  • “off” or 0 – 关闭规则
  • “warn” or 1 – 开启规则,使用警告级别的错误:warn (不会导致程序退出)
  • “error” or 2 – 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出)
/* eslint-disable no-undef */
module.exports = {
    'env': {
        'browser'true,
        'es2021'true,
    },
    'extends''eslint:recommended',
    'parserOptions': {
        'ecmaVersion'13,
        'sourceType''module',
    },
    'rules': {
        'no-console': process.env.NODE_ENV === 'production''error''off'// allow console during development
        'no-debugger': process.env.NODE_ENV === 'production''error''off'// allow debugger during development
        // 以下为该项目自定义部分
        'indent': ['error'4], //缩进风格 - 开启缩进4
        'max-len': ['error', {
            'code'120,         // 强制单行的最大长度为120
            'comments'120,    // 强制单行注释的最大长度为120    
        }],
        'space-in-parens': ['error''always'], // 强制圆括号内有一个空格
        'curly': ['error''multi''consistent'], //   ifelse if  else 所有的代码块使用或者不使用大括号。
        'keyword-spacing':['warn',{         // 关键字前后需要保持至少有一个空格
            'before'true,
            'after'true,
        }],
        'lines-around-comment':['warn',{        
            'beforeBlockComment'true,
            'afterBlockComment'true,
        }],
        'one-var-declaration-per-line': ['error''initializations'], // 强制每个变量初始化语句换行
        'comma-dangle': ['error''always-multiline'], //  当最后一个元素或属性与闭括号 ]  }  不同的行时,要求使用拖尾逗号;当在 同一行时,禁止使用拖尾逗号。
        'quotes': ['error''single'], // 要求尽可能地使用单引号
        'no-nested-ternary''error'// 禁止使用嵌套的三元表达式
        'multiline-ternary': ['error''always-multiline'], // 如果表达式跨越多个行,则在三元表达式的操作数之间强制换行
        'wrap-iife': ['error''any'], // 强制总是包裹,但允许其它风格。
        'no-new-wrappers''error'// 禁止对 StringNumber  Boolean 使用 new 操作符
        'no-var''error'// 要求使用 let  const 而不是 var
        'no-duplicate-imports''error'// 禁止重复模块导入
        'eol-last': ['error''always'], //文件强制使用换行 (LF)结束最后一行
        'camelcase': ['error', {'properties''always'}], //强制驼峰法命名 
    },
};


上面配置中的 ‘extends’: ‘eslint:recommended’,为继承eslint默认的rule配置,所以一些基础的配置就不需要我们再重复配置了。上面所包含的配置属性以及相关描述,在下方给一一列出来了:

规则名 规则描述
for-direction 强制 “for” 循环中更新子句的计数器朝着正确的方向移动
getter-return 强制 getter 函数中出现 return 语句
no-async-promise-executor 禁止使用异步函数作为 Promise executor
no-compare-neg-zero 禁止与 -0 进行比较
no-cond-assign 禁止条件表达式中出现赋值操作符
no-constant-condition 禁止在条件中使用常量表达式
no-control-regex 禁止在正则表达式中使用控制字符
no-debugger 禁用 debugger
no-dupe-args 禁止 function 定义中出现重名参数
no-dupe-keys 禁止对象字面量中出现重复的 key
no-duplicate-case 禁止出现重复的 case 标签
no-empty 禁止出现空语句块
no-empty-character-class 禁止在正则表达式中使用空字符集
no-ex-assign 禁止对 catch 子句的参数重新赋值
no-extra-boolean-cast(#fix) 禁止不必要的布尔转换
no-extra-semi(#fix) 禁止不必要的分号
no-func-assign 禁止对 function 声明重新赋值
no-inner-declarations 禁止在嵌套的块中出现变量声明或 function 声明
no-invalid-regexp 禁止 RegExp 构造函数中存在无效的正则表达式字符串
no-irregular-whitespace 禁止不规则的空白
no-misleading-character-class 不允许在字符类语法中出现由多个代码点组成的字符
no-obj-calls 禁止把全局对象作为函数调用
no-prototype-builtins 禁止直接调用 Object.prototypes 的内置属性
no-regex-spaces(#fix) 禁止正则表达式字面量中出现多个空格
no-sparse-arrays 禁用稀疏数组
no-unexpected-multiline 禁止出现令人困惑的多行表达式
no-unreachable 禁止在 return、throw、continue 和 break 语句之后出现不可达代码
no-unsafe-finally 禁止在 finally 语句块中出现控制流语句
no-unsafe-negation(#fix) 禁止对关系运算符的左操作数使用否定操作符
require-atomic-updates 禁止由于 await 或 yield的使用而可能导致出现竞态条件的赋值
use-isnan 要求使用 isNaN() 检查 NaN
valid-typeof 强制 typeof 表达式与有效的字符串进行比较
no-case-declarations 不允许在 case 子句中使用词法声明
no-empty-pattern 禁止使用空解构模式
no-fallthrough 禁止 case 语句落空
no-global-assign 禁止对原生对象或只读的全局对象进行赋值
no-octal 禁用八进制字面量
no-redeclare 禁止多次声明同一变量
no-self-assign 禁止自我赋值
no-unused-labels 禁用出现未使用过的标
no-useless-catch 禁止不必要的 catch 子句
no-useless-escape 禁用不必要的转义字符
no-with 禁用 with 语句
no-delete-var 禁止删除变量
no-shadow-restricted-names 禁止将标识符定义为受限的名字
no-undef 禁用未声明的变量,除非它们在 /*global */ 注释中被提到
no-unused-vars 禁止出现未使用过的变量
no-mixed-spaces-and-tabs 禁止空格和 tab 的混合缩进
constructor-super 要求在构造函数中有 super() 的调用
no-class-assign 禁止修改类声明的变量
no-const-assign 禁止修改 const 声明的变量
no-dupe-class-members 禁止类成员中出现重复的名称
no-new-symbol 禁止 Symbolnew 操作符和 new 一起使用
no-this-before-super 禁止在构造函数中,在调用 super() 之前使用 this 或 super
require-yield 要求 generator 函数内有 yield
no-console 禁用 console
indent 强制使用一致的缩进
max-len 强制一行的最大长度
space-in-parens 强制在圆括号内使用一致的空格
curly 强制所有控制语句使用一致的括号风格
keyword-spacing 强制在关键字前后使用一致的空格
lines-around-comment 要求在注释周围有空行
one-var-declaration-per-line 要求或禁止在变量声明周围换行
comma-dangle 要求或禁止末尾逗号
quotes 强制使用一致的反勾号、双引号或单引号
no-nested-ternary 禁用嵌套的三元表达式
wrap-iife 要求 IIFE 使用括号括起来
no-new-wrappers 禁止对 String,Number 和 Boolean 使用 new 操作符
no-var 要求使用 let 或 const 而不是 var
no-duplicate-imports 禁止重复模块导入
eol-last 要求或禁止文件末尾存在空行
camelcase 强制使用骆驼拼写法命名约定

js中数组删除对象的几种方式总结

胖蔡阅读(495)

JS中数组是我们较为常用的一种数据结构,本篇文章主要是介绍js中我们常见的一些删除数组中元素的方式方法,希望可以对大家有所帮助。站长不易,感兴趣的小伙伴帮忙点个广告。

数组中元素的删除通过删除的方法的不同可以分为:

  • 关键字删除
  • splice删除
  • 特殊位置删除

 

关键字删除

关键字删除是通过js提供的关键字 delete手动删除数组的某一项。 使用delete删除掉数组中的元素后,会把该下标出的值置为undefined,数组的长度不会变。

var arr = ['a','b','c','d'];
delete arr[1];
arr;  
//["a", undefined × 1, "c", "d"] 中间出现两个逗号,数组长度不变,有一项为undefined

 

 

splice删除

splice方法是js中较为常用的数组方法,它不仅仅可以实现数组的删除,也可以实现数组的替换、新增等。通过splice方法删除的数组,数组会发生该表(长度索引也会发生改变)。这是较为常用的数组删除方法。使用删除的方法调用格式为:array.splice(index,len,[item]) 

 

//删除起始下标为1,长度为1的一个值(len设置1,如果为0,则数组不变)
var arr = ['a','b','c','d'];
arr.splice(1,1);
console.log(arr);  
//['a','c','d']; 

//删除起始下标为1,长度为2的一个值(len设置2)
var arr2 = ['a','b','c','d']
arr2.splice(1,2);
console.log(arr2); 
//['a','d']

 

特殊位置删除

当我们只是需要删除数组的首尾数据的时候,也可以通过js的pop或者shift方法实现,这其实是两对对应的操作:添加与删除。

 

  • pushpop

通过push我们可以将元素添加到数组末尾,通过pop将末尾元素去除并返回。

const arr = [1, 2, 3, 4, 5, 6]
// 添加元素到数组末尾
arr.push(7) // arr: [1, 2, 3, 4, 5, 6, 7]
// 取出数组末尾元素并返回
const pop_res = arr.pop() // arr: [1, 2, 3, 4, 5, 6], pop_res: 7
  • unshiftshift

通过unshift可以将元素添加到数组首部,通过shift可去除数组头部元素并返回。

// 将元素添加到数组开头
arr.unshift(0) // arr: [0, 1, 2, 3, 4, 5, 6]
// 取出数组开头元素并返回
const sft_res = arr.shift() // arr: [1, 2, 3, 4, 5, 6], sft_res = 0

 

 

 

 

使用node-xlsx读取生成excel文件

胖蔡阅读(337)

node-xlsx是基于js-xlsx的实现的excel解析、生成器。这里我们通过node-xlsx实现excel的读取和生成。

安装

$ npm install node-xlsx -S

 

解析 excel文件

import xlsx from 'node-xlsx';
// Or var xlsx = require('node-xlsx').default;

// Parse a buffer
const workSheetsFromBuffer = xlsx.parse(fs.readFileSync(`${__dirname}/myFile.xlsx`));
// Parse a file
const workSheetsFromFile = xlsx.parse(`${__dirname}/myFile.xlsx`);

 

生成excel文件

import xlsx from 'node-xlsx';
// Or var xlsx = require('node-xlsx').default;

const data = [[1, 2, 3], [true, false, null, 'sheetjs'], ['foo', 'bar', new Date('2014-02-19T14:30Z'), '0.3'], ['baz', null, 'qux']];
var buffer = xlsx.build([{name: "mySheetName", data: data}]); // Returns a buffer

 

自定义excel格式


import xlsx from 'node-xlsx';
 // Or var xlsx = require('node-xlsx').default; 
// 自定义列宽
const data = [[1, 2, 3], [true, false, null, 'sheetjs'], ['foo', 'bar', new Date('2014-02-19T14:30Z'), '0.3'], ['baz', null, 'qux']] 
const options = {'!cols': [{ wch: 6 }, { wch: 7 }, { wch: 10 }, { wch: 20 } ]}; 
var buffer = xlsx.build([{name: "mySheetName", data: data}], options); // Returns a buffer


// 跨行设置
const data = [[1, 2, 3], [true, false, null, 'sheetjs'], ['foo', 'bar', new Date('2014-02-19T14:30Z'), '0.3'], ['baz', null, 'qux']];
const range = {s: {c: 0, r:0 }, e: {c:0, r:3}}; // A1:A4
const options = {'!merges': [ range ]};
var buffer = xlsx.build([{name: "mySheetName", data: data}], options); // Returns a buffer


// 跨页合并单元格


const data = [[1, 2, 3], [true, false, null, 'sheetjs'], ['foo', 'bar', new Date('2014-02-19T14:30Z'), '0.3'], ['baz', null, 'qux']]; 
const range = {s: {c: 0, r:0 }, e: {c:0, r:3}}; // A1:A4 
const options = {'!merges': [ range ]}; 
var buffer = xlsx.build([{name: "mySheetName", data: data}], options); // Returns a buffer

 

 

Vue中是用downloadjs实现文件下载

胖蔡阅读(1693)

1ed72c09f5e3fb0

Vue中使用downlaodjs库实现浏览器中文件的下载,可以防止通过a标签下载导致txt,jpg等直接展示不下载的问题。

1、downloadjs下载

$ npm i downloadjs -S

 

2、 Vue中使用

创建一个vue 页面组件。

 

<template>
  <div style="margin:20px">
     <button @click="downloadText">点击下载</button>
  </div>
</template>

<script>
import download from "downloadjs";
export default {
  methods: {
    download() {
       download(this.url);
    },
  },
data() {
  return {
      url:'/test.txt',
  };
 },
};
</script>


 

3、常用api

  • 纯文本下载成文件

download("hello world", "dlText.txt", "text/plain");

  • 通过文件的dataURL下载
download("data:text/plain,hello%20world", "dlDataUrlText.txt", "text/plain");
  • 通过blob下载
download(new Blob(["hello world"]), "dlTextBlob.txt", "text/plain");
  • 通过文件的地址
download("/robots.txt");
  • 文本 UInt8 数组
var str= "hello world",	arr= new Uint8Array(str.length);
str.split("").forEach(function(a,b){
  arr[b]=a.charCodeAt();
});

download( arr, "textUInt8Array.txt", "text/plain" );

JS实现MD5加密

胖蔡阅读(802)

MD5信息摘要算法(英语:MD5 Message-Digest Algorithm),是一种常用的密码散列函数,一般常用检测文件、传输信息的完整性。MD5是由美国密码学家罗纳德·李维斯特在1992年发布。这套算法的程序在 RFC 1321 标准中被加以规范。如下,通过JS来实现MD5加密。

32769b6b1036062-132769b6b1036062

通过prototype实现MD5

String.prototype.MD5 = function(bit) {
    var sMessage = this;
    function RotateLeft(lValue, iShiftBits) { return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits)); }
    function AddUnsigned(lX, lY) {
        var lX4, lY4, lX8, lY8, lResult;
        lX8 = (lX & 0x80000000);
        lY8 = (lY & 0x80000000);
        lX4 = (lX & 0x40000000);
        lY4 = (lY & 0x40000000);
        lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
        if (lX4 & lY4) return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
        if (lX4 | lY4) {
            if (lResult & 0x40000000) return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
            else return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
        } else return (lResult ^ lX8 ^ lY8);
    }

    function F(x, y, z) { return (x & y) | ((~x) & z); }
    function G(x, y, z) { return (x & z) | (y & (~z)); }
    function H(x, y, z) { return (x ^ y ^ z); }
    function I(x, y, z) { return (y ^ (x | (~z))); }
    function FF(a, b, c, d, x, s, ac) {
        a = AddUnsigned(a, AddUnsigned(AddUnsigned(F(b, c, d), x), ac));
        return AddUnsigned(RotateLeft(a, s), b);
    }

    function GG(a, b, c, d, x, s, ac) {
        a = AddUnsigned(a, AddUnsigned(AddUnsigned(G(b, c, d), x), ac));
        return AddUnsigned(RotateLeft(a, s), b);
    }

    function HH(a, b, c, d, x, s, ac) {
        a = AddUnsigned(a, AddUnsigned(AddUnsigned(H(b, c, d), x), ac));
        return AddUnsigned(RotateLeft(a, s), b);
    }

    function II(a, b, c, d, x, s, ac) {
        a = AddUnsigned(a, AddUnsigned(AddUnsigned(I(b, c, d), x), ac));
        return AddUnsigned(RotateLeft(a, s), b);
    }

    function ConvertToWordArray(sMessage) {
        var lWordCount;
        var lMessageLength = sMessage.length;
        var lNumberOfWords_temp1 = lMessageLength + 8;
        var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
        var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
        var lWordArray = Array(lNumberOfWords - 1);
        var lBytePosition = 0;
        var lByteCount = 0;
        while (lByteCount < lMessageLength) {
            lWordCount = (lByteCount - (lByteCount % 4)) / 4;
            lBytePosition = (lByteCount % 4) * 8;
            lWordArray[lWordCount] = (lWordArray[lWordCount] | (sMessage.charCodeAt(lByteCount) << lBytePosition));
            lByteCount++;
        }

        lWordCount = (lByteCount - (lByteCount % 4)) / 4;
        lBytePosition = (lByteCount % 4) * 8;
        lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
        lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
        lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
        return lWordArray;
    }

    function WordToHex(lValue) {
        var WordToHexValue = "",
            WordToHexValue_temp = "",
            lByte, lCount;
        for (lCount = 0; lCount <= 3; lCount++) {
            lByte = (lValue >>> (lCount * 8)) & 255;
            WordToHexValue_temp = "0" + lByte.toString(16);
            WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2);
        }
        return WordToHexValue;
    }

    var x = Array();
    var k, AA, BB, CC, DD, a, b, c, d
    var S11 = 7,
        S12 = 12,
        S13 = 17,
        S14 = 22;

    var S21 = 5,
        S22 = 9,
        S23 = 14,
        S24 = 20;

    var S31 = 4,
        S32 = 11,
        S33 = 16,
        S34 = 23;

    var S41 = 6,
        S42 = 10,
        S43 = 15,
        S44 = 21;

    // Steps 1 and 2. Append padding bits and length and convert to words
    x = ConvertToWordArray(sMessage);
    // Step 3. Initialise
    a = 0x67452301;
    b = 0xEFCDAB89;
    c = 0x98BADCFE;
    d = 0x10325476;

    // Step 4. Process the message in 16-word blocks
    for (k = 0; k < x.length; k += 16) {
        AA = a;
        BB = b;
        CC = c;
        DD = d;
        a = FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
        d = FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
        c = FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
        b = FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
        a = FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
        d = FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
        c = FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
        b = FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
        a = FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
        d = FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
        c = FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
        b = FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
        a = FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
        d = FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
        c = FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
        b = FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
        a = GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
        d = GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
        c = GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
        b = GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
        a = GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
        d = GG(d, a, b, c, x[k + 10], S22, 0x2441453);
        c = GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
        b = GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
        a = GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
        d = GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
        c = GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
        b = GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
        a = GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
        d = GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
        c = GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
        b = GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
        a = HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
        d = HH(d, a, b, c, x[k + 8], S32, 0x8771F681);
        c = HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
        b = HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
        a = HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
        d = HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
        c = HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
        b = HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
        a = HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
        d = HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
        c = HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
        b = HH(b, c, d, a, x[k + 6], S34, 0x4881D05);
        a = HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
        d = HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
        c = HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
        b = HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
        a = II(a, b, c, d, x[k + 0], S41, 0xF4292244);
        d = II(d, a, b, c, x[k + 7], S42, 0x432AFF97);
        c = II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
        b = II(b, c, d, a, x[k + 5], S44, 0xFC93A039);
        a = II(a, b, c, d, x[k + 12], S41, 0x655B59C3);
        d = II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
        c = II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
        b = II(b, c, d, a, x[k + 1], S44, 0x85845DD1);
        a = II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
        d = II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
        c = II(c, d, a, b, x[k + 6], S43, 0xA3014314);
        b = II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
        a = II(a, b, c, d, x[k + 4], S41, 0xF7537E82);
        d = II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
        c = II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
        b = II(b, c, d, a, x[k + 9], S44, 0xEB86D391);
        a = AddUnsigned(a, AA);
        b = AddUnsigned(b, BB);
        c = AddUnsigned(c, CC);
        d = AddUnsigned(d, DD);
    }

    if (bit == 32) {
        return WordToHex(a) + WordToHex(b) + WordToHex(c) + WordToHex(d);
    } else {
        return WordToHex(b) + WordToHex(c);
    }

}

使用JS调用

import '@/js/decoder.js';

function getMD5(str) {
    const md5_16 = str.MD5(); // 16位加密
    const md5_32 = str.MD5(32); //  32位加密方法
    $('#strForm').html(str);
    $('#md5_16_min').html(md5_16.toLowerCase());
    $('#md5_16_max').html(md5_16.toUpperCase());
    $('#md5_32_min').html(md5_32.toLowerCase());
    $('#md5_32_max').html(md5_32.toUpperCase());
}

MD5 不安全的三个原因

胖蔡阅读(409)

您可能已经阅读了该信息,并且您知道 MD5 不是最安全的散列函数
但是您知道为什么吗?你知道更安全的替代品吗?
这就是我今天要向您解释的内容。

为什么 MD5 不安全?

 

MD5 是一种密码算法,通常用于将密码存储在数据库中
但这种算法不再安全
暴力攻击比以往任何时候都快,字典表很大 MD5 算法还有其他潜在问题

 

什么是MD5?

MD5 是一种密码算法,通常用于在数据库中存储密码。
在互联网的早期,网站大多在其数据库中保存明文密码。
这不是一个好的解决方案,因此开发人员使用 MD5 来混淆数据库中的密码。

MD5 是一种算法,可从任何密码、短语或文本生成 32 个字符的十六进制字符串。
例如,如果您的密码是“qwerty”(坏主意),那么在数据库中您将拥有 d8578edf8458ce06fbc5bb76a58c5ca4。

这样一来,IT 人员就看不到您的密码,而且如果有人窃取了数据库,他们也无法直接获得所有密码。
今天,解密密码仍然不是立即的,但到目前为止还没有。
我将在接下来的部分解释原因,以及为什么您必须找到另一种存储密码的方法。

 

为什么 MD5 不安全?

1 – 对 MD5 哈希的蛮力攻击速度很快

蛮力攻击是一种通过尝试多种可能性来找到密码的方法。
要么通过猜测用户可能使用过的内容(生日、孩子的名字、宠物名称等),要么尝试所有内容(从 a、b、c 到带有特殊字符的 10 个字符的密码)。

 

MD5 算法使用起来很快。
所以在几秒钟内您可以尝试多种组合。

20 年前,为世界上最强大的计算机找到密码可能需要数年时间
今天,每个人家里都有一台超级计算机,随着处理器和图形处理器的改进,我们最多可以在几天内解密“安全”密码.
最好的计算机每秒可以尝试数十亿个密码(来源:ZDNet)。

对蛮力攻击的唯一抵抗可能是密码长度。
如果您有一个 40 个字符长的随机密码,并带有特殊字符,那么您目前可能是安全的,
但是还能持续多久呢?

2 – MD5 字典表很大

在 MD5Online 我们喜欢字典表。
通过在我们的数据库中存储超过 11,500 亿个密码,我们可以在几秒钟内提供任何哈希的答案

这是 MD5 算法的第二个问题。
它被如此广泛地使用,以至于多年来已经创建了像这样的大型数据库。
如果您的密码在里面(如果您有一个“短”密码,则很有可能),您的帐户根本就不安全。

至于蛮力方法,唯一安全的方法是使用带有特殊字符的长随机密码。
在这种数据库中拥有它的可能性太多了。
像这样的数据库占用了大量磁盘空间。即使这些年来价格越来越便宜,它仍然是一个障碍。

 

3 – MD5 有冲突

MD5 算法也已证明其加密方法存在问题。
冲突是指两个单词生成相同的哈希值。
安全算法具有良好的抗碰撞性。

也就是说,对于不同的单词,您获得相同散列的机会很小。
但MD5的抗碰撞性较低。

因此,如果您知道“abc”和“def”具有相同的生成散列(只是一个示例)。
您可以说“123abc”和“123def”也生成了相同的哈希值。
这对于加密哈希函数来说是一个糟糕的属性,因为您可以猜测出很多派生词。

有哪些解决方案?

既然您知道为什么 MD5 不安全,那么您可以做些什么来提高数据库的安全性。

使用盐

您可以尝试的第一件事是在加密密码时使用盐。
我已经写过一篇关于此的文章:什么是 MD5 盐以及如何使用它?
如果您想了解更多信息,请检查它。

基本上,盐是您将在每个密码之前和/或之后添加的词。
如果您的 salt 是“randomsaltformypassword”并且用户选择“qwerty”作为密码,您将使用“randomsaltformypasswordqwerty”作为 MD5 函数参数。

这样你就在你的数据库中加密了一个更长的密码,黑客将更难找到相应的密码。
确保选择长盐以提高安全性。

jQuery 常见选择器分类及使用方法

胖蔡阅读(369)

 

Jquery库可以通过选择器来让我们实现元素的快速定位和对选中元素的DOM操作。现在我们认识到过于频繁的DOM操作会影响应用的性能,但对于VUE、REACT框架不显的时代,Jquery的出现可以说是前端的一大神器,极大的缩减了我们的开发时间和实现难度。说是忆苦思甜也好,说是全面了解前端发展也罢,JQuery的基本操作和封装思想都是我们不可忽视。这篇文章主要是来介绍了解下常用的Jquery选择器分类和选择器使用方法。

6588348d0300eb5-1

6588348d0300eb5

Jquery选择一般的被我们分为:基本选择器、层次选择器、过滤选择器、表单选择器这四大类。

基本选择器

基本选择器是Jquery最常见的选择器,一般的我们可以通过元素的id、class、属性、元素名来定位元素。其他的所有选择器也是基于基本选择器的基础上的变形结构,常见的基本选择器类型如:

  • ID选择器
  • Class选择器
  • 元素选择器
  • 属性选择器
$("#selector")                 选择id值为selector的元素,id值是唯一的所以返回单个元素。
$("p")                         选择所有的p标签元素,返回p元素数组 
$(".myclass")                 选择使用myclass类的css的所有元素 
$("*")                        选取所有元素。
$("#test,div,.myclass")        选取多个元素。

 

层次选择器

层次选择器让我们可以通过元素的层级关系来定位元素,如果我们想通过元素之间的关系来获取特定的元素,那么层次选择器是一个非常好的选择。一般的我们会通过相应的链接符号来指代对应元素直接的层级关系,常见的层级关系如下:

  • 空格:空格指代元素的子孙元素
  • > : 指代元素的子元素
  • +,next():指代元素的兄弟节点元素(当前元素之后的同级元素),定位的为单个元素
  • ~,nextAll():指代元素的所有兄弟节点元素(当前元素之后的统计元素)
  • prev():这是不同于css的一个只想元素同级的上一个元素
  • siblings():指代元素的所有统计元素(包括上级和下级)
    $("div span")             选取<div>里的所有<span>元素
    $("div >span")             选取<div>元素下元素名是<span>的子元素
    $("#one +div")             选取id为one的元素的下一个<div>同辈元素        等同于$("#one").next("div")
    $("#one~div")              选取id为one的元素的元素后面的所有<div>同辈元素    等同于$("#one").nextAll("div")
    $("#one").siblings("div")      获取id为one的元素的所有<div>同辈元素(不管前后)
    $("#one").prev("div")        获取id为one的元素的前面紧邻的同辈<div>元素
    所以 获取元素范围大小顺序依次为:
    $("#one").siblings("div")>$("#one~div")>$("#one +div")  或是
    $("#one").siblings("div")>$("#one").nextAll("div")>$("#one").next("div")

 

过滤选择器

Jquery可以通过相应的过滤规则来过滤我们选择的部分元素,我们可以通过css中已有的伪元素、也可以通过jquery特有的伪元素、方法来过滤。通常情况下,我们可以根据过滤的方式的不同又可以将过滤选择器分为:基本过滤选择器、内容过滤选择器、可见性过滤选择器、属性过滤选择器、子元素过滤选择器以及表单对象属性过滤选择器,下面我们通过例子来了解他们的使用的不同。

  • 基本过滤选择器

基本过滤选择器一般都是通过一些常见的伪元素来过滤选择

       $("div:first")                 选取所有<div>元素中第1个<div>元素
    $("div:last")                   选取所有<div>元素中最后一个<div>元素
    $("input:not(.myClass)")        选取class不是myClass的<input>元素 
    $("input:even")                 选取索引是偶数的<input>元素(索引从0开始) 
    $("input:odd")                  选取索引是基数的<input>元素(索引从0开始) 
    $("input:eq(2)")                选取索引等于2的<input>元素 
    $("input:gt(4)")                选取索引大于4的<input>元素
    $("input:lt(4)")                选取索引小于4的<input>元素
    $(":header")                    过滤掉所有标题元素,例如:h1、h2、h3等
    $("div:animated")               选取正在执行动画的<div>元素  
    $(":focus")                     选取当前获取焦点的元素
  • 内容过滤选择器

内容过滤器中所提供的过滤伪元素,如:contains之内的都是jquery中内置式赋予能力的,属于自定义的通过元素的内容来实现元素的过滤的

    $("div:contains('Name')")       选取所有<div>中含有'Name'文本的元素 
    $("div:empty")                  选取不包含子元素(包括文本元素)的<div>空元素 
    $("div:has(p)")                 选取所有含有<p>元素的<div>元素 
    $("div:parent")                 选取拥有子元素的(包括文本元素)<div>元素
  • 可见性过滤选择器

这个通过例子比较明显的可以看出是通过元素的显示状态来进行过滤的,其实现是将集中不同的属性组合在一起,降低我们操作的复杂程度。

    $("div:hidden")                 选取所有不可见的<div>元素 
    $("div:visible")                选取所有可见的<div>元素
  • 属性过滤选择器

属性过滤选择器可以说是我们比较常见,也比较常用的方式,jquery服务我们通过元素的属性名来过滤选择的功能,属性名可以是默认的也可以是自定义的。

       $("div[id]")                  选取所有拥有属性id的元素
    $("input[name='test']")        选取所有的name属性等于'test'的<input>元素 
    $("input[name!='test']")      选取所有的name属性不等于'test'的<input>元素 
    $("input[name^='news']")        选取所有的name属性以'news'开头的<input>元素 
    $("input[name$='news']")        选取所有的name属性以'news'结尾的<input>元素 
    $("input[name*='news']")        选取所有的name属性包含'news'的<input>元素 
    $("div[title|='en']")           选取属性title等于'en'或以'en'为前缀(该字符串后跟一个连字符'-')的<div>元素
    $("div[title~='en']")           选取属性title用空格分隔的值中包含字符en的<div>元素
    $("div[id][title$='test']")     选取拥有属性id,并且属性title以'test'结束的<div>元素
  • 子元素过滤选择器
子元素过滤选择器一般是通过父元素的子元素位置、类型来过滤的,对于状态类型、列表类型的选择器使用比较方便。
    $("div .one:nth-child(2)")       选取class为'one'的<div>父元素下的第2个子元素
    $("div span:first-child")        选取每个<div>中的第1个<span>元素 
    $("div span:last-child")         选取每个<div>中的最后一个<span>元素 
    $("div button:only-child")       在<div>中选取是唯一子元素的<button>元素
  • 表单对象属性过滤选择器

这个可以被单独列为一类,可以说是和表单类组件的特有属性相关,其实这种选择我们也可以通过上述的属性过滤方式来实现,这里只是简化了书写方式,并不常用。

     $("#form1 :enabled")             选取id为'form1'的表单内所有可用元素
    $("#form2 :disabled")            选取id为'form2'的表单内所有不可用元素 
    $("input :checked")              选取所有被选中的<input>元素 
    $("select option:selected")      选取所有的select 的子元素中被选中的元素

 

表单选择器

表单选择器可以说和上述的表单过滤选择器有点类似,其主要使用还是为了让我们的表单选择操作变得更加的简便和易懂。

      $(":input")                      选取所有<input>,<textarea>,<select> 和 <button>元素 
    $(":text")                      选取所有的单行文本框
    $(":password")                   选取所有的密码框 
    $(":radio")                      选取所有单的选框 
    $(":checkbox")                   选取所有的多选框 
    $(":submit")                     选取所有的提交按钮
    $(":image")                      选取所有的图像按钮 
    $(":reset")                      选取所有的重置按钮
    $(":button")                     选取所有的按钮 
    $(":file")                       选取所有的上传域
    $(":hidden")                     选取所有不可见元素

 

 

 

上述的所有选择器或许中间存在交叉重复处,要知道对于Jquery选择器的分类其实无甚特别含义,只是为了我们更好更方便的取记忆使用罢了。所以,真正使用的时候不可过于拘泥于使用的类型,我们真正关注的只有两点:

  • 解决实现问题
  • 更好的解决实际问题

 

前端Latex 表达式不能正常显示

胖蔡阅读(330)

e681337914c5397-1

 

<form name="checkListForm">
    <input type="text" name="checkListItem"/>
</form>
<div id="button">Add!</div>
<br/>
<div class="list"></div>
    <script>
        $(document).ready(function(){
           $('#button').click(function(){
           var toAdd = $('input[name=checkListItem]').val();
           $('.list').append('<img src="http://latex.codecogs.com/gif.latex?\frac{x}  {y}"/>');

        }); 
         $(document).on('click', '.item', function(){
            $(this).remove();
         });
      });
    </script>

 

如上的代码,我在表格中通过按钮点击使用latex转化成图片的api, 但是我得到了这个我正在使用这个lates 表达式文件形式的codecogs文件:codecogs.com/latex/htmlequations.php

解决方法

在api请求参数上添加行转义符 ‘\’

$('.list').append('<img src="http://latex.codecogs.com/gif.latex?\frac{x}{y}"/>');

所以,我们需要把代码改成:

$('.list').append('<img src="http://latex.codecogs.com/gif.latex?\\frac{x}{y}"/>');