Giter VIP home page Giter VIP logo

mr_blog's People

Contributors

mr-jili avatar

Watchers

 avatar

mr_blog's Issues

webpack配置(vue)

1.安装node
2.全局安装 cnpm install vue-cli -g
3.vue init webpack 项目名称

? Project name y
? Project description A Vue.js project
? Author jili <[email protected]>
? Vue build standalone
? Install vue-router? Yes
? Use ESLint to lint your code? Yes? Pick an ESLint preset Standard
? Set up unit tests Yes
? Pick a test runner jest   //是否需要安装单元测试工具Karma+Mocha
? Setup e2e tests with Nightwatch? Yes    //是否安装e2e来进行用户行为模拟测试
? Should we run `npm install` for you after the project has been created? (recommended) npm    
.
|-- build                            // 项目构建(webpack)相关代码
|   |-- build.js                     // 生产环境构建代码
|   |-- check-version.js             // 检查node、npm等版本
|   |-- dev-client.js                // 热重载相关
|   |-- dev-server.js                // 构建本地服务器
|   |-- utils.js                     // 构建工具相关
|   |-- webpack.base.conf.js         // webpack基础配置
|   |-- webpack.dev.conf.js          // webpack开发环境配置
|   |-- webpack.prod.conf.js         // webpack生产环境配置
|-- config                           // 项目开发环境配置
|   |-- dev.env.js                   // 开发环境变量
|   |-- index.js                     // 项目一些配置变量
|   |-- prod.env.js                  // 生产环境变量
|   |-- test.env.js                  // 测试环境变量
|-- src                              // 源码目录
|   |-- components                     // vue公共组件
|   |-- store                          // vuex的状态管理
|   |-- App.vue                        // 页面入口文件
|   |-- main.js                        // 程序入口文件,加载各种公共组件
|-- static                           // 静态文件,比如一些图片,json数据等
|   |-- data                           // 群聊分析得到的数据用于数据可视化
|-- .babelrc                         // ES6语法编译配置
|-- .editorconfig                    // 定义代码格式
|-- .gitignore                       // git上传需要忽略的文件格式
|-- README.md                        // 项目说明
|-- favicon.ico 
|-- index.html                       // 入口页面
|-- package.json                     // 项目基本信息
.

package.json解析

{
  "name": "y",     //项目名称
  "version": "1.0.0",    //项目版本
  "description": "A Vue.js project",       //描述
  "author": "jili <[email protected]>",    
  "private": true,                        //私有
  "scripts": {
    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    "start": "npm run dev",
    "unit": "jest --config test/unit/jest.conf.js --coverage",
    "e2e": "node test/e2e/runner.js",
    "test": "npm run unit && npm run e2e",
    "lint": "eslint --ext .js,.vue src test/unit test/e2e/specs",
    "build": "node build/build.js"
  },
  "dependencies": {   //生产环境    项目运行时所依赖的模块
    "vue": "^2.5.2",
    "vue-router": "^3.0.1"
  },
  "devDependencies": {   //开发环境  项目开发时所依赖的模块
    
  },
  "engines": {
    "node": ">= 6.0.0",
    "npm": ">= 3.0.0"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ]
}

iconfig/index.js

'use strict'
const path = require('path')

module.exports = {
  dev: {

    // Paths
    assetsSubDirectory: 'static',  //编译输出的二级目录
    assetsPublicPath: '/',         //编辑发布的根目录,可配置为资源服务器域名或者cdn域名
    proxyTable: {  //使用proxyTable代理的接口(跨域处理)
      '/api1': {                                 
        target: 'http://172.22.0.58:8082',
        // changeOrigin: true,  //将changeOrigin选项设置为true时,代理会将请求转换为预期的目标服务器
        pathRewrite: {
          '^/api1': ''
        }
      },
      '/api': {
        target: 'http://192.168.101.202:9001',      //本地
        // changeOrigin: true,
        pathRewrite: {
          '^/api': ''
        }
        },

      '/test': {                                //测试
        target: 'http://123.56.6.167:2000',
        changeOrigin: true,
        pathRewrite: {
          '^/test': ''
        }
      },
      '/pre': {                               //预发布
        target: 'http://123.56.6.167:3000',
        changeOrigin: true,
        pathRewrite: {
          '^/pre': ''
        }
      },
      '/pro': {                               //生产
        target: 'http://123.56.6.167:4000',
        changeOrigin: true,
        pathRewrite: {
          '^/pro': ''
        }
      }
    },               


    host: '0.0.0.0', 
    port: 8080, // 端口
    autoOpenBrowser: true,   // 是否自动打开浏览器
    errorOverlay: true,       // 在浏览器是否展示错误蒙层
    notifyOnErrors: true,     // 是否展示错误的通知
    // vagrant也会在这方面存在很多问题,在这些情况下,使用poll选项(以轮询的方式去检查文件是否改变)可以设定为true
    // 或者具体的数值,指定文件查询的具体周期。
    poll: false,

    // Use Eslint Loader?
    useEslint: true,
  
    // 如果设置为true,在浏览器中,eslint的错误和警告会以蒙层的方式展现。
    showEslintErrorsInOverlay: false,

    /**
     * Source Maps
     */

    // source maps的格式
    devtool: 'cheap-module-eval-source-map',

    // 指定是否通过在文件名称后面添加一个查询字符串来创建source map的缓存
    cacheBusting: true,
    // 关闭css的source map
    cssSourceMap: true
  },

  build: {
    // html文件生成的地方
    index: path.resolve(__dirname, '../dist/index.html'),

    // 编译生成的文件目录
    assetsRoot: path.resolve(__dirname, '../dist'),
    //编译生成的静态文件的目录
    assetsSubDirectory: 'static',
    //编译发布的根目录,可配置为资源服务器域名或者cdn域名
    assetsPublicPath: '/',

    /**
     * Source Maps
     */
    //为true最终打包的文件中会出现一些map文件,map文件的作用在于:项目打包后,代码都是经过压缩加密的,如果运行时报错,输出的错误信息无法准确得知是哪里的代码报错。
    productionSourceMap: true,

    devtool: '#source-map',

    //是否开启生产环境的gzip压缩
    productionGzip: false,
    // 开启gzip压缩的文件的后缀名称
    productionGzipExtensions: ['js', 'css'],

    // 如果这个选项是true的话,那么则会在build后,会在浏览器中生成一份bundler报告
    bundleAnalyzerReport: process.env.npm_config_report
  }
}

config/dev.env.js

//本地环境
'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')

module.exports = merge(prodEnv, {
  NODE_ENV: '"development"',
  ENV_CONFIG: '"dev"',
  BASE_URL: '"/api"'
})

config/test.env.js

//测试环境
'use strict'
const merge = require('webpack-merge')
const devEnv = require('./dev.env')

module.exports = merge(devEnv, {
  NODE_ENV: '"testing"',
  ENV_CONFIG: '"test"',
  BASE_URL: '"http://172.22.1.22:9006"'
})

config/pre.env.js

//预发布环境
'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')

module.exports = merge(prodEnv, {
  NODE_ENV: '"development"',
  ENV_CONFIG: '"pre"',
  BASE_URL: '"http://123.56.6.167:3000"'
})

config/pro.env.js


//生产环境
'use strict'
module.exports = {
  NODE_ENV: '"production"',
  ENV_CONFIG: '"pro"',
  BASE_URL: '"http://123.56.6.167:4000"'
}

build/webpack.base.conf.js

'use strict'
const path = require('path')
const utils = require('./utils')
const config = require('../config')
const vueLoaderConfig = require('./vue-loader.conf')

function resolve (dir) {
  return path.join(__dirname, '..', dir)
}

const createLintingRule = () => ({
  test: /\.(js|vue)$/,
  loader: 'eslint-loader',
  enforce: 'pre',
  include: [resolve('src'), resolve('test')],
  options: {
    formatter: require('eslint-friendly-formatter'),
    emitWarning: !config.dev.showEslintErrorsInOverlay
  }
})

module.exports = {
  context: path.resolve(__dirname, '../'),
  entry: {
    app: './src/main.js'              //编译入口文件
  },
  output: {                           //编译输出路径
    path: config.build.assetsRoot,
    filename: '[name].js',
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  resolve: {                          //一些解决方案配置
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    }
  },
  resolveLoader:{},
  module: {
    //各种不同类型文件加载器配置
    rules: [
      ...(config.dev.useEslint ? [createLintingRule()] : []),
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: vueLoaderConfig
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('img/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('media/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      }
    ]
  },
  node: {
    setImmediate: false,
    dgram: 'empty',
    fs: 'empty',
    net: 'empty',
    tls: 'empty',
    child_process: 'empty'
  }
}

.bablerc

{
  //设定转码规则
  "presets": [
    ["env", { "modules": false }],
    "stage-2"
  ],
  //转码用的插件
  "plugins": ["transform-runtime"],
  "comments": false,
  //对BABEL_ENV或者NODE_ENV指定的不同的环境变量,进行不同的编译操作
  "env": {
    "test": {
      "presets": ["env", "stage-2"],
      "plugins": [ "istanbul" ]
    }
  }
}

.editorconfig

root = true
[*]    // 对所有文件应用下面的规则
charset = utf-8                    // 编码规则用utf-8
indent_style = space               // 缩进用空格
indent_size = 2                    // 缩进数量为2个空格
end_of_line = lf                   // 换行符格式
insert_final_newline = true        // 是否在文件的最后插入一个空行
trim_trailing_whitespace = true    // 是否删除行尾的空格

.main.js

import Vue from 'vue'
import App from './App'
import router from './router'

Vue.config.productionTip = false  //生产环境提示。

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

router/index.js

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: () => import('@/components/HelloWorld')
    }
  ]
})

配置热加载: //自动更新
下载webpack-dev-server依赖 npm install -g webpack-dev-server --save-dev
命令行执行命令,启动服务器8080端口 webpack-dev-server --inline --hot

dev、test、prod环境区分:	
debug = process.env.NODE_ENV == 'production'

配置文件:
var debug =  process.env.NODE_ENV == 'production' ? false : true

配置webpack.config.js 
```
//省略一堆配置...
devServer:{
	host: 'localhost', //可选,ip
	port: 3000, //可选,端口
	contentBase:path.resolve(__dirname,'dist'), //可选,基本目录结构
	compress: true //可选,压缩
}
```
 new webpack.HotModuleReplacementPlugin(), //热加载插件

mvvm

Vue.js 是采用 Object.defineProperty 的 getter 和 setter,并结合观察者模式来实现数据绑定的。当把一个普通 Javascript 对象传给 Vue 实例来作为它的 data 选项时,Vue 将遍历它的属性,用 Object.defineProperty 将它们转为 getter/setter。用户看不到 getter/setter,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>双向数据绑定</title>
</head>

<body>
  <input type="text" id="message" />
  <div id="msg"></div>
  <script>
    var obj = {};
    Object.defineProperty(obj, "data", {
      get: function () {
        console.log("get")
      },
      set: function (newValue) {
        document.getElementById("message").value = newValue
        document.getElementById("msg").innerText = newValue
      }
    })
    document.getElementById("message").onkeyup = function (e) {
      console.log(e.target.value);
      obj.data = e.target.value;
    };

    //柯里化**
    //         var curry = function(func){
    //     var args = [].slice.call(arguments,1);
    //     console.log(args);
    //     return function(){
    //         var newArgs = args.concat([].slice.call(arguments));
    //         console.log(newArgs);  
    //         return func.apply(this,newArgs);
    //     }
    // }
    // function add(a, b) {
    //     return a + b;
    // }

    // var addCurry = curry(add,1);
    // console.log(addCurry(3));//3
  </script>
</body>
</html>

//尤雨溪版
var obj = {foo:123}
convert(obj)
function convert(obj){
  Object.keys(obj).forEach(key=>{
    let internalVal = obj[key];
    Object.defineProperty(obj,key,{
      get(){
        return internalVal;
      },
      set(newVal){
        internalVal = newVal;
      }
    })
  })
}
// obj.foo ="jili1111111111111"

这里只是简单的了解下,待续~~~
详细了解 :https://github.com/Mr-jili/mvvm

attachment upload

<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8">
  <title>attachment upload</title>
  <script src="node_modules\jquery\dist\jquery.min.js"></script>
  <script src="node_modules\bootstrap\dist\js\bootstrap.min.js"></script>
  <link rel="stylesheet" href="node_modules\bootstrap\dist\css\bootstrap.css">
  <style>
    input{
      position: absolute;
      top: 0;
      width: 90px;
      height: 38px;
      top: 0;
      opacity: 0;
    }
    #file_view{
      text-align: right;
    }
    ul,li{
      list-style: none;
    }
  </style>
</head>

<body>
  <div id="newPageGrey">
    <div class="cushion_enclosure_box" style="position: relative;padding-top: 10px;">
      <button type="button" class="btn btn-info" id="cushion_enclosure">上传附件</button>
      <div id="file_view"></div>
    </div>
  </div>

</body>
<script>
  $('#newPageGrey').on('click', '#cushion_enclosure', function () {
    debugger
    var file_input_ele = $('#newPageGrey .file_input')
    if (file_input_ele.length) {
      for (var i = 0; i < file_input_ele.length; i++) {
        if (file_input_ele.eq(i).attr('id') == 'uploaderInput') {
          file_input_ele.eq(i).remove()
        }
      }
    }
    var file_num = (file_input_ele.eq(file_input_ele.length - 1)).attr('file_num') == undefined ? 0 : parseFloat((
      file_input_ele.eq(file_input_ele.length - 1)).attr('file_num'))

    if (!file_input_ele.length) {
      var uploadFile =
        '<input name="files0" id="uploaderInput" file_num="0" class="file_input" type="file" accept="application/pdf,image/png, image/jpeg,image/jpg"/>'
    } else {
      var uploadFile = '<input name="files' + (file_num + 1) + '" id="uploaderInput" file_num="' + (file_num + 1) +
        '" class="file_input" type="file" accept="application/pdf,image/png, image/jpeg,image/jpg"/>'
    }
    $('#file_view').append($(uploadFile))
    $('#uploaderInput').bind('change', function (e) {
      // 可以做一些其他的事,比如图片预览
      var that = this;
      var fileObj = this.files[0]
      var windowURL = window.URL || window.webkitURL
      if (fileObj) {
        var dataURl = windowURL.createObjectURL(fileObj)
      }
      var file_index = $(this).val().lastIndexOf('\\')
      var format_index = $(this).val().lastIndexOf('.')
      var file_name = $(this).val().substring(file_index + 1)
      var format_name = $(this).val().substring(format_index + 1)
      // 文件格式

      if (format_name != 'jpg' && format_name != 'JPEG' && format_name != 'JPG' && format_name != 'jpeg' &&
        format_name != 'png' && format_name != 'PNG' && format_name != 'pdf' && format_name != 'PDF') {
        alert('请上传jpg、pdf、png、jpeg格式文件!')
        $(this).val('')
        return
      }
      var file_html = ''
      if (!file_input_ele.length) {
        file_html += '<ul class="row cushion_enclosure_box_list" style="list-style:none;">' +
          '<li class="col-lg-10 col-md-10 col-sm-10 col-xs-10 files_name">' + file_name + '</li>' +
          '<li class="col-lg-1 col-md-1 col-sm-1 col-xs-1 open_view" style="padding:0;"><a href="' + dataURl +
          '" target="_blank">查看</a></li>' +
          '<li class="col-lg-1 col-md-1 col-sm-1 col-xs-1 delete_file fontblue" file_num="0" style="padding:0;">删除</li>' +
          '</ul>'
      } else {
        file_html += '<ul class="row cushion_enclosure_box_list" style="list-style:none;">' +
          '<li class="col-lg-10 col-md-10 col-sm-10 col-xs-10 files_name">' + file_name + '</li>' +
          '<li class="col-lg-1 col-md-1 col-sm-1 col-xs-1 open_view" style="padding:0;"><a href="' + dataURl +
          '" target="_blank">查看</a></li>' +
          '<li class="col-lg-1 col-md-1 col-sm-1 col-xs-1 delete_file fontblue" file_num="' + (file_num + 1) +
          '" style="padding:0;">删除</li>' +
          '</ul>'
      }
      $('#newPageGrey').find('.cushion_enclosure_box').append(file_html)
      $(this).removeAttr('id')
    })
    $('#uploaderInput').click()
  })

  // 附件 删除
  $('#newPageGrey').on('click', '.delete_file', function () {
    var index = $(this).attr('file_num')
    var file_input = $(this).parent('.cushion_enclosure_box_list').siblings('#file_view').find('.file_input')
    for (var i = 0; i < file_input.length; i++) {
      if (file_input.eq(i).attr('file_num') == index) {
        file_input.eq(i).remove()
      }
    }
    $(this).parent('.cushion_enclosure_box_list').remove()
    var file_input_ele = $('#newPageGrey .file_input')
    if (file_input_ele.length) {
      for (var i = 0; i < file_input_ele.length; i++) {
        file_input_ele.eq(i).attr('file_num', i)
        file_input_ele.eq(i).attr('name', 'files' + i)
      }
    }
    var file_li1 = $('#newPageGrey').find('li.delete_file')
    for (var i = 0; i < file_li1.length; i++) {
      file_li1.eq(i).attr('file_num', i)
    }
  })
$('#newPageGrey').on('change', '.file_input', function () {

	  var file_input_ele = $('#newPageGrey .file_input')
	  
	  if (file_input_ele.length) {
	    for (var i = 0; i < file_input_ele.length; i++) {
	      file_input_ele.eq(i).attr('file_num', i)
	      file_input_ele.eq(i).attr('name', 'files' +  i)
	    }
	  }
  var file_li1 = $('#newPageGrey').find('li.delete_file')
  for (var i = 0; i < file_li1.length; i++) {
	  file_li1.eq(i).attr('file_num', i)
	  }
})


  //后台上传
  // var upload_file = $('#newPageGrey #file_view').find('.file_input')
  // var form = new FormData(document.getElementById("XXX"));
  // for (var i = 0; i < upload_file.length; i++) {
	//     if (upload_file.eq(i).attr('id') && (i !== 0)) {
	//       upload_file.eq(i).remove()
	//       break // 当有空input一定是最后一个,可以跳出循环
	//     }
	//     upload_file.eq(i).attr('name', 'files' + i)
	//     var key = 'files' + i	    
	//     var val = upload_file.eq(i).val()
	//     form.append(key, val)
  //   }
    
</script>

</html>

Fictitious DOM Operation

怎样添加、移除、移动、复制、创建和查找节点?

创建新节点

createDocumentFragment() //创建一个DOM片段
createElement() //创建一个具体的元素
createTextNode() //创建一个文本节点

//文档碎片    利于优化
var element  = document.getElementById('ul'); // assuming ul exists
var fragment = document.createDocumentFragment();
var browsers = ['Firefox', 'Chrome', 'Opera', 
    'Safari', 'Internet Explorer'];

browsers.forEach(function(browser) {
    var li = document.createElement('li');
    li.textContent = browser;
    fragment.appendChild(li);
});

element.appendChild(fragment);

添加、移除、替换、插入

appendChild() //添加
removeChild() //移除
replaceChild() //替换
insertBefore() //插入

查找

getElementsByTagName() //通过标签名称
getElementsByName() //通过元素的Name属性的值
getElementById() //通过元素Id,唯一性

insertAdjacentHTML

将指定的文本解析为HTML或XML,并将结果节点插入到DOM树中的指定位置。它不会重新解析它正在使用的元素,因此它不会破坏元素内的现有元素。这避免了额外的序列化步骤,使其比直接innerHTML操作更快。

element.insertAdjacentHTML(position, text);
position参数:
beforebegin 元素自身的前面。
afterbegin 插入元素内部的第一个子节点之前
beforeend 插入元素内部的最后一个子节点之后
afterend 元素自身的后面

// <div id="one">one</div> 
var d1 = document.getElementById('one'); 
d1.insertAdjacentHTML('afterend', '<div id="two">two</div>');

// 此时,新结构变成: // <div id="one">one</div><div id="two">two</div>


// ES6 version

// let html = `<div id="two">two</div>`;
// div.insertAdjacentHTML(`beforeend`, html);

TypeScript Done

deno的简读

deno是使用Go语言代替C++重新编写跨平台底层内核驱动,上层仍然使用V8引擎,最终提供一个安全的TypeScript运行时
链接:https://github.com/denoland/deno

TypeScript是什么?

TypeScript 是一种由微软开发的自由和开源的编程语言。它是 JavaScript 的一个超集,TypeScript 在 JavaScript 的基础上添加了可选的静态类型和基于类的面向对象编程。

TypeScript和JavaScript的对比

TypeScript是一个应用程序级的JavaScript开发语言。(这也表示TypeScript比较牛逼,可以开发大型应用,或者说更适合开发大型应用)
TypeScript是JavaScript的超集,可以编译成纯JavaScript。这个和我们CSS离的Less或者Sass是很像的,我们用更好的代码编写方式来进行编写,最后还是有好生成原生的JavaScript语言。
TypeScript跨浏览器、跨操作系统、跨主机、且开源。由于最后他编译成了JavaScript所以只要能运行JS的地方,都可以运行我们写的程序,设置在node.js里。
TypeScript始于JavaScript,终于JavaScript。遵循JavaScript的语法和语义,所以对于我们前端从业者来说,学习前来得心应手,并没有太大的难度。
TypeScript可以重用JavaScript代码,调用流行的JavaScript库。
TypeScript提供了类、模块和接口,更易于构建组件和维护。

TypeScript使用流程

首先安装TypeScript

npm install typescript -g
tsc --version

编写HelloWorld程序

终端输入:
1.npm init -y (初始化项目,生成package.json文件)
2.tsc --init (它是一个TypeScript项目的配置文件,可以通过读取它来设置TypeScript编译器的编译参数)
3.npm install @types/node --dev-save (主要是解决模块的声明文件问题)
4.编写hello.ts文件

var a:string = "HelloWorld"
console.log(a)

5.tsc hello.ts 编译成hello.js文件
6.node hello.js

TypeScript中的数据类型有

Undefined
Number
String
Boolean
enum 枚举类型
any 任意类型
void 空类型
Array
Tuple 元祖类型
Null

Number类型有

  • NaN
  • Infinity :正无穷大。
  • -Infinity:负无穷大。

enum类型

一般应用于固定数据

// enum REN{ nan , nv ,yao}
// console.log(REN.yao)  //返回了2,这是索引index,跟数组很象。

enum REN{
    nan = '男',
    nv = '女',
    yao= '妖'
}
console.log(REN.yao)  //返回了妖 这个字

any类型

TypeScript友好的为我们提供了一种特殊的类型any,比如我们在程序中不断变化着类型,又不想让程序报错,这时候就可以使用any了。

var t:any =10 
t = "jspang"
t = true
console.log(t)
Tuple类型(元祖类型)
>元祖是一种特殊的数组,元祖类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同 ``` //声明一个元祖类型 let x : [string,number] //正确的初始化 x = ['hello',10] //错误的初始化方法 x = [10,'hello'] ```

函数中传参

举个typescript语法的例子:

function searchXiaoJieJie3(...xuqiu:string[]):string{
    let  yy:string = '找到了'
    for (let i =0;i<xuqiu.length;i++){
        yy = yy + xuqiu[i]
        if(i<xuqiu.length){
            yy=yy+'、'
        }
    }
    yy=yy+'的小姐姐'
    return yy
}
var result:string  =  searchXiaoJieJie3('22岁','大长腿','瓜子脸','水蛇腰')
console.log(result)

局部变量·全局变量·var与let和javascript差不多,不一一言论

引用类型-数组

声明数组的方法

由let var 关键字来实现,ts中声明较复杂

let arr1:number[ ]     //声明一个数值类型的数组
let arr2:Array<string>  //声明一个字符串类型的数组

数组赋值

  • 字面量赋值法:直接使用“[ ]”对数组进行赋值。
//定义一个空数组,数组容量为0
let arr1:number[] = [] 
//定义一个数组时,直接给数组赋值
let arr2:number[] = [1,2,3,4,5]
//定义数组 的同事给数组赋值
let arr3:Array<string> = ['jspang','技术胖','金三胖']
let arr4:Array<boolean> = [ true,false,false]

//切记:
let arr5:number[] = [1,2,true]  //报错 必须存储number类型的数据
  • 构造函数赋值法:
let arr1:number[] = new Array()
let ara2:number[] = new Array(1,2,3,4,5)
let arr3:Array<string> = new Array('jspang','技术胖','金三胖')
let arr4:Array<boolean> = new Array(true,false,false)

引用类型-字符串

  • 基本类型字符串:由单引号或者双引号括起来的一串字符串。
  • 引用类型字符串:用new 实例化的 String类型。
let jspang:string = '技术胖'
let jspanga:String = new String("jspang.com")
console.log(jspang)  //技术胖
console.log(jspanga) //[String: 'jspang.com']

replace替换

let something:string = "清早起来打开窗,心情美美的,我要出去找小姐姐,心情美美的。"
let xiaoJieJie:string = "小姐姐"
console.log(something.replace(xiaoJieJie,'小哥哥'))  // /小姐姐/g全局匹配

引用类型-日期对象

1.不传递任何参数

let d:Date = new Date()
console.log(d)  //2018-09-06T06:48:12.504Z

2.传递一个整数

let d:Date = new Date(1000)
let da:Date = new Date(2000)
console.log(d)  //1970-01-01T00:00:01.000Z
console.log(da) //1970-01-01T00:00:02.000Z

3.传递一个字符串

let d1:Date = new Date('2018/09/06 05:30:00')
let d2:Date = new Date('2018-09-06 05:30:00')
let d3:Date = new Date('2018-09-06T05:30:00')
console.log(d1)  
console.log(d2)
console.log(d3)  //2018-09-05T21:30:00.000Z结果一样

4.传递表示年月日时分秒的变量

let d:Date = new Date(year,month,day,hours,minutes,seconds,ms);

  • year 表示年份,4位数字。
  • month表示月份,数值是0(1月)~11(12月)之间的整数。
  • day 表示日期。数值是1~31之间的整数。
  • hours 表示小时,数值是0-23之间的整数。
  • minutes 表示分钟数,数值是0~59之间的整数。
  • seconds 表示秒数,数值是0~59之间的整数。
  • ms 表示毫秒数,数值是0~999之间的整数。

引用类型-正则表达式

构造函数法

构造函数中可以传一个参数,也可以传递两个参数。一个是字符串描述,另一个是修饰符,比如g是全局修饰符,i是忽略大小写,m是多行模式。

let reg1:RegExp = new RegExp("jspang")  //表示字符串规则里含有jspang
console.log(reg1)
let reg2:RegExp = new RegExp("jspang",'gi')
console.log(reg2)

字面量法

let reg3:RegExp = /jspang/
let reg4:RegExp = /jspang/gi

RegExp中的常用方法

RegExp对象包含两个方法:test( )和exec( ),功能基本相似,用于测试字符串匹配。

  • test(string) :匹配。在字符串中查找是否存在指定的正则表达式并返回布尔值,如果存在则返回 true,不存在则返回 false。
  • exec(string) : 捕获。用于在字符串中查找指定正则表达式,如果 exec() 方法执行成功,则返回包含该查找字符串的相关信息数组。如果执行失败,则返回 null。
    待续~~~

babel-plugin-import

组件库按需加载 babel-plugin-import

按需加载插件。只需要引入模块即可,无需单独引入样式。babel-plugin-import

安装

npm install babel-plugin-import --save-dev

如下配置

// 在 .babelrc 或 babel-loader 中添加插件配置
// 注意:webpack 1 无需设置 libraryDirectory
{
"plugins": [
["import", {
"libraryName": "vant",
"libraryDirectory": "es",
"style": true
}]
]
}

引用

//以Vant为例
import { Button, Cell } from 'vant';
Vue.use(Button);

Headlines Interview

头条题目描述:

 const obj = {
    selector: {
      to: {
        toutiao: "FE Coder"
      }
    },
    target: [1, 2, {
      name: 'byted'
    }]
  };
get(obj, 'selector.to.toutiao', 'target[0]', 'target[2].name')
//结果:FE Coder   1    byted

思路一:

  function get(data, ...args) {
    const reg = /\[[0-9]+\]/gi;
    return args.map((item) => {
      const paths = item.split('.');
      let res = data;
      paths.map((path) => {
        if (reg.test(path)) {
          const match = path.match(reg)[0];
          console.log(match)
          // 将target[0]里的target储存到cmd里
          const cmd = path.replace(match, '');
          // 获取数组索引
          console.log(cmd)
          const arrIndex = match.replace(/[\[\]]/gi, '');
          console.log(cmd, arrIndex)
          res = res[cmd][arrIndex];
        } else {
          res = res[path];
        }
      });
      return res;
    });
  }

思路二:

  function get(data, ...args) {
    const res = JSON.stringify(data);
    return args.map(item => {
      return (new Function(`try {return ${res}.${item} } catch(e) {}`))()
    })
  }

CSS

CSS

选择器分类

  • 标签选择器 p{}
  • 类选择器 .class{}
  • 属性选择器 [type=radio]{}
  • 伪类选择器 :hover{}
  • 伪元素选择器 ::before{}
  • ID选择器 #ID{}
  • 组合选择器 [type=checkbox]+label{}
  • 否定选择器 not(.class){}
  • 通用选择器 *

选择器权重

权重计算规则:

  1. 第一等:代表内联样式,如: style=””,权值为1000。
  2. 第二等:代表ID选择器,如:#content,权值为0100。
  3. 第三等:代表类(.content)伪类和属性选择器,伪类选择器比如 :hover,:focus等等,权值为0010。
  4. 第四等:代表类型选择器和伪元素选择器,如div p,:before : after权值为0001。
  5. 通配符、子选择器、相邻选择器等的。如*、>、+,权值为0000。
  6. 继承的样式没有权值。

CSS3新特性

  • border-radius(圆角)
  • box-shadow(阴影)
  • text-shadow(文字特效)
  • linear-gradient(渐变)
  • transform(特效)
  • border-image
  • background-image backgroundimage:url('1.jpg),url('2.jpg')
  • background-cilp(裁剪)border-box / padding-box / content-box
  • background-origin(设置背景图像的原始起始位置)border-box / padding-box / content-box
  • background- repeat(设置是否及如何重复背景图像,默认地,背景图像在水平和垂直方向上重复。)
  • background-size(大小图像)

CSS布局

  • float浮动+margin
  • inline-block布局
  • flexbox布局/grid布局

float 布局

  1. 元素“浮动” 2. 脱离文档流 3. 但不脱离文本流

flex布局

面试题

盒模型

在标准模式下的盒模型: width /height = 内容的宽度 / 内容的高度
在怪异模式下的盒模型:width / height = 内容的宽度 + border + padding / 内容的高度 + border + padding
box-sizing有两个值一个是content-box,另一个是border-box。
当设置为box-sizing:content-box时,将采用标准模式解析计算;
当设置为box-sizing:border-box时,将采用怪异模式解析计算。

position属性 (z-index设置层级)

  • static 静态布局,按照文档流布局
  • relative 相对于元素本身的偏移,relative偏移时,元素所占据的文档空间不会产生偏移
  • absolute从文档流脱离,相对于最近的父级absolute或者relative,如果父级不是的话,会一直网上到body
  • fixed 相对于屏幕/可视区域
  • inherit 规定应该从父元素继承 position 属性的值

BFC(块格式化上下文 )

  • float属性不为none
  • position为absolute或fixed
  • display为inline-block, table-cell, table-caption, flex, inline-flex
  • overflow不为visible

清除浮动

第一种
  .clearfix:after{
        content: "";
        display: block;
        height: 0;
        clear:both;
        visibility: hidden;
  }
第二种
// 给父容器添加 overflow:hidden 或者 auto 样式,通过触发BFC方式,实现浮动
第三种
// 新添标签
  <div class="clear">额外标签法</div>
第四种 
// 双伪元素清除浮动(强烈推荐)
        .clearfix:before,
        .clearfix:after {
            display: table;
            content: "";    /*不用有内容也可以*/
        }

        .clearfix:after {
            clear: both;
        }

        .clearfix {
            *zoom: 1;
        }

href与src 区别?title与alt

href 锚点或资源之间定义一个链接或者关系,在 link和a 等元素上使用

src 是引入。在 img、script、iframe 等元素上使用。

title:既是html标签,又是html属性,title作为属性时,用来为元素提供额外说明信息.

alt:alt是html标签的属性,alt属性则是用来指定替换文字,只能用在img、area和input元素中(包括applet元素),用于网页中图片无法正常显示时给用户提供文字说明使其了解图像信息.

nth-of-type | nth-child?

举例说明:
<ul> <p>111</p> <span>222</span> <li>1</li> <li>2</li> <li>3</li> </ul>
li:nth-of-type(2):表示ul下的第二个li元素
li:nth-child(2):表示既是li元素又是在ul下的第二个元素(找不到)。
建议一般使用nth-of-type,不容易出问题。

:before 和 ::before 区别?

单冒号(:)用于CSS3伪类,双冒号(::)用于CSS3伪元素。 对于CSS2之前已有的伪元素,比如:before,单冒号和双冒号的写法::before作用是一样的。

如何让一个div 上下左右居中?

方法1: .div1{ position:absolute;  left:50%;   top:50%;   transform: translate(-50%,-50%); }
方法2: .div2{ position: absolute;  left:0;  top: 0;  bottom: 0;  right: 0;  margin: auto; }
方法3: .div3{ position: absolute;  left: 50%;  top:50%;  margin-left:-200px;  margin-top: -200px;  }

viewport 所有属性

  • width
  • height
  • initial-scale
  • minimum-scale

多行文本溢出显示省略号

overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;

伪类选择器和伪元素?c3中引入的伪类选择器有?c3中伪元素有?

伪类选择器单冒号 伪元素两个冒号

:not()选择器称为否定选择器
:empty()选择器表示的就是空
:first-child()选择器表示的是选择父元素的第一个子元素的元素E
:nth-child()选择某个元素的一个或多个特定的子元素。
:nth-last-child()从某父元素的最后一个子元素开始计算,来选择特定的元素
:nth-of-type(n)选择器和:nth-child(n)选择器非常类似,不同的是它只计算父元素中指定的某种类型的子元素。
:only-child表示的是一个元素是它的父元素的唯一一个子元素。
:first-line为某个元素的第一行文字使用样式。
:first-letter 为某个元素中的文字的首字母或第一个字使用样式。
:before 在某个元素之前插入一些内容。
:after 在某个元素之后插入一些内容。

::first-line选择元素的第一行,
::before和::after这两个主要用来给元素的前面或后面插入内容,这两个常用"content"配合使用,见过最多的就是清除浮动

常见兼容性问题?

  • 浏览器默认的margin和padding不同。解决方案是加一个全局的*{margin:0;padding:0;}来统一
  • 超链接访问过后hover样式就不出现了 被点击访问过的超链接样式不在具有hover和active了解决方法是改变CSS属性的排列顺序: L-V-H-A : a:link {} a:visited {} a:hover {} a:active {}
  • 上下margin重合问题

ie和ff都存在,相邻的两个div的margin-left和margin-right不会重合,但是margin-top和> margin-bottom却会发生重合。
解决方法,养成良好的代码编写习惯,同时采用margin-top或者同时采用margin-bottom。

  • IE下,event对象有x,y属性,但是没有pageX,pageY属性; Firefox下,event对象有pageX,pageY属性,但是没有x,y属性. * 解决方法:(条件注释)缺点是在IE浏览器下可能会增加额外的HTTP请求数。

px/em/rem有什么区别?

px 在缩放页面时无法调整那些使用它作为单位的字体、按钮等的大小;
em 的值并不是固定的,会继承父级元素的字体大小,代表倍数;
rem 的值并不是固定的,始终是基于根元素 的,也代表倍数。

如果对css进行优化如何处理?

压缩打包,图片整合,避免使用Hack,解决兼容问题,使用简写,让CSS能保证日后的维护

图片和文字在同一行显示?

在css中给div添加上“vertical-align:middle”属性。

animation 与 transition transform

// animation transition 区别:
他们的主要区别是transition需要触发一个事件才能改变属性, 而animation不需要触发任何事件的情况下才会随时间改变属性值,并且transition为2帧,从from .... to,而animation可以一帧一帧的

transform的主要用途是用来做元素的特殊变形

  • translate3d(x,y,z) 是用来控制元素的位置在页面上的三轴的位置的;
  • rotate(deg)是用来控制元素旋转角度的
  • skewx,y 这个属性是用来制作倾斜度的
  • scale3d(x,y,z) 用来放大缩小效果,属性是比值;
  • matrix3d,css矩阵

Transition属性是一个简单的动画属性,animation的简化版本

  • -webkit-transition:left 0.5s ease-out;
  • transition-property(none/all/indent):变换的属性
  • transition-duration:转换持续时间,单位 s/ms
  • transition-timing-function(ease/liner/ease-in/ease-out/ease-in-out/cubic-bezier):变换速率
  • transition-delay:转换开始执行的时间,事件触发后多久执行

animation则根据这个keyframes提供的属性变化方式去计算元素动画当中的属性

  • animation-name:元素绑定动画名(@Keyframes定义的动画名)
  • animation-duration:动画持续时间
  • animation-delay:开始时间
  • animation-interation-count: 循环播放次数
  • animation-direction: 动画运动方向
@keyframes 'wobble'{
  0%{
   left:100px
}
   30%{
   left:300px;
}
  100%{
   left:500px;
}
}
.animate{
left:100px;
   -webkit-animation:wobble 0.5s ease-out;
   -webkit-animation-fill-mode:backwards;
}

CSS中 link 和@import 的区别是什么?

  • link属于HTML标签,而@import是CSS提供的页面被加载的时,link会同时被加载,而@import引用的CSS会等到页面被加载完再加载
  • import只在IE5以上才能识别,而link是HTML标签,无兼容问题
  • link方式的样式的权重 高于@import的权重.

解释下 CSS sprites,以及你要如何在页面或网站中使用它

图像拼合,是把网页中一些背景图片整合到一张图片文件中,再利用CSS的“background-image”,“background- repeat”,“background-position”的组合进行背景定位,减少很多图片请求的开销,减少请求耗时

使元素消失的方法

visibility:hidden、display:none、z-index=-1、opacity:0

a点击出现框,解决方法

a,a:hover,a:active,a:visited,a:link,a:focus{ 
 -webkit-tap-highlight-color:rgba(0,0,0,0);
 -webkit-tap-highlight-color: transparent;
 outline:none;background: none;
 text-decoration: none;border:none;
 -webkit-appearance: none; }

bug

1.我父组件里传一个json数据,但是子组件大多时候都是NULL,但是有的时候子组件又可以接收到

props: ['charData'],
  data() {
    return {
      dataList: []
    }
  }
  watch: {
    charData: function (newVal,oldVal) {
      
    }
  }
  //监听charData的值,当它由空转变时就会触发,这时候就能取到,拿到值后要做的处理方法也需要在watch里面执行

2.vue拦截器

// 引入axios
import axios from 'axios'
// axios配置
Vue.prototype.$http = axios

// 配置默认axios参数
axios.defaults.baseURL = '/'
axios.defaults.timeout = 1000000
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'

// 添加请求拦截器
axios.interceptors.request.use(function (config) {
  let token = localStorage.getItem('token')
  if(token== null && router.currentRoute.path == '/login'){// 本地无token,不为登录 跳转至登录页面
    router.push('/login')
  }else{
    if(config.data==undefined){
      config.data = {
        "token":token
      }
    }else{
      Object.assign(config.data,{"token":token})
    }

  }
  return config
}, function (error) {
  iView.Message.error('请求失败')
  return Promise.reject(error)
})

// 返回结果拦截
axios.interceptors.response.use(function (response) {
  if(response.hasOwnProperty("data") && typeof response.data == "object"){
      if(response.data.code === 998){// 登录超时 跳转至登录页面
          iView.Message.error(response.data.msg)
          router.push('/login')
          return Promise.reject(response)
      }else if (response.data.code === 1000) {// 成功
        return Promise.resolve(response)
      }
  } else {
    return Promise.resolve(response)
  }

}, function (error) {
  // 请求取消 不弹出
  if(error.message != '0000'){
    iView.Message.error('请求失败')
  }

  // 请求错误时做些事
  return Promise.reject(error)
})

3.使用keep-alive标签后部分安卓机返回缓存页位置不精确问题

//router全局配置即可
<div id="app">
  <keep-alive>
   <router-view v-if="$route.meta.keepAlive"></router-view>
  </keep-alive>
  <router-view v-if="!$route.meta.keepAlive"></router-view>
</div>
const router = new Router({
 scrollBehavior(to, from, savedPosition) {
  if (savedPosition && to.meta.keepAlive) {
   return savedPosition;
  }
  return { x: 0, y:0 };
 },
});

4.页面返回出现空白屏问题

//全局配置,共用
const router = new Router({
 scrollBehavior(to, from, savedPosition) {
  // keep-alive 返回缓存页面后记录浏览位置
  if (savedPosition && to.meta.keepAlive) {
   return savedPosition;
  }
  // 异步滚动操作
  return new Promise((resolve) => {
   setTimeout(() => {
    resolve({ x: 0, y: 1 });
   }, 0);
  });
 },
});

5.vue-router中的全局钩子函数

//在路由跳转之前做什么  权限判定
router.beforeEach((to, from, next) => {
    let token = router.app.$storage.fetch("token");
    let needAuth = to.matched.some(item => item.meta.login);
    if(!token && needAuth) return next({path: "/login"});
    next();
});
//使用钩子函数对路由进行权限跳转
router.beforeEach((to, from, next) => {
    const role = localStorage.getItem('ms_username');
    if(!role && to.path !== '/login'){
        next('/login');
    }else if(to.meta.permission){
        // 如果是管理员权限则可进入,这里只是简单的模拟管理员权限而已
        role === 'admin' ? next() : next('/403');
    }else{
        // 简单的判断IE10及以下不进入富文本编辑器,该组件不兼容
        if(navigator.userAgent.indexOf('MSIE') > -1 && to.path === '/editor'){
            Vue.prototype.$alert('vue-quill-editor组件不兼容IE10及以下浏览器,请使用更高版本的浏
            览器查看', '浏览器不兼容通知', {
                confirmButtonText: '确定'
            });
        }else{
            next();
        }
    }
})

//暂无使用
router.afterEach((to, from) => {})

6 vue在页面渲染出来前显示{{变量名}}


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <style>
        [v-cloak]{
            display: none
        }
    </style>
</head>
<body>
   <div id="box">
    <p v-cloak>{{msg}}</p>
   </div>
    <script src="js/vue.js"></script>
    <script>
        new Vue({
            el:"#box",
            data:{
                msg:"hellovue"
            }
        })
    </script>
</body>
</html>

7 nextTick

https://segmentfault.com/a/1190000012861862

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

应用场景:需要在视图更新之后,基于新的视图进行操作。

////点击按钮显示原本以 v-show = false 隐藏起来的输入框,并获取焦点。
showsou(){
  this.showit = true
  this.$nextTick(function () {
    // DOM 更新了
    document.getElementById("keywords").focus()
  })
}

//点击获取元素宽度。
<div id="app">
    <p ref="myWidth" v-if="showMe">{{ message }}</p>
    <button @click="getMyWidth">获取p元素宽度</button>
</div>

getMyWidth() {
    this.showMe = true;
    //this.message = this.$refs.myWidth.offsetWidth;
    //报错 TypeError: this.$refs.myWidth is undefined
    this.$nextTick(()=>{
        //dom元素更新后执行,此时能拿到p元素的属性
        this.message = this.$refs.myWidth.offsetWidth;
  })
}

8 为啥 await 不能用在 forEach 中(掘金)

forEach只支持同步代码

链接:https://juejin.im/post/5cb1d5a3f265da03587bed99

//解决方法
async function test() {
  let arr = [3, 2, 1]
  for(let item of arr){
    const res = await fetch(item)
    console.log(res)
  }
  console.log('end')
}

//OR

async function test() {
  let arr = [3, 2, 1]
  await Promise.all(
    arr.map(async item => {
      const res = await fetch(item)
      console.log(res)
    })
  )
  console.log('end')
}

function fetch(x) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(x)
    }, 500 * x)
  })
}
test()
<!--预期结果 -->
// 1  2  3  end

动态属性名(可使用表达式来设置动态属性名或方法名)

<!-- 属性name -->
<a :[name]="url"> ... </a>
<!-- 计算属性sss和s -->
<img :[sss]="/img/test.png"/>  
<!-- 方法change1和change2 -->
<img :[change1()]="change2()"/>

data: {
    name: 'href',
    sss: 'src'
}

computed/methods/watch

  • computed可使用get/set
   computed: {
       top() {
           return 'top'
       },
       name: {
           get () {
               return this.name
           },
           set (val) {
               this.name = val
           }
       }
   }
  • computed可缓存,但不可传参,会根据data中的属性变化而变化,即是根据响应式依赖来变化,而Date不是响应式依赖,即不会变化;method则每次都会进行计算,但可传参。

  • watch用于处理异步或开销较大的操作,如输入搜索时。

style绑定

  • 直接对象或变量对象
  • 计算属性
  • 直接style或style对象
<!-- 属性名可加引号也可不加,属性小驼峰 -->
<div :style="{ 'color': 'red', fontSize: fontSize + 'px' }">样式3</div>
  • 数组结合三目/数组结合对象
data: {
  isActive: true,
  activeClass: 'active'
}
<!-- 使用数组时变量和字符串需要通过引号来区分 -->
<div :class="[isActive ? activeClass : '', 'errorClass']"></div>
<!-- 使用对象时类名不加引号可表示变量也可表示字符串 -->
<div :class="[{ active: isActive }, 'errorClass']"></div>

v-if条件渲染

可使用template包裹元素,template会被当成不可见的包裹元素

<template v-if="ok">
    <h1>Title</h1>
    <p>Paragraph 1</p>
    <p>Paragraph 2</p>
</template>

多条件判断

<div v-if="type === 'A'">
  A
</div>
<div v-else-if="type === 'B'">
  B
</div>
<div v-else-if="type === 'C'">
  C
</div>
<div v-else>
  Not A/B/C
</div>

key

添加key防止vue重复利用不想被重复利用的元素,如下的input如果不添加key,则vue会重复使用key,进而input的value值在切换后还会被保留,因为vue仅仅替换了placeholder

<template v-if="loginType === 'username'">
  <label>Username</label>
  <input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
  <label>Email</label>
  <input placeholder="Enter your email address" key="email-input">
</template>

v-if和v-show

v-if是组件的销毁和重建,如果初始条件为false,则什么都不做,直到变为真,所以切换开销高,运行条件很少改变时适用

v-show是display:none和block之间的CSS切换,基于渲染,不管初始条件如何都会渲染,所以初始渲染开销高,切换频率高时适用

更改响应式数据

Vue.set(object, key, value)

this.$set(object, key, value)

this.items.splice(index, 1, newValue)

// 不要直接Object.assign(this.items, {age: 18}
this.items = Object.assign({}, this.items, {
  age: 18,
  favoriteColor: 'Vue Green'
})

事件修饰符

.passive:滚动的默认事件会立即出发,即告诉浏览器不想阻止默认事件的触发,可提升移动端性能

<div :scroll.passive="onScroll">...</div>

.capture:添加事件监听器时使用事件捕获模式,即元素自身触发的事件先在此处理,然后才交由内部元素进行处理

.self:只当在 event.target 是当前元素自身时触发处理函数,即事件不是从内部元素触发的

.once:点击事件只会触发一次

键盘修饰符:

<input v-on:keyup.enter="submit">

Prop

使用v-bind="obj"会将对象的每个属性都作为一个独立的prop传入进去,所以接受时也需要逐个属性接收。

<test v-bind="obj"></test>

props虽然是单向数据流,但对于引用类型,子组件还是可以改变父组件的状态

props会在组件实例创建之前进行验证,所以实例的属性再default或validator中是不可用的。

slot

  • 具名插槽
<base-layout>
  <template v-slot:header>
    <h1>Here might be a page title</h1>
  </template>
<!-- 默认插槽也可不用加上template和v-slot -->
  <template v-slot:default>
    <p>A paragraph for the main content.</p>
    <p>And another one.</p>
  </template>
  <template v-slot:footer>
    <p>Here's some contact info</p>
  </template>
</base-layout>
  • 作用域插槽
<!-- current-user组件 -->
<span>
  <slot :user="user">
    {{ user.lastName }}
  </slot>
</span>

<!-- 父级组件通过自定义名称访问子级作用域 -->
<current-user>
  <template v-slot:default="slotProps">
    {{ slotProps.user.firstName }}
  </template>
</current-user>

<!-- 支持缩写和解构 -->
<current-user>
  <template #default="{ user = { firstName: Gust } }">
    {{ user.firstName }}
  </template>
</current-user>

组件通信

  • vuex/eventBus
  • prop/$emit
  • $children/$parent
  • provide/inject
  • $refs

路由

区分:this.$router指路由器,this.$route指当前路由

通配符:捕获所有路由或 404 Not found路由

  // 含通配符的路由都要放在最后,因为优先级由定义顺序决定
{
  // 会匹配所有路径
  path: '*'
}
{
  // 会匹配以 `/user-` 开头的任意路径
  path: '/user-*'
}

当使用一个通配符时,$route.params内会自动添加一个名为 pathMatch 参数。它包含了 URL 通过通配符被匹配的部分:

// 给出一个路由 { path: '/user-*' }
this.$router.push('/user-admin')
this.$route.params.pathMatch // 'admin'
// 给出一个路由 { path: '*' }
this.$router.push('/non-existing')
this.$route.params.pathMatch // '/non-existing'

点击 等同于调用 router.push(...)方法,因为会在内部调用该方法,进而在history栈添加一个新的记录

使用了push时,如果提供的path不完整,则params会被忽略,需要提供路由的 name 或手写完整的带有参数的 path:

const userId = '123'
router.push({ name: 'user', params: { userId }})  // -> /user/123
router.push({ path: `/user/${userId}` })          // -> /user/123
// 这里的 params 不生效
router.push({ path: '/user', params: { userId }}) // -> /user

router.push/router.replace/router.go 效仿于 window.history.pushState/window.history.replaceState/window.history.go

命名视图:router-view可设置名字,如果router-view没有设置名字,那么默认为 default

<router-view></router-view>
<router-view name="a"></router-view>
<router-view name="b"></router-view>

const router = new VueRouter({
  routes: [
    {
      path: '/',
      components: {
        default: Foo,
        a: Bar,
        b: Baz
      } 
    }
  ]
})

路由使用props:可将路由参数设置为组件属性

const User = {
  props: ['id'],
  template: '<div>User {{ id }}</div>'
}
// 通过布尔值设置
const router = new VueRouter({
  routes: [
    { path: '/user/:id', component: User, props: true },

    // 对于包含命名视图的路由,你必须分别为每个命名视图添加 `props` 选项:
    {
      path: '/user/:id',
      components: { default: User, sidebar: Sidebar },
      props: { default: true, sidebar: false }
    }
  ]
})

// 通过函数设置query 
// URL /search?q=vue 会将 {name: 'vue'} 作为属性传递给 SearchUser 组件
const router = new VueRouter({
  routes: [
    { path: '/search', component: SearchUser, props: (route) => ({ name: route.query.q }) }
  ]
})

beforeRouteEnter:可使用beforeRouteEnter来提前获取接口数据,同时需要在next后才能访问到实例:

beforeRouteEnter(to, from, next) {
  axios('/text.json').then(res => {
    next(vm => {
      vm.datas = res
    })
  })
}

路由设置有参数时,如果跳转页面后再通过返回键返回时,路由会保留有参数,如果通过push跳转返回,则不会保留该参数,这在第三方调用模块传参时需要注意。

iview>table>render函数

        {
          title: '退款方式',
          render: (h, params) => {
            return h('Select', {
              props: {
                clearable: true,
                value: 0
              },
              on: {
                'on-change': (val) => {
                  this.item_str[params.index].type = val
                }
              }
            }, this.action.map(item => {
              return h('Option', {
                props: {
                  value: item.value,
                  label: item.name
                }
              })
            }))
          }
        },
        {
          title: '退款金额',
          render: (h, params) => {
            return h('Input', {
              props: {
                value: '',
                size: 'small'
              },
              on: {
                input: (val) => {
                  console.log(params)
                  this.item_str[params.index].amount = val
                }
              }
            })
          }
        },
        {
          title: '退款原因',
          render: (h, params) => {
            return h('Input', {
              props: {
                value: ''
              },
              on: {
                input: (val) => {
                  console.log(params)
                  this.item_str[params.index].reason = val
                }
              }
            })
          }
        },
        {
          title: '操作',
          render: (h, params) => {
            return h('div', [
              h('Button', {
                style: {
                  color: '#3399ea',
                  cursor: 'pointer'
                },
                on: {
                  click: () => {
                    this.showDetail()
                  }
                }
              }, '添加'),
              h('Button', {
                style: {
                  color: '#3399ea',
                  cursor: 'pointer'
                },
                on: {
                  click: () => {
                  }
                }
              }, '删除')
            ])
          }
        }

Nginx

初始Nginx

Nginx是一款轻量级的HTTP服务器,采用事件驱动的异步非阻塞处理方式框架,这让其具有极好的IO性能,时常用于服务端的反向代理和负载均衡。

ES6

Set

new Set([iterable]),返回一个Set对象,这里可以需要Array.from进行转换

var set = new Set([1]);
set.add(100)        // Set { 1,100 }            
set.delete(1)       // Set { 100 }      
set.has(3)          // false
//set.clear()       // 清除所有成员
set.size          //数量
console.log(set.entries())   //遍历
console.log(set.keys())       //遍历
console.log(set.values())     //遍历
for(let item of set.entries()){
  console.log(item)
}
for(let item of set.keys()){
  console.log(item)
}
  • 数组去重
Array.from(new Set([1,3,1,NaN,NaN,null,undefined,null,undefined]))  //[ 1, 3, NaN, null, undefined ]
  • Set与Array转换
var arr = [1,4,5,6];
var set = new Set(arr)
console.log([...set])
  • 字符串转Set
var  text = "yuan";
var stringSet = new Set(text);
console.log(stringSet); // Set(4) {"y", "u", "a", "n"}
stringSet.size; //4
  • 实现并集、交集、差集
let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);
// 并集
let union = new Set([...a, ...b]); // Set {1, 2, 3, 4} 
// 交集
let intersect = new Set([...a].filter (x => b.has(x))); // Set { 2, 3} 
// 差集
let difference = new Set([...a].filter (x => !b.has(x))); // Set { 1 }

Map

对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。

var myMap = new Map();
 
var keyObj = {},
    keyFunc = function () {},
    keyString = "a string";
 
// 添加键
myMap.set(keyString, "和键'a string'关联的值");
myMap.set(keyObj, "和键keyObj关联的值");
myMap.set(keyFunc, "和键keyFunc关联的值");
 
myMap.size; // 3
 
// 读取值
myMap.get(keyString);    // "和键'a string'关联的值"
myMap.get(keyObj);       // "和键keyObj关联的值"
myMap.get(keyFunc);      // "和键keyFunc关联的值"
 
myMap.get("a string");   // "和键'a string'关联的值"
                         // 因为keyString === 'a string'
myMap.get({});           // undefined, 因为keyObj !== {}
myMap.get(function() {}) // undefined, 因为keyFunc !== function () {}

将 NaN 作为 Map 的键

var myMap = new Map();
myMap.set(NaN, "not a number");

myMap.get(NaN); // "not a number"

var otherNaN = Number("foo");
myMap.get(otherNaN); // "not a number"

使用 for..of 方法迭代 Map

var myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");

for (var key of myMap.keys()) {
  console.log(key);
}
// 将会显示两个log。 一个是 "0" 另一个是 "1"

for (var value of myMap.values()) {
  console.log(key,value);
}
// // 将会显示两个log。 一个是 "zero" 另一个是 "one"

for (var [key, value] of myMap.entries()) {
  console.log(key,value);
}
// 将会显示两个log。 一个是 "0  zero" 另一个是 "1  one"

Map对象也能与数组合并

var first = new Map([
  [1, 'one'],
  [2, 'two'],
  [3, 'three'],
]);

var second = new Map([
  [1, 'uno'],
  [2, 'dos']
]);

// Map对象同数组进行合并时,如果有重复的键值,则后面的会覆盖前面的。
var merged = new Map([...first, ...second, [1, 'eins']]);

console.log(merged.get(1)); // eins
console.log(merged.get(2)); // dos
console.log(merged.get(3)); // three

Number新增方法

  • Number.isFinite()

用来检查一个数值是否为有限的(finite),即不是Infinity。
如果参数类型不是数值,Number.isFinite一律返回false

  • Number.isInteger()

用来判断一个数值是否为整数

Number.isInteger(25) // true
Number.isInteger(5E-324) // false
Number.isInteger(5E-325) // true  5E-325由于值太小,会被自动转为0,因此返回true。
Number.isInteger(25.1) // false
Number.isInteger() // false
Number.isInteger(null) // false
Number.isInteger('15') // false
Number.isInteger(true) // false
  • Number.prototype.toPrecision

可在对象的值超出指定位数时将其转换为指数计数法。

function precise(x) {
  return Number.parseFloat(x).toPrecision(4);
}

console.log(precise(123.456));
// expected output: "123.5"

console.log(precise(0.004));
// expected output: "0.004000"

console.log(precise('1.23e+5'));
// expected output: "1.230e+5"

ES6中的循环

for..in..

Object.keys(obj)

Object.getOwnPropertyNames(obj)

Object.getOwnPropertySymbols(obj)

Reflect.ownKeys(obj)

Obejct.assign()

方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

const target = { a: 1, b: 2 };
const source = { b: 4, c: 5 };

const returnedTarget = Object.assign(target, source);

console.log(target);
// expected output: Object { a: 1, b: 4, c: 5 }

console.log(returnedTarget);
// expected output: Object { a: 1, b: 4, c: 5 }

Object.entries()

方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环也枚举原型链中的属性)

const object1 = { foo: 'bar', baz: 42 };
console.log(Object.entries(object1)[1]);
// expected output: Array ["baz", 42]

const object2 = { 0: 'a', 1: 'b', 2: 'c' };
console.log(Object.entries(object2)[2]);
// expected output: Array ["2", "c"]

const result = Object.entries(object2).sort((a, b) => a - b);
console.log(Object.entries(result)[1]);
// expected output: Array ["1", Array ["1", "b"]]

forEach

当数组中元素是值类型,forEach绝对不会改变数组;当是引用类型,则可以改变数组
不支持链式调用

var arr1 = [
   {name:'鸣人',age:16},
   {name:'佐助',age:17}
];
var arr2 = [1,2,3];

arr1.forEach(item => { 
  item.age = item.age + 1}
);

//=> [{name:'鸣人',age:17},{name:'佐助',age:18}]

arr2.forEach(item => {
  item = item * 2}
)

// => [1,2,3]

filter

过滤数据,返回一个新数组

let newArr = [1,2,3,4,5].filter(item =>{
   if(item > 3) return item 
})
//  => [4,5]

map

map即映射,原数组被映射成对应新数组
map方法不能使用于过滤

let arr = [1,2,3]
arr = arr.map(item=>item*2)
//1,4,9

let newArr = [1,2,3,4,5].map(item => { if(item > 3) return item })
// => [undefined, undefined, undefined, 4, 5]

sort

判断大小
直接改变原始数组

[1,2,3,7,8,65,5,4].sort((a,b)=>{
  return a - b;
})

let Users = [
  {name:'鸣人',age:16},
  {name:'卡卡西',age:28},
  {name:'自来也',age:50},
  {name:'佐助',age:17}
];
Users.sort((a,b)=> {
    a.age - b.age
})

// => 鸣人、佐助、卡卡西、自来也

some

某一条件成立则返回true 类似于||
在空数组上调用固定返回 false

let result = [2,4,6,7].some(item=>item > 6)
//true

every

全部成立返回true 类似于&&
在空数组上调用固定返回 true

let result = [2,4,6,7].every(item=>item > 6)
//false
let result1 = [].every(item=>item)
//true

findIndex

中断遍历,IE11不支持,兼容使用Lodash的_.findIndex()
返回当前中断索引

let ass4 = [1,5,6,8,5].findIndex(item=>{
	return item > 6
})
//3

reduce具体用例

// 累加对象数组里的值
var initialValue = 0;
var sum = [{x: 1}, {x:2}, {x:3}].reduce(function (accumulator, currentValue) {
    return accumulator + currentValue.x;
},initialValue)

// console.log(sum) // logs 6

// 将二维数组转化为一维
var flattened = [[0, 1], [2, 3], [4, 5]].reduce(
  function(a, b) {
    return a.concat(b);
  },
  []
);
// flattened is [0, 1, 2, 3, 4, 5]

// 计算数组中每个元素出现的次数
var names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];

var countedNames = names.reduce(function (allNames, name) {
  if (name in allNames) {
    allNames[name]++;
  }
  else {
    allNames[name] = 1;
  }
  return allNames;
}, {});
// countedNames is:
// { 'Alice': 2, 'Bob': 1, 'Tiff': 1, 'Bruce': 1 }

// 按属性对object分类
var people = [
  { name: 'Alice', age: 21 },
  { name: 'Max', age: 20 },
  { name: 'Jane', age: 20 }
];

function groupBy(objectArray, property) {
  return objectArray.reduce(function (acc, obj) {
    var key = obj[property];
    if (!acc[key]) {
      acc[key] = [];
    }
    acc[key].push(obj);
    return acc;
  }, {});
}

var groupedPeople = groupBy(people, 'age');
// groupedPeople is:
// { 
//   20: [
//     { name: 'Max', age: 20 }, 
//     { name: 'Jane', age: 20 }
//   ], 
//   21: [{ name: 'Alice', age: 21 }] 
// }

// 数组去重
let arr = [1,2,1,2,3,5,4,5,3,4,4,4,4];
let result = arr.sort().reduce((init, current) => {
    if(init.length === 0 || init[init.length-1] !== current) {
        init.push(current);
    }
    return init;
}, []);
// console.log(result); //[1,2,3,4,5]


// reduce兼容处理
if (!Array.prototype.reduce) {
  Object.defineProperty(Array.prototype, 'reduce', {
    value: function(callback /*, initialValue*/) {
      if (this === null) {
        throw new TypeError( 'Array.prototype.reduce ' + 
          'called on null or undefined' );
      }
      if (typeof callback !== 'function') {
        throw new TypeError( callback +
          ' is not a function');
      }

      // 1. Let O be ? ToObject(this value).
      var o = Object(this);

      // 2. Let len be ? ToLength(? Get(O, "length")).
      var len = o.length >>> 0; 

      // Steps 3, 4, 5, 6, 7      
      var k = 0; 
      var value;

      if (arguments.length >= 2) {
        value = arguments[1];
      } else {
        while (k < len && !(k in o)) {
          k++; 
        }

        // 3. If len is 0 and initialValue is not present,
        //    throw a TypeError exception.
        if (k >= len) {
          throw new TypeError( 'Reduce of empty array ' +
            'with no initial value' );
        }
        value = o[k++];
      }

      // 8. Repeat, while k < len
      while (k < len) {
        // a. Let Pk be ! ToString(k).
        // b. Let kPresent be ? HasProperty(O, Pk).
        // c. If kPresent is true, then
        //    i.  Let kValue be ? Get(O, Pk).
        //    ii. Let accumulator be ? Call(
        //          callbackfn, undefined,
        //          « accumulator, kValue, k, O »).
        if (k in o) {
          value = callback(value, o[k], k, o);
        }

        // d. Increase k by 1.      
        k++;
      }

      // 9. Return accumulator.
      return value;
    }
  });
}

vue after feel

vue.js的初引入

   <div id="app">
        {{message}}
        <span @click=handleClick();>切换</span>
    </div>
    <script type="text/javascript">
        var app=new Vue({
            el:'#app',
            data(){
                return {
                    message:'hello Vue!',
                    x:0
                }
            },
            methods:{     
                handleClick(){
                    this.x++;
                    if(this.x % 2 == 0){
                        this.message='hello vue1';
                    }else{
                        this.message='hello vue2'; 
                    }
                }

            }
        })
    </script>

v-if v-else v-sho

v-if操作的是DOM元素
v-show操作的是属性
v-if: 判断是否加载,可以减轻服务器的压力,在需要时加载。
v-show:调整css dispaly属性,可以使客户端操作更加流畅

watch与computed

computed:计算属性将被混入到 Vue 实例中。所有 getter 和 setter 的 this 上下文自动地绑定为 Vue 实例。
注意如果你为一个计算属性使用了箭头函数,则 this 不会指向这个组件的实例,不过你仍然可以将其实例作为函数的第一个参数来访问。

watch:尽量减少箭头函数使用(this指向不同),一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象。Vue 实例将会在实例化时调用 $watch(),遍历 watch 对象的每一个属性。

//computed:
    <div id="app">
        <input type="text" v-model="firstName" />
        <input type="text" v-model="lastName" /> 
        {{fullName}}
      </div>
  
      <script>
        new Vue({
          el: '#app',
          data: {
            firstName: 'hello',
            lastName: 'vue'
          },
          computed:{
            fullName:function(){
                return this.firstName+""+this.lastName;
            }
          }
        });

        var vm = new Vue({
            data: { a: 1 },
            computed: {
                // 仅读取
                aDouble: function () {
                return this.a * 2
                },
                // 读取和设置
                aPlus: {
                get: function () {
                    return this.a + 1
                },
                set: function (v) {
                    this.a = v - 1
                }
        }
  }
})
vm.aPlus   // => 2
vm.aPlus = 3
vm.a       // => 2  
vm.aDouble // => 4


//watch:
  <div id="app">
        <input type="text" v-model="firstName" />
        <input type="text" v-model="lastName" /> 
        {{fullName}}
      </div>
  
      <script>
        new Vue({
          el: '#app',
          data: {
            firstName: 'hello',
            lastName: 'vue',
            fullName: 'hello vue'
          },
            watch: {
            'firstName': function(newval, oldval) {
              console.log(newval,oldval);
              this.fullName = this.firstName + this.lastName;
            },
            'lastName': function(newval, oldval) {
              console.log(newval,oldval);
              this.fullName = this.firstName + this.lastName;
            }
          }
        });
      </script>   

    
      deep: true   深度watcher
      immediate: true 该回调将会在侦听开始之后被立即调用  

$mount $watch

$mount作用为手动挂载,可用于延时挂载

 app.$watch('temperature',function(newVal,oldVal){
     console.log(newVal,oldVal);
})

new Vue({
    data:{

    },
    ...
}).$mount('#app')

数组排序(computed的具体使用)

<div id="app">
        {{itemSort}}        
    </div>
    <script type="text/javascript">
        var app=new Vue({
            el:'#app',
            created(){
                sortNumber=(a,b)=>{
                    return a-b
                }
            },
            data(){
                return {
                    items:[4,3,5,7,8,100,1,50,45,23],
                    
                }
            },
            methods:{  },
            computed:{
                itemSort:function(){
                    return this.items.sort(sortNumber);
                }, 
            }
        })
    </script>

对象排序(computed的具体使用)

<div id="app">
        <ul>
            <li v-for='item in sortItem'>
                {{item.name}}-{{item.age}}
            </li>
        </ul>     
    </div>
    <script type="text/javascript">
        var app=new Vue({
            el:'#app',
            created(){
                  //数组对象方法排序:
                  sortByKey=(array,key)=>{
                            return array.sort(function(a,b){
                            var x=a[key];
                            var y=b[key];
                            return ((x<y)?-1:((x>y)?1:0));
                        });
                }
            },
            data(){
                return {
                    itemsArr:[
                        {name:'jili',age:22},
                        {name:'cheng',age:10},
                        {name:'lala',age:9}
                    ] 
                }
            },
            methods:{     
            },
            computed:{
                sortItem:function(){
                    return sortByKey(this.itemsArr,'age');
                }
            }
        })
    </script> 

v-text & v-html & v-model

//v-text可以简写为{{}},vue中有个指令叫做 v-once 可以通过v-once与v-text结合,实现仅执行一次性的插值
<span v-once>这个将不会随msg属性的改变而改变: {{ msg }}</span>

v-html用于输出html,它与v-text区别在于v-text输出的是纯文本,浏览器不会对其再进行html解析,但v-html会将其当html标签解析后输出。

需要注意的是:在生产环境中动态渲染HTML是非常危险的,因为容易导致XSS攻击。所以只能在可信的内容上使用v-html,永远不要在用户提交和可操作的网页上使用

v-model通常用于表单组件的绑定,例如input,select等。它与v-text的区别在于它实现的表单组件的双向绑定,如果用于表单控件以外标签是没有用的。

 <div id="app">
        <p>原始文本信息:{{message}}</p>
        <h3>文本框</h3>
        <p>v-model:<input type="text" v-model="message"></p>
    </div>
    <script>
        var app=new Vue({
        el:'#app',
        data:{
            message:'hello Vue!'
        }
    })
    </script>

vue语法修饰符

  • .lazy:取代 imput 监听 change 事件。
  • .number:输入字符串转为数字。
  • .trim:输入去掉首尾空格。

多选按钮与单选按钮

<!-- 多选按钮 -->
 <div id="app">
        <h3>多选绑定一个数组</h3>
       <p>
            <input type="checkbox" id="JSPang" value="JSPang" v-model="web_Names">
            <label for="JSPang">JSPang</label><br/>
            <input type="checkbox" id="Panda" value="Panda" v-model="web_Names">
            <label for="JSPang">Panda</label><br/>
            <input type="checkbox" id="PanPan" value="PanPan" v-model="web_Names">
            <label for="JSPang">PanPan</label>
            <p>{{web_Names}}</p>
       </p>
   </div>
    <script>
        var app=new Vue({
        el:'#app',
        data:{
            web_Names:[]
        }
    })
    </script>

    <!-- 单选按钮 -->
     <div id="app">
        <h3>单选按钮绑定</h3>
    <input type="radio" id="one" value="男" v-model="sex">
    <label for="one">男</label>
    <input type="radio" id="two" value="女" v-model="sex">
    <label for="one">女</label>
    <p>{{sex}}</p>
   </div>
    <script>
        var app=new Vue({
        el:'#app',
        data:{
            sex:'男'
        }
    })
    </script>

v-bind 指令


1、直接绑定class样式

<div :class="className">1、绑定classA</div>

2、绑定classA并进行判断,在isOK为true时显示样式,在isOk为false时不显示样式。

<div :class="{classA:isOk}">2、绑定class中的判断</div>

3、绑定class中的数组

<div :class="[classA,classB]">3、绑定class中的数组</div>

4、绑定class中使用三元表达式判断

<div :class="isOk?classA:classB">4、绑定class中的三元表达式判断</div>

5、绑定style

<div :style="{color:red,fontSize:font}">5、绑定style</div>

6、用对象绑定style样式

<div :style="styleObject">6、用对象绑定style样式</div>
var app=new Vue({
   el:'#app',
   data:{
       styleObject:{
           fontSize:'24px',
           color:'green'
            }
        }
})

其他内部指令(v-pre & v-cloak)

在模板中跳过vue的编译,直接输出原始值。就是在标签中加入v-pre就不会输出vue中的data值了。

{{message}}
这时并不会输出我们的message值,而是直接在网页中显示{{message}}

使用 v-cloak 防止页面加载时出现 vuejs 的变量名

<!-- 直接在css中添加 -->
[v-cloak] {
  display: none;
}

CSS3 attribute

CSS3淡入淡出效果

@-webkit-keyframes fadeInOut {
      0% {
        opacity: 1;
      }

      25% {
        opacity: 0;
      }

      50% {
        opacity: 0;
      }

      75% {
        opacity: 1;
      }
    }
    .anim_fade_image {
      position: absolute;
      -webkit-animation-name: fadeInOut;
      -webkit-animation-timing-function: ease-in-out;
      -webkit-animation-iteration-count: infinite;
      -webkit-animation-duration: 5s;
      -webkit-animation-direction: alternate;
    }
    <div class="anim_fade_image">hello world</div>

如果文本长度超过一行,它将被截断并以省略号结束。

  <p class="truncate-text">If I exceed one line's width, I will be truncated.</p>
  <style>
    .truncate-text {
      overflow: hidden;
      white-space: nowrap;
      text-overflow: ellipsis;
      width: 200px;
    }
    </style>

伪类

&:after {
      content: '';
      background: inherit;
      filter: blur(0.4rem);
      opacity: 0.7;
      z-index: -1;
    }

css中filter属性

1  grayscale灰度

2  sepia褐色(有种复古的旧照片感觉)

3  saturate饱和度

4  hue-rotate色相旋转

5  invert反色

6  opacity透明度

7  brightness亮度

8  contrast对比度

9  blur模糊

0  drop-shadow阴影

垂直对齐

.main{
    position: relative;
    top: 50%;
    -webkit-transform: translateY(-50%);
    -o-transform: translateY(-50%);
    transform: translateY(-50%);
}

基于文件格式使用不同的样式

a[href^="http://"]{
    padding-right: 20px;
    background: url(external.gif) no-repeat center right;
}
/* emails */
a[href^="mailto:"]{
    padding-right: 20px;
    background: url(email.png) no-repeat center right;
}

/* pdfs */
a[href$=".pdf"]{
    padding-right: 20px;
    background: url(pdf.png) no-repeat center right;
}

背景渐变动画

button {
    background-image: linear-gradient(#5187c4, #1c2f45);
    background-size: auto 200%;
    background-position: 0 100%;
    transition: background-position 0.5s;
}    
button:hover {
    background-position: 0 0;
}

CSS:表格列宽自适用

//给td元素添加white-space: nowrap;能让文本正确的换行
td {
    white-space: nowrap;
}

盒子阴影

.box-shadow {
    background-color: #FF8020;
    width: 160px;
    height: 90px;
    margin-top: -45px;
    margin-left: -80px;
    position: absolute;
    top: 50%;
    left: 50%;
}
.box-shadow:after {
    content: "";
    width: 150px;
    height: 1px;
    margin-top: 88px;
    margin-left: -75px;
    display: block;
    position: absolute;
    left: 50%;
    z-index: -1;
    -webkit-box-shadow: 0px 0px 8px 2px #000000;
       -moz-box-shadow: 0px 0px 8px 2px #000000;
            box-shadow: 0px 0px 8px 2px #000000;
}

包裹长文本

pre {
    white-space: pre-line;
    word-wrap: break-word;
}

制造模糊文本

.blurry-text {
   color: transparent;
   text-shadow: 0 0 5px rgba(0,0,0,0.5);
}

用CSS动画实现省略号动画

.loading:after {
    overflow: hidden;
    display: inline-block;
    vertical-align: bottom;
    animation: ellipsis 2s infinite;
    content: "\2026"; /* ascii code for the ellipsis character */
}
@keyframes ellipsis {
    from {
        width: 2px;
    }
    to {
        width: 15px;
    }
}

样式重置

html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 100%;
  font: inherit;
  vertical-align: baseline;
  outline: none;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}
html { height: 101%; }
body { font-size: 62.5%; line-height: 1; font-family: Arial, Tahoma, sans-serif; }
article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { display: block; }
ol, ul { list-style: none; }
blockquote, q { quotes: none; }
blockquote:before, blockquote:after, q:before, q:after { content: ''; content: none; }
strong { font-weight: bold; } 
table { border-collapse: collapse; border-spacing: 0; }
img { border: 0; max-width: 100%; }
p { font-size: 1.2em; line-height: 1.0em; color: #333; }

/* reset */
html,body,h1,h2,h3,h4,h5,h6,div,dl,dt,dd,ul,ol,li,p,blockquote,pre,hr,figure,table,caption,th,td,form,fieldset,legend,input,button,textarea,menu{margin:0;padding:0;}
header,footer,section,article,aside,nav,hgroup,address,figure,figcaption,menu,details{display:block;}
table{border-collapse:collapse;border-spacing:0;}
caption,th{text-align:left;font-weight:normal;}
html,body,fieldset,img,iframe,abbr{border:0;}
i,cite,em,var,address,dfn{font-style:normal;}
[hidefocus],summary{outline:0;}
li{list-style:none;}
h1,h2,h3,h4,h5,h6,small{font-size:100%;}
sup,sub{font-size:83%;}
pre,code,kbd,samp{font-family:inherit;}
q:before,q:after{content:none;}
textarea{overflow:auto;resize:none;}
label,summary{cursor:default;}
a,button{cursor:pointer;}
h1,h2,h3,h4,h5,h6,em,strong,b{font-weight:bold;}
del,ins,u,s,a,a:hover{text-decoration:none;}
body,textarea,input,button,select,keygen,legend{font:12px/1.14 arial,\5b8b\4f53;color:#333;outline:0;}
body{background:#fff;}
a,a:hover{color:#333;}

典型的CSS清除浮动

.clearfix:after {
 content: "."; 
 display: block;
 clear: both;
 visibility: hidden;
 line-height: 0;
 height: 0; 
}
.clearfix { display: inline-block; }
html[xmlns] .clearfix { display: block; }
* html .clearfix { height: 1%; }

新版清除浮动

.clearfix:before, .container:after { content: ""; display: table; }
.clearfix:after { clear: both; }
/* IE 6/7 */
.clearfix { zoom: 1; }

跨浏览器的透明

.transparent {
    filter: alpha(opacity=50); /* internet explorer */
    -khtml-opacity: 0.5;      /* khtml, old safari */
    -moz-opacity: 0.5;       /* mozilla, netscape */
    opacity: 0.5;           /* fx, safari, opera */
}

通用媒体查询

/* Smartphones (portrait and landscape) ----------- */
@media only screen and (min-device-width : 320px) and (max-device-width : 480px) {
  /* Styles */
}
/* Smartphones (landscape) ----------- */
@media only screen and (min-width : 321px) {
  /* Styles */
}
/* Smartphones (portrait) ----------- */
@media only screen and (max-width : 320px) {
  /* Styles */
}
/* iPads (portrait and landscape) ----------- */
@media only screen and (min-device-width : 768px) and (max-device-width : 1024px) {
  /* Styles */
}
/* iPads (landscape) ----------- */
@media only screen and (min-device-width : 768px) and (max-device-width : 1024px) and (orientation : landscape) {
  /* Styles */
}
/* iPads (portrait) ----------- */
@media only screen and (min-device-width : 768px) and (max-device-width : 1024px) and (orientation : portrait) {
  /* Styles */
}
/* Desktops and laptops ----------- */
@media only screen and (min-width : 1224px) {
  /* Styles */
}
/* Large screens ----------- */
@media only screen and (min-width : 1824px) {
  /* Styles */
}
/* iPhone 4 ----------- */
@media only screen and (-webkit-min-device-pixel-ratio:1.5), only screen and (min-device-pixel-ratio:1.5) {
  /* Styles */
}

锚链接伪类

a:link { color: blue; }
a:visited { color: purple; }
a:hover { color: red; }
a:active { color: yellow; }

CSS3:全屏背景

html { 
    background: url('images/bg.jpg') no-repeat center center fixed; 
    -webkit-background-size: cover;
    -moz-background-size: cover;
    -o-background-size: cover;
    background-size: cover;
}

内容垂直居中

.container {
    min-height: 6.5em;
    display: table-cell;
    vertical-align: middle;
} 

CSS3渐变模板

#colorbox {
    background: #629721;
    background-image: -webkit-gradient(linear, left top, left bottom, from(#83b842), to(#629721));
    background-image: -webkit-linear-gradient(top, #83b842, #629721);
    background-image: -moz-linear-gradient(top, #83b842, #629721);
    background-image: -ms-linear-gradient(top, #83b842, #629721);
    background-image: -o-linear-gradient(top, #83b842, #629721);
    background-image: linear-gradient(top, #83b842, #629721);
}

CSS3 斑马线

tbody tr:nth-child(odd) {
    background-color: #ccc;
}

三角形列表项目符号

ul {
    margin: 0.75em 0;
    padding: 0 1em;
    list-style: none;
}
li:before { 
    content: "";
    border-color: transparent #111;
    border-style: solid;
    border-width: 0.35em 0 0.35em 0.45em;
    display: block;
    height: 0;
    width: 0;
    left: -1em;
    top: 0.9em;
    position: relative;
}

CSS3 列文本

#columns-3 {
    text-align: justify;
    -moz-column-count: 3;
    -moz-column-gap: 12px;
    -moz-column-rule: 1px solid #c4c8cc;
    -webkit-column-count: 3;
    -webkit-column-gap: 12px;
    -webkit-column-rule: 1px solid #c4c8cc;
}

跨浏览器设置最小高度

#container {
    min-height: 550px;
    height: auto !important;
    height: 550px;
}

CSS3 鲜艳的输入

input[type=text], textarea {
    -webkit-transition: all 0.30s ease-in-out;
    -moz-transition: all 0.30s ease-in-out;
    -ms-transition: all 0.30s ease-in-out;
    -o-transition: all 0.30s ease-in-out;
    outline: none;
    padding: 3px 0px 3px 3px;
    margin: 5px 1px 3px 0px;
    border: 1px solid #ddd;
}
input[type=text]:focus, textarea:focus {
    box-shadow: 0 0 5px rgba(81, 203, 238, 1);
    padding: 3px 0px 3px 3px;
    margin: 5px 1px 3px 0px;
    border: 1px solid rgba(81, 203, 238, 1);
}

强制换行

pre {
    white-space: pre-wrap;       /* css-3 */
    white-space: -moz-pre-wrap;  /* Mozilla, since 1999 */
    white-space: -pre-wrap;      /* Opera 4-6 */
    white-space: -o-pre-wrap;    /* Opera 7 */
    word-wrap: break-word;       /* Internet Explorer 5.5+ */
}

在可点击的项目上强制手型

a[href], input[type='submit'], input[type='image'], label[for], select, button, .pointer {
    cursor: pointer;
}

CSS3对话气泡

.chat-bubble {
    background-color: #ededed;
    border: 2px solid #666;
    font-size: 35px;
    line-height: 1.3em;
    margin: 10px auto;
    padding: 10px;
    position: relative;
    text-align: center;
    width: 300px;
    -moz-border-radius: 20px;
    -webkit-border-radius: 20px;
    -moz-box-shadow: 0 0 5px #888;
    -webkit-box-shadow: 0 0 5px #888;
    font-family: 'Bangers', arial, serif; 
}
.chat-bubble-arrow-border {
    border-color: #666 transparent transparent transparent;
    border-style: solid;
    border-width: 20px;
    height: 0;
    width: 0;
    position: absolute;
    bottom: -42px;
    left: 30px;
}
.chat-bubble-arrow {
    border-color: #ededed transparent transparent transparent;
    border-style: solid;
    border-width: 20px;
    height: 0;
    width: 0;
    position: absolute;
    bottom: -39px;
    left: 30px;
}
 <div class="chat-bubble">
      请查看以下状况:
      1.是否有空格
      2.字符长度
      <span class="chat-bubble-arrow-border chat-bubble-arrow"></span>
    </div>

H1-H5默认样式

h1,h2,h3,h4,h5{
    color: #005a9c;
}
h1{
    font-size: 2.6em;
    line-height: 2.45em;
}
h2{
    font-size: 2.1em;
    line-height: 1.9em;
}
h3{
    font-size: 1.8em;
    line-height: 1.65em;
}
h4{
    font-size: 1.65em;
    line-height: 1.4em;
}
h5{
    font-size: 1.4em;
    line-height: 1.25em;
}

CSS悬浮提示文本

a { 
    border-bottom:1px solid #bbb;
    color:#666;
    display:inline-block;
    position:relative;
    text-decoration:none;
}
a:hover,
a:focus {
    color:#36c;
}
a:active {
    top:1px; 
}
/* Tooltip styling */
a[data-tooltip]:after {
    border-top: 8px solid #222;
    border-top: 8px solid hsla(0,0%,0%,.85);
    border-left: 8px solid transparent;
    border-right: 8px solid transparent;
    content: "";
    display: none;
    height: 0;
    width: 0;
    left: 25%;
    position: absolute;
}
a[data-tooltip]:before {
    background: #222;
    background: hsla(0,0%,0%,.85);
    color: #f6f6f6;
    content: attr(data-tooltip);
    display: none;
    font-family: sans-serif;
    font-size: 14px;
    height: 32px;
    left: 0;
    line-height: 32px;
    padding: 0 15px;
    position: absolute;
    text-shadow: 0 1px 1px hsla(0,0%,0%,1);
    white-space: nowrap;
    -webkit-border-radius: 5px;
    -moz-border-radius: 5px;
    -o-border-radius: 5px;
    border-radius: 5px;
}
a[data-tooltip]:hover:after {
    display: block;
    top: -9px;
}
a[data-tooltip]:hover:before {
    display: block;
    top: -41px;
}
a[data-tooltip]:active:after {
    top: -10px;
}
a[data-tooltip]:active:before {
    top: -42px;
}

<a data-tooltip href="">百度搜索</a>

深灰色的圆形按钮

.graybtn {
    -moz-box-shadow:inset 0px 1px 0px 0px #ffffff;
    -webkit-box-shadow:inset 0px 1px 0px 0px #ffffff;
    box-shadow:inset 0px 1px 0px 0px #ffffff;
    background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #ffffff), color-stop(1, #d1d1d1) );
    background:-moz-linear-gradient( center top, #ffffff 5%, #d1d1d1 100% );
    filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#d1d1d1');
    background-color:#ffffff;
    -moz-border-radius:6px;
    -webkit-border-radius:6px;
    border-radius:6px;
    border:1px solid #dcdcdc;
    display:inline-block;
    color:#777777;
    font-family:arial;
    font-size:15px;
    font-weight:bold;
    padding:6px 24px;
    text-decoration:none;
    text-shadow:1px 1px 0px #ffffff;
}
.graybtn:hover {
    background:-webkit-gradient( linear, left top, left bottom, color-stop(0.05, #d1d1d1), color-stop(1, #ffffff) );
    background:-moz-linear-gradient( center top, #d1d1d1 5%, #ffffff 100% );
    filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#d1d1d1', endColorstr='#ffffff');
    background-color:#d1d1d1;
}
.graybtn:active {
    position:relative;
    top:1px;
}

在可打印的网页中显示URLs

@media print   {  
  a:after {  
    content: " [" attr(href) "] ";  
  }  
}

CSS3 圆点图案

body {
    background: radial-gradient(circle, white 10%, transparent 10%),
    radial-gradient(circle, white 10%, black 10%) 50px 50px;
    background-size: 100px 100px;
}

CSS font属性缩写

p {
  font: italic small-caps bold 1.2em/1.0em Arial, Tahoma, Helvetica;
}

论文页面的卷曲效果

ul.box {
    position: relative;
    z-index: 1; /* prevent shadows falling behind containers with backgrounds */
    overflow: hidden;
    list-style: none;
    margin: 0;
    padding: 0; 
}
ul.box li {
    position: relative;
    float: left;
    width: 250px;
    height: 150px;
    padding: 0;
    border: 1px solid #efefef;
    margin: 0 30px 30px 0;
    background: #fff;
    -webkit-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.27), 0 0 40px rgba(0, 0, 0, 0.06) inset;
    -moz-box-shadow: 0 1px 4px rgba(0, 0, 0, 0.27), 0 0 40px rgba(0, 0, 0, 0.06) inset; 
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.27), 0 0 40px rgba(0, 0, 0, 0.06) inset; 
}
ul.box li:before,
ul.box li:after {
    content: '';
    z-index: -1;
    position: absolute;
    left: 10px;
    bottom: 10px;
    width: 70%;
    max-width: 300px; /* avoid rotation causing ugly appearance at large container widths */
    max-height: 100px;
    height: 55%;
    -webkit-box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
    -moz-box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
    box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3);
    -webkit-transform: skew(-15deg) rotate(-6deg);
    -moz-transform: skew(-15deg) rotate(-6deg);
    -ms-transform: skew(-15deg) rotate(-6deg);
    -o-transform: skew(-15deg) rotate(-6deg);
    transform: skew(-15deg) rotate(-6deg); 
}
ul.box li:after {
    left: auto;
    right: 10px;
    -webkit-transform: skew(15deg) rotate(6deg);
    -moz-transform: skew(15deg) rotate(6deg);
    -ms-transform: skew(15deg) rotate(6deg);
    -o-transform: skew(15deg) rotate(6deg);
    transform: skew(15deg) rotate(6deg); 
}

鲜艳的锚链接

a {
    color: #00e;
}
a:visited {
    color: #551a8b;
}
a:hover {
    color: #06e;
}
a:focus {
    outline: thin dotted;
}
a:hover, a:active {
    outline: 0;
}
a, a:visited, a:active {
    text-decoration: none;
    color: #fff;
    -webkit-transition: all .3s ease-in-out;
}
a:hover, .glow {
    color: #ff0;
    text-shadow: 0 0 10px #ff0;
}

禁用移动Webkit的选择高亮

body {
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    -khtml-user-select: none;
    -moz-user-select: none;
    -ms-user-select: none;
    user-select: none;
}

css3实现头像变灰

-webkit-filter: grayscale(100%);  
-webkit-filter: grayscale(1);  
filter: grayscale(100%);  
filter: gray;

图片与文字在同意div中中间对齐

<div class="image-text">
    <img src="xxxx"/>
    <p>文字<p/>
</div>
.image-text {
    display:inline-block;
    vertical-align:middle;
}

实现水平和垂直翻转

transform: scale(-1, 1);//水平翻转
transform: scale(1, -1);//垂直翻转

三角符号绘制
···
.icon-arrow-bottom {
width: 0;
height: 0;
border: 100px solid #000;
border-color: #000 transparent transparent transparent;
}
.icon-arrow-top {
width: 0;
height: 0;
border: 100px solid #000;
border-color: transparent transparent #000 transparent;
}
···

Vue Overall situation API

Vue.directive 自定义指令

代码说明:

<div id="app">
        <div v-jili="color" id="demo">
            {{num}}
        </div>
        <div>
             <button @click="add">Add</button>
        </div>
    </div>
    <script>
        Vue.directive('jili',function(el,binding,vnode){ 
            console.log(el,binding,vnode);   //el  当前元素    binding 包含指令的很多信息。
            el.style='color:'+binding.value;
        });
        var app=new Vue({
            el:'#app',
            data:{
                num:10,
                color:'green'
            },
            methods:{
                add:function(){
                    this.num++;
                }
            }
        })
    </script>

自定义指令的生命周期

1.bind 被绑定
2.inserted 绑定到节点
3.update 组件更新
4.componentUpdated 组件更新完成
5.unbind 解绑

Vue.extend构造器

扩展实例构造器,意为当有多个地方使用同一个标签路径,我们在实例上封装一个自动调用的方法,方法,并挂载到自定义元素上

var authorExtend = Vue.extend({
    template:"<p><a :href='authorUrl'>{{authorName}}</a></p>",
    data:function(){
    return{
          authorName:'度娘',
          authorUrl:'http://www.baidu.com'
          }
    }
});

//new authorExtend().$mount('元素')

Vue.set全局操作

Vue.set 的作用就是在构造器外部操作构造器内部的数据、属性或者方法。

Vue.set存在意义

由于Javascript的限制,Vue不能自动检测以下变动的数组。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script type="text/javascript" src="../assets/js/vue.js"></script>
    <title>Vue.set 全局操作</title>
</head>
<body>
    <h1>Vue.set 全局操作</h1>
    <hr>
    <div id="app">
        <ul>
            <li v-for=" aa in arr">{{aa}}</li>
        </ul>
    </div>
    <button onclick="add()">外部添加</button>
    <script type="text/javascript">
        function add(){
            console.log("我已经执行了");
           app.arr[1]='ddd';          //不能变动
           //Vue.set(app.arr,1,'ddd');
        }
        var outData={
            arr:['aaa','bbb','ccc']
        };
        var app=new Vue({
            el:'#app',
            data:outData
        })
    </script>
</body>
</html>

print transfer slip

打印交接单

preview(1)
function preview(oper){
			if (oper < 10){
				bdhtml=window.document.body.innerHTML;//获取当前页的html代码
				sprnstr="<!--startprint"+oper+"-->";//设置打印开始区域
				eprnstr="<!--endprint"+oper+"-->";//设置打印结束区域
				prnhtml=bdhtml.substring(bdhtml.indexOf(sprnstr)+18); //从开始代码向后取html
				prnhtml=prnhtml.substring(0,prnhtml.indexOf(eprnstr));//从结束代码向前取html
				window.document.body.innerHTML=prnhtml;
				window.print();
				window.document.body.innerHTML=bdhtml;
			} else {
				window.print();
			}
		}

package method

/**

//data数据
let arr = [
  [
    ["1-7", "2-6"], "4-6", [
      ["2-0", "1-4"],
      ["3-9"], "4-5"
    ]
  ]
];
//递归实现
function flat(arr) {
  const result = [];
  function _flat(arr) {
    arr.forEach(element => {
      if (Array.isArray(element)) {
        _flat(element);
      } else {
        result.push(element);
      }
    })
  }
  _flat(arr)
  return result;
}
console.log(flat(arr))

/**

    <input type="text" name="" id="demo" onkeyup="clearNoNum(this)"/>
    //数字输入匹配
    function clearNoNum(obj) {
      obj.value = obj.value.replace(/[^\d.]/g, ""); //清除“数字”和“.”以外的字符
      obj.value = obj.value.replace(/\.{2,}/g, "."); //只保留第一个. 清除多余的
      obj.value = obj.value.replace(".", "$#$").replace(/\./g, "").replace("$#$", ".");
      obj.value = obj.value.replace(/^\./g, ""); //验证第一个字符是数字而不是.
      obj.value = obj.value.replace(/^(\-)*(\d+)\.(\d\d).*$/, "$1$2.$3"); //只能输入两个小数
      if (obj.value.indexOf(".") < 0 && obj.value != "") {
        //以上已经过滤,此处控制的是如果没有小数点,首位不能为类似于 01、02的金额
        obj.value = parseFloat(obj.value);
      }
    }
    //空格处理
    function clearNoNum(obj) {
      obj.value = obj.value.replace(/\s/g, ""); 
    }
/**
 * @author
 * @description:深拷贝
 **/
//递归
function deepClone(obj) {
  let result = Array.isArray(obj) ? [] : {};
  if (obj && typeof obj === 'object') {
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        if (obj[key] && typeof obj[key] === 'object') {
          result[key] = deepClone(obj[key])
        } else {
          result[key] = obj[key]
        }
      }
    }
  }
  return result;
}

//1.JSON.parse与JSON.stringify
/2.通过jQuery的extend方法实现深拷贝
   var array = [1,2,3,4];
   var newArray = $.extend(true,[],array);
//3.Object.assign()拷贝
//当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝

/**
 * @author
 * @description:bind封装
 **/
Function.prototype.bind2 = function (context) {
  var self = this;
  return function () {
    self.apply(context);
  }
}
/**
 * @author
 * @description:promise
 **/
class Promise {
  callbacks = [];
  failbacks = [];
  constructor(fn) {
    fn(this.resolve.bind(this), this.reject.bind(this));
  }
  resolve(res) {
    if (this.callbacks.length > 0) this.callbacks.shift()(res, this.resolve.bind(this), this.reject.bind(this));
  }
  reject(res) {
    this.callbacks = [];
    if (this.failbacks.length > 0) this.failbacks.shift()(res, this.resolve.bind(this), this.reject.bind(this));
  }
  catch (fn) {
    this.failbacks.push(fn);
  }
  then(fn) {
    this.callbacks.push(fn);
    return this;
  }
}
/**
 * @author
 * @description:new封装
 **/
function create() {
  // 创建一个空的对象
  let obj = new Object()
  // 获得构造函数
  let Con = [].shift.call(arguments)
  // 链接到原型
  obj.__proto__ = Con.prototype
  // 绑定 this,执行构造函数
  let result = Con.apply(obj, arguments)
  // 确保 new 出来的是个对象
  return typeof result === 'object' ? result : obj
}
/**
 * @author
 * @description:extends实现
 **/
//子类  extends  父类
Function.prototype.extends = function(func, options){
  for(var key in func.prototype){
      this.prototype[key] = func.prototype[key];
  }
  for(var name in options){
      this.prototype[name] = options[name];
  }
}
/**
 * @author
 * @description:高级递归排序
 **/
function quickSort(arr) {
    if(arr.length <= 1) {
        return arr;  //递归出口
    }
    var left = [],
        right = [],
        current = arr.splice(0,1); 
    for(let i = 0; i < arr.length; i++) {
        if(arr[i] < current) {
            left.push(arr[i])  //放在左边
        } else {
            right.push(arr[i]) //放在右边
        }
    }
    return quickSort(left).concat(current,quickSort(right));
}

WEB fuzzy search

前言
技术栈:jQuery+bootstrap
语义::contains 选择器选取包含指定字符串的元素。 语法:$(":contains(text)")

HTML

<div role="group" style="display:inline">
    <input type="text" id="belongcompanyid" placeholder="search name" autocomplete="off">
    <div role="form" style="overflow-y:hidden;">
      <div id="belongcompanyList" style="max-height: 297px;overflow-y: auto;overflow-x: hidden;display: none;">
      </div>
    </div>
  </div>

js

systmeCustomer();
function systmeCustomer() {
  $.ajax({
    type: "get",
    url: "./index.json",
    data: {},
    async: false,
    dataType: "json",
    success: function(data) {
      console.log(data);
      if (data.result_code == "0") {
        $("#belongcompanyList").empty();
        var datalist = data.data_list;
        var auditHtml = "";
        for (var i = 0; i < 26; i++) {
          var ch = String.fromCharCode(65 + i);
          var auditHtml1 = "";
          var auditHtml2 = "";
          auditHtml1 +=
            '<div class="row">' +
            '<div class="col-lg-2 col-md-2 col-sm-2 col-xs-2" style="text-align: right;float:left;">' +
            ch +
            "</div>" +
            '<div class="col-lg-10 col-md-10 col-sm-12 col-xs-12 PList" style="border-left:1px solid #fff">';
          for (var j = 0; j < datalist.length; j++) {
            if (datalist[j].py.toUpperCase() == ch) {
              auditHtml2 +=
                "<p  belong_company_id=" +
                datalist[j].company_id +
                ' class="billIdClick">' +
                datalist[j].company_name +
                "</p>";
            }
          }
          if (auditHtml2 == "") {
            auditHtml1 = "";
          } else {
            auditHtml1 += auditHtml2;
          }
          auditHtml += auditHtml1;
          auditHtml += "</div>" + "</div>";
        }
        $("#belongcompanyList").append(auditHtml);
      } else {
        alert(data.result_msg);
      }
    }
  });
}
//模糊搜索
$("#belongcompanyid").blur(function() {
  var thisval = $(this).val();
  $("#belongcompanyList>div").show().children("div p").show();
  $("#belongcompanyList p").show();
    if (thisval.length > 0) {
      $('#belongcompanyList').css('display','block');
      $("#belongcompanyList>div>div>p").hide().filter(":contains('" + thisval + "')").show();
      var p_list = $("#belongcompanyList>div>div.PList");
      for (var i = 0; i < p_list.length; i++) {
        if ($(p_list[i]).children("p:visible").length == "0") {
          $(p_list[i]).parent("div").hide();
        }
      }
    }
  }).keyup(function() {
    $(this).triggerHandler("blur");
  }).focus(function() {
    $(this).triggerHandler("blur");
  }).change(function() {
    $(this).triggerHandler("blur");
  });
$("#belongcompanyList").on("click", ".billIdClick", function() {
  var custom_name = $(this).html();
  $("#belongcompanyid").val(custom_name);
  $('#belongcompanyList').hide();
  $(".custom-search").removeClass("open");
});
// json数据
{"result_msg":"成功","data_list":[{"company_id":1,"crm_company_id":177857,"company_name":"华为技术有限公司","py":"H"},{"company_id":3,"crm_company_id":152,"company_name":"北京市北京饭店","py":"B"},{"company_id":4,"crm_company_id":185139,"company_name":"商路延","py":"S"},{"company_id":5,"crm_company_id":18552,"company_name":"首约","py":"S"},{"company_id":1251,"crm_company_id":337837,"company_name":"河北马利食品有限公司","py":"H"},{"company_id":1252,"crm_company_id":300148,"company_name":"苏州绿城玫瑰园房地产开发有限公司","py":"S"},{"company_id":1253,"crm_company_id":300965,"company_name":"常州安必克阀门有限公司","py":"C"},{"company_id":1254,"crm_company_id":301268,"company_name":"北京京环华胜信息科技有限公司","py":"B"},{"company_id":1256,"crm_company_id":301065,"company_name":"隆基绿能科技股份有限公司","py":"L"},{"company_id":1527,"crm_company_id":311033,"company_name":"**科协青少年科技中心","py":"Z"},{"company_id":1528,"crm_company_id":311195,"company_name":"友利银行(**)有限公司上海吴中路支行bc","py":"Y"},{"company_id":1529,"crm_company_id":3112844,"company_name":"湖北视觉时代文化传媒有限公司","py":"H"}],"result_code":0}

javascript常用方法

javascript常用方法

数组常用方法

  • concat 拼接数组
  • foreach 循环数组
  • includes 判断一个数组是否包含一个指定的值
  • pop 删除数组的最后一个元素返回删除的元素
  • push 向末尾添加一个元素
  • reduce 将数组元素计算为一个值
  • reverse 反转数组
  • shift 删除第一个元素并返回数组的第一个元素
  • unshift 删除最后元素并返回数组的最后元素
  • slice 选取数组的一部分,返回一个新数组 *
new Array(1,2,3,4,5).slice(1,5)  => 2,3,4,5 
  • map 处理数组的每个元素,返回处理后的数组
// 反转数组 类似reverse
var arr = new Array(1,2,3,4,5,6)
[...arr].map(arr.pop,arr)
  • some 查看数组中是否有元素符合条件
new Array(1,2,3,4,5).some(item => {
	return item > 4
})
// true
  • sort 排序(单独只对个位数有用)
//由小到大
new Array(22,555,444,1111,478).sort((a, b) => {
	return a - b
})
  • splice 从数组中添加或删除元素
// splice与slice区别
array.slice(start,end) 1.可以从数组中提取指定元素  2.该方法不会改变元素数组,而是将截取的元素封装到一个新数组返回 3.类似于substring
var arr = [3,4,5,6,7]
arr.slice(1,-2)  => 4,5   -2代指倒数第二个,从0算起

array.splice(start[, deleteCount[, item1[, item2[, ...]]]])
// 第一参数截取初始位置
// 第二参数截取元素个数
// 在删除位置参数的元素
1.可用于删除数组 2.影响原数组,返回删除的元素	
var arr = [3,4,5,6]
arr.splice(0,1,34,56)
console.log(arr) //=> 34,56,4,5,6 

arr.splice(2,0,55)
console.log(arr) //=> 3,4,55,5,6

String常用方法

  • String.prototype.charAt() 返回特定位置的字符
'cat'.charAt(1) //=>a
  • charCodeAt() 返回表示给定索引的字符的Unicode的值
'cat'.charCodeAt(1) //=>97
  • concat
  • includes 是否包含
'cat'.includes('t')  //=> true
  • indexOf/lastIndexOf 从字符串对象中返回首个/最后被发现的给定值的索引值,如果没有找到则返回-1。
'catccc'.indexOf('c') //=> 0
'cataaa'.indexOf('b') //=>-1
'cataaa'.lastIndexOf('a') //=>5
  • repeat 返回指定重复次数的由元素组成的字符串对象
'a'.repeat(4) //=>'aaaa'
  • toLowerCase/toUpperCase
'AA'.toLowerCase() //=>'aa'
'aa'.toUpperCase() //=>'AA'
  • replace 替换
'ccbb aa'.replace(/aa/,'bb') //=> 'ccbb bb'
  • toString null与undefinded不能转换

Object常用方法

  • Object.assign(target,source) 通过复制一个或多个对象来创建一个新的对象 不兼容IE,实行的是浅拷贝
const source1 = {a: 1, b: 2}
const source2 = {b: 3, c: 2}
Object.assign(source1, source2) //=> {a: 1, b: 3, c: 2}
//特殊情况
Object.assign({a: 1}, undefined) === {a: 1}  //=> true null也一致
Object.assign([1], [4]) //=>[4]
//浅拷贝
const obj1 = {a: {b: 1}};
const obj2 = Object.assign({}, obj1);
obj1.a.b = 2
obj2.a.b //=> 2 
  • Object.create() 使用指定的原型对象和属性创建一个新对象。
//创建一个可写的,可枚举的,可配置的属性p
//第一参数原型对象,第二参数本身实例
const obj2 = Object.create({}, {
  'p': {
    value: 2,       // 属性值
    writable: true,     //  是否可以重写值
    enumerable: true,   //是否可枚举
    configurable: true  //是否可以修改以上几项配置
  },
  'a': {
	value: 3,
	writable: true, 
    enumerable: true,
    configurable: true
  }
});
obj2 //=> {p: 2, a: 3}
// Object.defineProperty(obj, prop, descriptor)
/**
 *参数obj表示的是需要定义属性的那个对象
 *参数prop表示需要被定义或者修改的属性名
 *参数descriptor就是我们定义的那个属性prop的描述
 * 
 * 要求就是你要给dreamapple添加一个fullName属性
 * dreamapple的firstName或者lastName发生变化的时候,fullName也要随之变化;而且当我们设置了fullName的值的时候,
 * 那么相应的它的firstName和lastName也随之发生变化; 那么我们应该怎么做呢?
 **/
var dream = {
    firstName: 'dream',
    lastName: 'apple'
}

Object.defineProperty(dream,'fullName',{
    enumerable: true, //是否可枚举
    get () {
        return this.firstName +' '+ this.lastName
    },
    set (fullName) {
        const name =  fullName.trim().split(' ')
        this.firstName = name[0]
        this.lastName = name[1]
    }
})
dream.firstName = 'lala'
dream.lastName = 'haha'
console.log(dream.fullName)

// dream.fullName = 'apple aaaaaadd'
// console.log(dream.firstName,dream.lastName)
  • Object.entries() 返回给定对象自身可枚举属性的 [key, value] 数组
//类似for..in  不兼容  
const obj = { foo: 'bar', baz: 42 }
Object.entries(obj) //=>[ ["foo", "bar"], ["baz", 42] ]
  • Object.is(val1,val2) 比较两个值是否相同。所有 NaN 值都相等
Object.is(NaN,NaN)  //=>true
Object.is('1',1)    //=>false
  • Object.keys(obj) 遍历可枚举的属性
let arr = ["a", "b", "c"];
let obj = { foo: "bar", baz: 42 };

Object.keys(arr)        // ['0', '1', '2']
Object.keys(obj)        // ["foo","baz"]
  • Object.values(obj) 遍历可枚举的属性值
let arr = ["a", "b", "c"];
let obj = { foo: "bar", baz: 42 };

Object.keys(arr)        // ['a', 'b', 'c']
Object.keys(obj)        // ["bar","42 "]

Number常用方法

  • isNaN
Number('10a') //=>NaN
isNaN(undefined) //=> true
isNaN(1) //=> false
isNaN == isNaN //=> false
  • parseInt 取整,第二个参数为进制(没写的话默认十进制)
parseInt(2.45678); //2
parseInt(10,8) // 8

  • parseFloat 取浮点数
parseFloat("010.01aa") //=> 10.01
  • toFixed 保留小数位

Math常用方法

  • Math.PI 圆周率数值
  • Math.floor() 向下取整
  • Math.ceil() 向上取整
  • Math.pow() 两个参数;次方
Math.pow(2,3) //8  2的3次方
  • Math.sqrt() 平方根
Math.sqrt(9) //=> 3
Math.sqrt(-9) //=> NaN
  • Math.abs() 取绝对值
  • Math.max() 取最大值
  • Math.min() 取最小值
  • Math.round() 四舍五入
  • Math.random() 取0-1之间的随机数
// 取0-10之间的随机数
Math.round(Math.random()*10)

Interview summary in segmentfault

实现(0.1).add(0.2).minus(0.3) 及精度处理

Number.MAX_SAFE_DIGITS = Number.MAX_SAFE_INTEGER.toString().length-2        //14
Number.prototype.digits = function(){
  let result = (this.valueOf().toString().split('.')[1] || '').length
	return result > Number.MAX_SAFE_DIGITS ? Number.MAX_SAFE_DIGITS : result
}

Number.prototype.add = function(i=0){
	if (typeof i !== 'number') {
        	throw new Error('请输入正确的数字');
    	}
	const v = this.valueOf();
	const thisDigits = this.digits();
  const iDigits = i.digits();
  console.log(thisDigits,iDigits)
	const baseNum = Math.pow(10, Math.max(thisDigits, iDigits));
	const result = (v * baseNum + i * baseNum) / baseNum;
	if(result>0){ return result > Number.MAX_SAFE_INTEGER ? Number.MAX_SAFE_INTEGER : result }
	else{ return result < Number.MIN_SAFE_INTEGER ? Number.MIN_SAFE_INTEGER : result }
}
Number.prototype.minus = function(i=0){
	if (typeof i !== 'number') {
        	throw new Error('请输入正确的数字');
    	}
	const v = this.valueOf();
	const thisDigits = this.digits();
	const iDigits = i.digits();
	const baseNum = Math.pow(10, Math.max(thisDigits, iDigits));
	const result = (v * baseNum - i * baseNum) / baseNum;
	if(result>0){ return result > Number.MAX_SAFE_INTEGER ? Number.MAX_SAFE_INTEGER : result }
	else{ return result < Number.MIN_SAFE_INTEGER ? Number.MIN_SAFE_INTEGER : result }
}

console.log((0.001).add(0.2))

vue 与 react优缺点对比

  • vue

API设计上简单,语法简单,学习成本低

构建方面不包含路由和ajax功能,使用vuex, vue-router

指令(dom)和组件(视图,数据,逻辑)处理清晰

性能好,容易优化

基于依赖追踪的观察系统,并且异步队列更新

独立触发

v-model 实时渲染

适用于:模板和渲染函数的弹性选择

简单的语法及项目搭建

更快的渲染速度和更小的体积

  • react

利用jsx创建虚拟dom

是一种在内存中描述dom数状态的数据结构

函数式的方法描述视图

使用虚拟dom作为模板

程序片段

不好控制dom

服务端渲染:react的虚拟dom的生成可以在任何支持js的环境生成的,所以可以在node环境生成,直接转为string,然后插入到html文件中输出浏览器便可
适用于:大型应用和更好的可测试性;同时适用于web端和原生app;更大的生态圈

React伟大之处就在于,提出了Virtual Dom这种新颖的思路,并且这种思路衍生出了React Native,有可能会统一Web/Native开发。在性能方面,由于运用了Virtual Dom技术,Reactjs只在调用setState的时候会更新dom,而且还是先更新Virtual Dom,然后和实际Dom比较,最后再更新实际Dom。这个过程比起Angularjs的bind方式来说,一是更新dom的次数少,二是更新dom的内容少,速度肯定快

ReactJS更关注UI的组件化,和数据的单向更新,提出了FLUX架构的新概念,现在React可以直接用Js ES6语法了,然后通过webpack编译成浏览器兼容的ES5,开发效率上有些优势. React Native生成的App不是运行在WebView上,而是系统原生的UI,React通过jsx生成系统原生的UI,iOS和Android的React UI组件还是比较相似的,大量代码可以复用

维护UI的状态,Angular 里面使用的是 $scope,在 React 里面使用的是 this.setState。 而 React 的好处在于,它更简单直观。所有的状态改变都只有唯一一个入口 this.setState(),同构的JavaScript 单页面JS应用程序的最大缺陷在于对搜索引擎的索引有很大限制。React对此有了解决方案。

React可以在服务器上预渲染应用再发送到客户端。它可以从预渲染的静态内容中恢复一样的记录到动态应用程序中。 因为搜索引擎的爬虫程序依赖的是服务端响应而不是JavaScript的执行,预渲染你的应用有助于搜索引擎优化。

  • vue、react共性

虚拟dom实现快速渲染

轻量级响应式组件

服务端渲染易于集成路由工具,打包工具及状态管理工具

回文字符串

//判定方法
function run(input) {
  if (typeof input !== 'string') return false;
  return input.split('').reverse().join('') === input;
}

垂直居中

.wraper {
  position: relative;
  .box {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
  }
}

.wraper {
  .box {
    display: flex;
    justify-content:center;
    align-items: center;
    height: 100px;
  }
}

.wraper {
  display: table;
  .box {
    display: table-cell;
    vertical-align: middle;
  }
}

Reflect(ES6 vue3.0中使用)

Reflect.apply(target, thisArg, args)
Reflect.construct(target, args)
Reflect.get(target, name, receiver)
Reflect.set(target, name, value, receiver)
Reflect.defineProperty(target, name, desc)
Reflect.deleteProperty(target, name)
Reflect.has(target, name)
Reflect.ownKeys(target)
Reflect.isExtensible(target)
Reflect.preventExtensions(target)
Reflect.getOwnPropertyDescriptor(target, name)
Reflect.getPrototypeOf(target)
Reflect.setPrototypeOf(target, prototype)

proxy(ES6 vue3.0中使用,实现数据绑定)

var obj = new Proxy({}, {
  get: function (target, key, receiver) {
    console.log(`proxy get ${key}`)
    return Reflect.get(target, key, receiver)
  },
  set: function (target, key, value, receiver) {
    console.log(`proxy set ${key}`)
    return Reflect.set(target, key, value, receiver)
  }
})

实现Storage,使得该对象为单例,并对localStorage进行封装设置值setItem(key,value)和getItem(key)

var instance = null;
class Storage {
  static getInstance() {
    if (!instance) {
      instance = new Storage();
    }
    return instance;
  }
  setItem = (key, value) => localStorage.setItem(key, value),
  getItem = key => localStorage.getItem(key)
}

react注意点

1.JSX做表达式判断时候,需要强转为boolean类型,如:

render() {
  const b = 0;
  return <div>
    {
      !!b && <div>这是一段文本</div>
    }
  </div>
}
//如果不使用 !!b 进行强转数据类型,会在页面里面输出 0。

2.尽量不要在 componentWillReviceProps 里使用 setState,如果一定要使用,那么需要判断结束条件,不然会出现无限重渲染,导致页面崩溃。
3.给组件添加ref时候,尽量不要使用匿名函数,因为当组件更新的时候,匿名函数会被当做新的prop处理

event loop

首先,js是单线程的,主要的任务是处理用户的交互,而用户的交互无非就是响应DOM的增删改,使用事件队列的形式,一次事件循环只处理一个事件响应,使得脚本执行相对连续,所以有了事件队列,用来储存待执行的事件,那么事件队列的事件从哪里被push进来的呢。那就是另外一个线程叫事件触发线程做的事情了,他的作用主要是在定时触发器线程、异步HTTP请求线程满足特定条件下的回调函数push到事件队列中,等待js引擎空闲的时候去执行,当然js引擎执行过程中有优先级之分,首先js引擎在一次事件循环中,会先执行js线程的主任务,然后会去查找是否有微任务microtask(promise),如果有那就优先执行微任务,如果没有,在去查找宏任务macrotask(setTimeout、setInterval)进行执行。

说说事件流

事件流分为两种,捕获事件流和冒泡事件流。
捕获事件流从根节点开始执行,一直往子节点查找执行,直到查找执行到目标节点。
冒泡事件流从目标节点开始执行,一直往父节点冒泡查找执行,直到查到到根节点。
事件流分为三个阶段,一个是捕获节点,一个是处于目标节点阶段,一个是冒泡阶段。

react 的虚拟dom是怎么实现的

首先说说为什么要使用Virturl DOM,因为操作真实DOM的耗费的性能代价太高,所以react内部使用js实现了一套dom结构,在每次操作在和真实dom之前,使用实现好的diff算法,对虚拟dom进行比较,递归找出有变化的dom节点,然后对其进行更新操作。为了实现虚拟DOM,我们需要把每一种节点类型抽象成对象,每一种节点类型有自己的属性,也就是prop,每次进行diff的时候,react会先比较该节点类型,假如节点类型不一样,那么react会直接删除该节点,然后直接创建新的节点插入到其中,假如节点类型一样,那么会比较prop是否有更新,假如有prop不一样,那么react会判定该节点有更新,那么重渲染该节点,然后在对其子节点进行比较,一层一层往下,直到没有子节点。

请手写实现一个promise

promise

function MyPromise(executor){
  var that = this
  this.status = 'pending' // 当前状态
  this.data = undefined
  this.onResolvedCallback = [] // Promise resolve时的回调函数集,因为在Promise结束之前有可能有多个回调添加到它上面
  this.onRejectedCallback = [] // Promise reject时的回调函数集,因为在Promise结束之前有可能有多个回调添加到它上面

  // 更改状态 => 绑定数据 => 执行回调函数集
  function resolve(value){
    if(that.status === 'pending'){
      that.status = 'resolved'
      that.data = value
      for(var i = 0; i < that.onResolvedCallback.length; ++i){
        that.onResolvedCallback[i](value)
      }
    }
  }

  function reject(reason){
    if(that.status === 'pending'){
      that.status = 'rejected'
      that.data = reason
      for(var i = 0; i < that.onResolvedCallback.length; ++i){
        that.onRejectedCallback[i](reason)
      }
    }
  }

  try{ 
    executor(resolve, reject) // resolve, reject两个函数可以在外部传入的函数(executor)中调用
  } catch(e) { // 考虑到执行过程可能有错
    reject(e)
  }
}

// 标准是没有catch方法的,实现了then,就实现了catch
// then/catch 均要返回一个新的Promise实例

MyPromise.prototype.then = function(onResolved, onRejected){
  var that = this
  var promise2

  // 值穿透
  onResolved = typeof onResolved === 'function' ? onResolved : function(v){ return v }
  onRejected = typeof onRejected === 'function' ? onRejected : function(r){ return r }

  if(that.status === 'resolved'){
    return promise2 = new MyPromise(function(resolve, reject){
      try{
        var x = onResolved(that.data)
        if(x instanceof MyPromise){ // 如果onResolved的返回值是一个Promise对象,直接取它的结果做为promise2的结果
          x.then(resolve, reject)
        }
        resolve(x) // 否则,以它的返回值做为promise2的结果 
      } catch(e) {
        reject(e) // 如果出错,以捕获到的错误做为promise2的结果
      }
    })
  }

  if(that.status === 'rejected'){
    return promise2 = new MyPromise(function(resolve, reject){
      try{
        var x = onRejected(that.data)
        if(x instanceof MyPromise){
          x.then(resolve, reject)
        }
      } catch(e) {
        reject(e)
      }
    })
  }

  if(that.status === 'pending'){
    return promise2 = new MyPromise(function(resolve, reject){
      self.onResolvedCallback.push(function(reason){
        try{
          var x = onResolved(that.data)
          if(x instanceof MyPromise){
            x.then(resolve, reject)
          }
        } catch(e) {
          reject(e)
        }
      })

      self.onRejectedCallback.push(function(value){
        try{
          var x = onRejected(that.data)
          if(x instanceof MyPromise){
            x.then(resolve, reject)
          }
        } catch(e) {
          reject(e)
        }
      })
    })
  }
}

MyPromise.prototype.catch = function(onRejected){
  return this.then(null, onRejected)
}

// 以下是简单的测试样例:
new MyPromise(resolve => resolve(8)).then(value => {
  console.log(value)
})

CSS和JS的位置会影响页面效率,为什么?

css在加载过程中不会影响到DOM树的生成,但是会影响到Render树的生成,进而影响到layout,所以一般来说,style的link标签需要尽量放在head里面,因为在解析DOM树的时候是自上而下的,而css样式又是通过异步加载的,这样的话,解析DOM树下的body节点和加载css样式能尽可能的并行,加快Render树的生成的速度。
js脚本应该放在底部,原因在于js线程与GUI渲染线程是互斥的关系,如果js放在首部,当下载执行js的时候,会影响渲染行程绘制页面,js的作用主要是处理交互,而交互必须得先让页面呈现才能进行,所以为了保证用户体验,尽量让页面先绘制出来。

浏览器的缓存机制

浏览器缓存机制有两种,一种为强缓存,一种为协商缓存。
对于强缓存,浏览器在第一次请求的时候,会直接下载资源,然后缓存在本地,第二次请求的时候,直接使用缓存。
对于协商缓存,第一次请求缓存且保存缓存标识与时间,重复请求向服务器发送缓存标识和最后缓存时间,服务端进行校验,如果失效则使用缓存。
强缓存方案
Exprires:服务端的响应头,第一次请求的时候,告诉客户端,该资源什么时候会过期。Exprires的缺陷是必须保证服务端时间和客户端时间严格同步。
Cache-control:max-age,表示该资源多少时间后过期,解决了客户端和服务端时间必须同步的问题,
协商缓存方案
If-None-Match/ETag:缓存标识,对比缓存时使用它来标识一个缓存,第一次请求的时候,服务端会返回该标识给客户端,客户端在第二次请求的时候会带上该标识与服务端进行对比并返回If-None-Match标识是否表示匹配。
Last-modified/If-Modified-Since:第一次请求的时候服务端返回Last-modified表明请求的资源上次的修改时间,第二次请求的时候客户端带上请求头If-Modified-Since,表示资源上次的修改时间,服务端拿到这两个字段进行对比。

svg和canvas各自的优缺点

共同点:都是有效的图形工具,对于数据较小的情况下,都很又高的性能,它们都使用 JavaScript 和 HTML;它们都遵守万维网联合会 (W3C) 标准。
svg优点:
矢量图,不依赖于像素,无限放大后不会失真。
以dom的形式表示,事件绑定由浏览器直接分发到节点上。
svg缺点:
dom形式,涉及到动画时候需要更新dom,性能较低。
canvas优点:
定制型更强,可以绘制绘制自己想要的东西。
非dom结构形式,用JavaScript进行绘制,涉及到动画性能较高。
canvas缺点:
事件分发由canvas处理,绘制的内容的事件需要自己做处理。
依赖于像素,无法高效保真,画布较大时候性能较低

浏览器输入网址到页面打开发生了什么

1、输入地址
2、浏览器查找域名的 IP 地址(域名解析)
3、浏览器向 web 服务器发送一个 HTTP 请求
4、服务器的永久重定向响应
5、浏览器跟踪重定向地址
6、服务器处理请求
7、服务器返回一个 HTTP 响应
8、浏览器显示 HTML
9、浏览器发送请求获取嵌入在 HTML 中的资源(如CSS、JS、图片、音频、视频等)

头条题目描述:

 const obj = {
    selector: {
      to: {
        toutiao: "FE Coder"
      }
    },
    target: [1, 2, {
      name: 'byted'
    }]
  };
get(obj, 'selector.to.toutiao', 'target[0]', 'target[2].name')
//结果:FE Coder   1    byted

思路一:

  function get(data, ...args) {
    const reg = /\[[0-9]+\]/gi;
    return args.map((item) => {
      const paths = item.split('.');
      let res = data;
      paths.map((path) => {
        if (reg.test(path)) {
          const match = path.match(reg)[0];
          console.log(match)
          // 将target[0]里的target储存到cmd里
          const cmd = path.replace(match, '');
          // 获取数组索引
          console.log(cmd)
          const arrIndex = match.replace(/[\[\]]/gi, '');
          console.log(cmd, arrIndex)
          res = res[cmd][arrIndex];
        } else {
          res = res[path];
        }
      });
      return res;
    });
  }

思路二:

  function get(data, ...args) {
    const res = JSON.stringify(data);
    return args.map(item => {
      return (new Function(`try {return ${res}.${item} } catch(e) {}`))()
    })
  }

js创建对象的安全模式

var Person = function (name) {
  if(this instanceof Person){
      this.name = name;
  }else{
    return new Person(name)
  }

}
var jack = Person('Jack')
console.log(jack)     //Person {name: "Jack"}
console.log(jack.name)//jack

图片优化

图片格式

  • JPG
  • PNG
  • SVG
    • 动态图片
    • webP
    • gif

图片优化方案

1.图片质量压缩
tinypng
智图

2.雪碧图

3.base64

4.懒加载

5.webapck图片优化

image-webpack-loader插件及逆行质量的压缩

{
test: /\.(png|jpg|gif|svg)$/,
use: [
  'file-loader',
  {
    loader: 'image-webpack-loader',
    options: {
      bypassOnDebug: true,
      mozjpeg: {
        progressive: true,
        quality: 65
      },
      optipng: {
        enabled: false,
      },
      pngquant: {
        quality: '65-90',
        speed: 4
      },
      gifsicle: {
        interlaced: false,
      },
      // the webp option will enable WEBP
      webp: {
        enabled: false,
      },
      limit: 1,
      name: '[name].[ext]?[hash]'
    }
  }]
}

合成雪碧图

const SpritesmithPlugin = require('webpack-spritesmith')
new SpritesmithPlugin({
  src: {
    cwd: path.resolve(__dirname, 'src/asserts'),
    glob: '*.png'
  },
  target: {
    image: path.resolve(__dirname, 'src/spritesmith-generated/sprite.png'),
    css: path.resolve(__dirname, 'src/spritesmith-generated/sprite.css')
  },
  apiOptions: {
    cssImageRef: "src/sprite.png"
  }
})
//生成sprite.css文件 

总结于https://segmentfault.com/a/1190000017481260
以便后续使用

HTML

html常见元素分类

  1. head区元素
  • meta
  • title
  • link
  • style
  • head
  • body
  • script
  • base(为页面上的所有链接规定默认地址或默认目标)
  1. body区元素
  • div/selection/article/aside/header/footer
  • p
  • span/em/strong
  • table/thead/tbody/tr/td
  • ul/ol/li/dl/dt/dd
  • a
  • form/input/select/textarea/button
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <base href="/"> 
  // 指定一个基础路径,所有的路径都是以这个为基准
  // viewport表示视图的大小,适配移动端第一步,viewport
  // width 设置layout viewport  的宽度,为一个正整数,或字符串"width-device"
  // initial-scale  设置页面的初始缩放值,为一个数字,可以带小数
  // maximum-scale  允许用户的最大缩放值,为一个数字,可以带小数
  // minimum-scale  允许用户的最小缩放值,为一个数字,可以带小数
  // user-scalable  是否允许用户进行缩放,值为‘no’或‘yes’, no 代表不允许,yes代表允许

html属性

  • a [href,target]
  • img [src,alt]
  • table td [colspan rowspan]
  • form [target(表单提交地址),method(get或者post),enctype(指定编码,如果上传需使用form-data)]
  • input [type,value]
  • button [type]
  • select>option [value]
  • label [for]

html5新增内容

  1. 新增区块标签
  • section
  • article
  • nav
  • aside
  1. 表单
  • 日期时间搜索
  • 表单验证
  • placehold自动聚焦
  1. 语义化标签(容易理解,机器容易检索,有助SEO)
  • header/footer
  • section/article
  • nav导航
  • aside 不重要内容
  • em/strong 强调
  • i / icon
  1. 新的API
  • Canvas+webGL
  • 本地存储
  • websocket
  • MathML,SVG

面试题

doctype存在的意义

让浏览器以标准模式渲染
让浏览器知道元素的合法性
####块级元素 行内元素 自闭合元素
块级元素

  • div
  • section
  • nav
  • header/footer
  • article(文章)
  • aside (文章侧栏)
  • details (元素细节)
  • dialog (对话框)
  • h1,h2,h3,h4,h5,h6
  • p
  • ul/ol/li
  • dl/dt/dd(列表)
  • form
  • table
  • iframe
  • canvas
  • hr

行内元素

  • span
  • em
  • strong
  • b(粗体)
  • i (斜体)
  • sup (上标)
  • sub (下标)
  • del (被删除的文本)
  • img
  • a
  • input
  • button
  • textarea

自闭合元素

  • img
  • a (可自闭合)
  • input
  • hr / br
  • meta / link

Property与Attribute区别

property是DOM中的属性,是javascript的对象
attribute是HTML构造树上的特性,值只能是字符串

html新增属性 如何处理HTML5新标签的浏览器兼容问题? 如何区分 HTML 和 HTML5?

  • 内容标签(header,nav,footer,aside,article,section)
  • 音频、视频API(audio,video)
  • 画布(Canvas)
  • 本地离线存储 localStorage sessionStorage
  • 表单控件 date、time、email、url、search
  • websocket

h5兼容 IE8/IE7/IE6支持通过document.createElement方法产生的标签处理兼容
如何区分:DOCTYPE声明\新增的结构元素\功能元素

webapck Independent To configure

webpack配置

前置工作

mkdir vue_style    
cd vue_style
npm init -y   //初始化package.json
//生成如下目录
  ├── src                                        //源目录(输入目录)
  │   ├── index.js          
  │   ├── app.vue                               
+ |── index.html       
  ├── package.json 
  |── webpack.config.js                          //webpack配置文件                        

安装依赖

npm install --save-dev vue 
//基于vue的那么vue必不可少...不多介绍
npm install --save-dev webpack 
//基于webpack的那么webpack也必不可少...不多介绍
npm install --save-dev webpack-cli 
//webpack version 4+ 需要下载webpack-cli(一些指令下文可能涉及到)
npm install --save-dev path 
//path 模块提供了一些工具函数,用于处理文件与目录的路径。
npm install --save-dev html-webpack-plugin 
//简化了HTML文件的创建 Plugin that simplifies creation of HTML files to serve your bundles
` npm install --save-dev clean-webpack-plugin 
//用于构建时清理构建文件夹下的内容 A webpack plugin to remove/clean your build folder(s) before building
npm install --save-dev vue-loader 
//Vue.js组件加载器(插件)
npm install --save-dev vue-template-compiler 
//对于模板的函数编译 与vue-loader 配合使用
npm install --save-dev webpack-dev-server
//热更新需要搭建服务模块
npm install --save-dev style-loader css-loader  
//css样式处理器

index.js

import Vue from 'vue'   // 引入vue模块
import App from './app.vue'  //引入文件(组件) app

new Vue({                //vue写法 新建一个实例
  el:"#app",             //元素  
  template:'<App/>',  // 模板使用标签<app/>
  components:{App}   // 组件app
})

app.vue

<template>
    <div id="app">
        <p class="test">hello world!!</p>
        <p class="test">{{msg}}</p>
    </div>
</template>
<script>
import Vue from 'vue'
    export default {
        name:'app',
        data(){
            return {
                msg:"hello vue !!"
            }
        },
    }
</script>
<style >
    .test{
        color:#020202;
        font-size:18px;
    }
</style>

webapck.config.js

const path = require('path'); //path 模块提供了一些工具函数,用于处理文件与目录的路径。
const HtmlWebpackPlugin = require('html-webpack-plugin'); //构建html文件
const CleanWebpackPlugin = require('clean-webpack-plugin'); // 清理构建目录下的文件
const webpack = require('webpack'); //webpack打包工具
const VueLoaderPlugin = require('vue-loader/lib/plugin'); // vue-loader 编译vue文件
const compiler = require('vue-template-compiler') // 模板函数编译 与vue-loader配合使用

module.exports = {
  entry: { //入口
    "app": "./src/index.js"
  },
  module: { //处理项目中的不同类型的模块。
    rules: [ // rules 各种规则(数组类型) 每个规则可以分为三部分 - 条件(condition),结果(result)和嵌套规则(nested rule)
      {
        test: /\.css/,
        use: ['style-loader', 'css-loader'] // style-loader 和css-loader 编译css处理
      },
      {
        test: /\.vue$/,
        loader: 'vue-loader' //vue-loader 编译vue模块
      }
    ]
  },
  devtool: 'inline-source-map', //生曾map 映射对应代码  方便错误查询
  devServer: {
    contentBase: './dist', // 告诉服务从哪提供代码内容(静态文件这么使用)
    hot: true //hot模式开启 
  },
  plugins: [
    new CleanWebpackPlugin(['dist']), // 告诉清理插件的目录
    new HtmlWebpackPlugin({ // 构建html
      filename: 'index.html', //文件名
      title: 'my-vue-cli', //title
      template: './index.html', //参照模板样式
    }),
    new webpack.HotModuleReplacementPlugin(), //热模块替换开启
    new VueLoaderPlugin() //vue-loader插件开启
  ],
  output: { //出口
    filename: 'index.js', //文件名
    path: path.resolve(__dirname, 'dist'), //路径
    publicPath: "" //srcript 引入路径
  },
  resolve: {
    //引入路径是不用写对应的后缀名
    extensions: ['.js', '.vue', '.json'],
    alias: {
      //正在使用的是vue的运行时版本,而此版本中的编译器时不可用的,我们需要把它切换成运行时 + 编译的版本
      'vue$': 'vue/dist/vue.esm.js',
      //用@直接指引到src目录下
      '@': path.resolve(__dirname, './src'),
    }
  },

};

package.json

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "watch": "webpack --watch",
    "dev": "webpack-dev-server --open --hot",
    "build": "webpack"
  },

npm run dev 运行于8080/可看到预期效果.
npm run build 打包编译同样可以看到效果

Accompanying

###vscode中格式化与vue中ESlint冲突

//在setting.json中设置如下
{
  "workbench.colorTheme": "Quiet Light",
  "window.zoomLevel": -1,
  "editor.fontSize": 20,
  "[html]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },
  "java.configuration.checkProjectSettingsExclusions": false,
  "editor.suggestSelection": "first",
  "vsintellicode.modify.editor.suggestSelection": "automaticallyOverrodeDefaultValue",
  "[javascript]": {
    "editor.defaultFormatter": "esbenp.prettier-vscode"
  },

  "vetur.validation.template": false,                                         //重要
  "vetur.format.defaultFormatter.js": "vscode-typescript", //重要
  "javascript.format.insertSpaceBeforeFunctionParenthesis": true, //重要
  "editor.formatOnType": true, //重要
  "editor.formatOnSave": true, //重要
  "editor.tabSize": 2
}

document​.referrer

返回跳转或打开到当前页面的那个页面的URI。

如果用户直接打开了这个页面(不是通过页面跳转,而是通过地址栏或者书签等打开的),则该属性为空字符串。由于该属性只是返回一个字符串,所以不能够通过该属性引用页面的 DOM。

base64互转 window.btoa window.atob

function base64EncodeUnicode(str) {//加密
    return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function(match, p1) {
        return String.fromCharCode('0x' + p1);
    }));
}

function base64DecodeUnicode(str) {//解码
    return decodeURIComponent(atob(str).split('').map(function(c) {
        return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
    }).join(''));
}

二维数组

for(var i =0;i< data_list.length;i++) {

  var dataList = data_list[i].data
    dataList.sort(function (a, b) {
      var t1 = a.xxx* 1;
      var t2 = b.sss* 1;
      if (t1 > t2) return 1;
      else if (t1 < t2) return -1;
      else return 0;

    })
}

object.keys() 把对象转换成数组进行遍历,返回一个给定对象的自身可枚举属性组成的数组

var data={a:1,b:2,c:9,d:4,e:5};
			console.log(data);//{a: 1, b: 2, c: 9, d: 4, e: 5}
			console.log(typeof Object.keys(data));//["a", "b", "c", "d", "e"]
			Object.keys(data).map((key,item)=>{
				console.log(key,data[key]);//key=>属性名    data[key]=>属性值
			});

set方法 可以去重

let set = new Set();
let a = NaN;
let b = NaN;
set.add(a);
set.add(b);
set // Set {NaN}
//=>NaN可以相等,需要去除一个NaN

封装bind方法

function bind(fn, context){
  return function (){
     return fn.apply(context, arguments);
  }
}

什么情况下会触发重排?

(1)页面渲染初始化时;(这个无法避免)
(2)浏览器窗口改变尺寸;
(3)元素尺寸改变时;
(4)元素位置改变时;
(5)元素内容改变时;
(6)添加或删除可见的DOM 元素时。

重排优化有如下五种方法

(1)将多次改变样式属性的操作合并成一次操作,减少DOM访问。
(2)如果要批量添加DOM,可以先让元素脱离文档流,操作完后再带入文档流,这样只会触发一次重排。(fragment元素的应用)
(3)将需要多次重排的元素,position属性设为absolute或fixed,这样此元素就脱离了文档流,它的变化不会影响到其他元素。例如有动画效果的元素就最好设置为绝对定位。
(4)由于display属性为none的元素不在渲染树中,对隐藏的元素操作不会引发其他元素的重排。如果要对一个元素进行复杂的操作时,可以先隐藏它,操作完成后再显示。这样只在隐藏和显示时触发两次重排。
(5)在内存中多次操作节点,完成后再添加到文档中去。例如要异步获取表格数据,渲染到页面。可以先取得数据后在内存中构建整个表格的html片段,再一次性添加到文档中去,而不是循环添加每一行。

getBoundingClientRect() 的用法

兼容性 
ie9以下浏览器只支持 getBoundingClientRect 方法的 top 、bottom、right、left属性; 
ie9 和其它浏览器支持 getBoundingClientRect 方法 有6个属性 top 、bottom、right、left、width和height
![Alt text](./1532930660184.png)

http://0927.red

轻量、可靠的移动端 Vue 组件库:
Fundebug 创始人:https://kiwenlau.com/

https://dc.36fy.com/ 代理

XSS SQL CSRF dDos CDN

Web攻击技术,如何防止被攻击

攻击:
  • XSS(Cross-Site Scripting,跨站脚本攻击):指通过存在安全漏洞的Web网站注册用户的浏览器内运行非法的HTML标签或者JavaScript进行的一种攻击。
  • SQL 注入攻击:通过表单提交可运行的 sql 语句,以破坏数据库数据。
  • CSRF(Cross-Site Request Forgeries,跨站点请求伪造):指攻击者通过设置好的陷阱,强制对已完成的认证用户进行非预期的个人信息或设定信息等某些状态更新。
  • dDos 拒绝服务攻击:通过大量请求疯狂占用服务器资源至其瘫痪。
  • CDN 攻击:使用不合理数据发起请求或请求不合理接口。
  • 身份伪造:冒充服务器或用户获取从另一方获取信息。
防御:
  • XSS:
    1.输入验证,过滤标签、事件、脚本、SQL
    2.http头: X-XSS-Protection
    3.cookie保护:set-cookie 头加入 http-only
  • SQL 注入
    1.输入验证,过滤标签、事件、脚本、SQL
    2.数据库权限最小化
    3.使用接口而非 SQL 语句
    4.限制文件上传类型
  • CSRF
    1.验证码
    2.验证 http 头 referer 项
    3.在 http 中加入 taken
  • 身份伪造
    1.隐藏敏感信息
    2.加密
    3.session 定期失效
    4.权限验证、中间件校验
    5.数字签名
    6.CA 证书校验
  • dDos 拒绝服务攻击
    1.流量防火墙
    2.验证码
  • CDN 攻击
    1.对版本控制进行Hash验证
    2.跳转验证(重定向验证)

live server

live server的作用:

live-server可以帮助我们前端人员搭建临时的http服务器。它不需要安装任何插件,使用起来比较便捷。它可以自动打开项目;修改本地文件后,浏览器能够立即同步,自动加载,自动刷新。
在package中增加代码

"scripts": {
    "server": "live-server ./ --port=8081"
}

live server的参数

live-server --port=8083  //更改端口号
* `--port=NUMBER`     - 选择要使用的端口,默认值:PORT env var或8080 
* `--host=ADDRESS`    - 选择要绑定的主机地址,默认值:IP env var或0.0.0.0(“任意地址”)
* `--no-browser`      - 禁止自动Web浏览器启动 
* `--browser=BROWSER` - 指定浏览器使用,而不是系统默认 
* `--quiet | -q`      - 禁止记录 
* `--verbose | -V`    - 更多日志记录(记录所有请求,显示所有侦听的IPv4接口等) 
* `--open=PATH`       - 启动浏览器到PATH而不是服务器根目录 
* `--watch=PATH`      - 用逗号分隔的路径来专门监视更改(默认值:观看所有内容)
* `--ignore=PATH`     - 要忽略的逗号分隔的路径字符串([anymatch](https://github.com/es128/anymatch) -compatible definition) 
* `--ignorePattern=RGXP`-文件的正则表达式忽略(即`.*\.jade`)(**不推荐使用**赞成`--ignore`) 
* `--middleware=PATH` - 导出.js文件的路径导出中间件功能添加; 可以是一个没有路径的名字,也不是引用`middleware`文件夹中捆绑的中间件的扩展名 
* `--entry-file=PATH` - 提供这个文件(服务器的根相对),以取代丢失的文件(对单页面应用程序有用) 
* `--mount=ROUTE:PATH` - 在定义的路线下提供路径内容(可能有多个定义) 
* `--spa`             - 将请求从/ abc转换为/#/ abc(适用于单页面应用程序) 
* `--wait=MILLISECONDS` - (默认100ms)等待所有更改,然后重新加载 
* `--htpasswd=PATH`   - 启用期待位于PATH的htpasswd文件的http-auth 
* `--cors`            - 为任何来源启用CORS(反映请求源,支持凭证的请求) 
* `--https=PATH`      - 到HTTPS配置模块的路径 
* `--proxy=ROUTE:URL` - 代理ROUTE到URL的所有请求 
* `--help | -h`       - 显示简短的使用提示和退出 
* `--version | -v`    - 显示版本和退出

node中的使用

var liveServer = require("live-server");
 
var params = {
    port: 8181, // Set the server port. Defaults to 8080. 
    host: "0.0.0.0", // Set the address to bind to. Defaults to 0.0.0.0 or process.env.IP. 
    root: "/public", // Set root directory that's being served. Defaults to cwd. 
    open: false, // When false, it won't load your browser by default. 
    ignore: 'scss,my/templates', // comma-separated string for paths to ignore 
    file: "index.html", // When set, serve this file for every 404 (useful for single-page applications) 
    wait: 1000, // Waits for all changes, before reloading. Defaults to 0 sec. 
    mount: [['/components', './node_modules']], // Mount a directory to a route. 
    logLevel: 2, // 0 = errors only, 1 = some, 2 = lots 
    middleware: [function(req, res, next) { next(); }] // Takes an array of Connect-compatible middleware that are injected into the server middleware stack 
};
liveServer.start(params);

按某相同字段进行分组

  var data = {
    "reduce_list": [{
      "reduce_id": 168,
      "settlement_id": 26,
      "settlement_code": "JSD-1003201811120001",
      "buss_contract_id": 4968,
      "buss_contract_code": "BZ-1003201811060014",
      "buss_order_id": 5776,
      "buss_order_code": "BZ-10032018110600140004",
      "reduce_item": 2,
      "reduce_amount": 4900,
      "reduce_explain": "北风卷地白草折",
      "reduce_type": 3,
      "bill_type": 3,
      "bill_code": "ZD-1003201811060014-0005"
    },{
      "reduce_id": 168,
      "settlement_id": 26,
      "settlement_code": "JSD-1003201811120001",
      "buss_contract_id": 4968,
      "buss_contract_code": "BZ-1003201811060014",
      "buss_order_id": 5776,
      "buss_order_code": "BZ-10032018110600140004",
      "reduce_item": 2,
      "reduce_amount": 4900,
      "reduce_explain": "北风卷地白草折",
      "reduce_type": 3,
      "bill_type": 3,
      "bill_code": "ZD-1003201811060014-0006"
    },{
      "reduce_id": 168,
      "settlement_id": 26,
      "settlement_code": "JSD-1003201811120001",
      "buss_contract_id": 4968,
      "buss_contract_code": "BZ-1003201811060014",
      "buss_order_id": 5776,
      "buss_order_code": "BZ-10032018110600140004",
      "reduce_item": 2,
      "reduce_amount": 4900,
      "reduce_explain": "北风卷地白草折",
      "reduce_type": 3,
      "bill_type": 3,
      "bill_code": "ZD-1003201811060014-0006"
    },{
      "reduce_id": 168,
      "settlement_id": 26,
      "settlement_code": "JSD-1003201811120001",
      "buss_contract_id": 4968,
      "buss_contract_code": "BZ-1003201811060014",
      "buss_order_id": 5776,
      "buss_order_code": "BZ-10032018110600140004",
      "reduce_item": 2,
      "reduce_amount": 4900,
      "reduce_explain": "北风卷地白草折",
      "reduce_type": 3,
      "bill_type": 3,
      "bill_code": "ZD-1003201811060014-0006"
    } ,{
      "reduce_id": 168,
      "settlement_id": 26,
      "settlement_code": "JSD-1003201811120001",
      "buss_contract_id": 4968,
      "buss_contract_code": "BZ-1003201811060014",
      "buss_order_id": 5776,
      "buss_order_code": "BZ-10032018110600140004",
      "reduce_item": 2,
      "reduce_amount": 4900,
      "reduce_explain": "北风卷地白草折",
      "reduce_type": 3,
      "bill_type": 3,
      "bill_code": "ZD-1003201811060014-0007"
    }, {
      "reduce_id": 165,
      "settlement_id": 26,
      "settlement_code": "JSD-1003201811120001",
      "buss_contract_id": 4968,
      "buss_contract_code": "BZ-1003201811060014",
      "buss_order_id": 5776,
      "buss_order_code": "BZ-10032018110600140004",
      "reduce_item": 5,
      "reduce_amount": 4900,
      "reduce_explain": "北风卷地白草折",
      "reduce_type": 1,
      "bill_type": 3,
      "bill_code": "ZD-1003201811060014-0007"
    }]
  }
//根据bill_code进行分组
/*
*  data:分组数据
*  group:按某字段分组
*/
function groupArray(data,group){
  var map = {}
  var reduceArray = []
  for (var i = 0; i < data.length; i++) {
    var dataList = data[i];
    console.log(!map[group]);
    if (!map[]) {
      reduceArray.push({
        id: group,
        data: [dataList]
      });
      map[group] = dataList
    } else {
      for (var j = 0; j < reduceArray.length; j++) {
        var dj = reduceArray[j]
        if (dj.id === group) {
          dj.data.push(dataList)
          break;
        }
      }
    }
  }
  return reduceArray;
}
  var reduceArray = groupArray(data.reduce_list,dataList.bill_code);
  console.log(reduceArray);

实例2:按某相同字段相加

const arr = [{
    id: 1,
    num: 10
  },
  {
    id: 1,
    num: 100
  },
  {
    id: 1,
    num: 10
  },
  {
    id: 2,
    num: 10
  },
  {
    id: 1,
    num: 100
  },
  {
    id: 2,
    num: 100
  },
  {
    id: 10,
    num: 10
  },
  {
    id: 10,
    num: 10
  }
]

let a = arr.reduce((h,n)=>{
  if(h.length === 0){
    h.push(n);
    return h;
  }
  for(let item of h){
    if(item.id === n.id){
      item.num += n.num;
      return h;  
    }
  }
  return h.concat([n])
},[])
console.log(a)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.