├── 2018 ├── React源码分析与实现(一):组件的初始化与渲染.md ├── React源码分析与实现(二):状态、属性更新 -> setState.md ├── 函数式编程了解一下(下).md ├── 函数式编程了解一下(上).md └── 窥探Underscore源码系列-开篇介绍.md ├── .gitignore ├── .idea ├── PersonalBlog.iml ├── modules.xml ├── vcs.xml └── workspace.xml ├── OnceTheBlog ├── 变量、作用域和内存问题.md └── 编写高质量代码基本要点.md ├── README.md ├── blogImg └── 47 │ ├── 6E39C3BFC492366A4D3231206111C2C1.jpg │ ├── pai_filter.gif │ └── zhu_filter.gif ├── hooks ├── .gitignore ├── README.md ├── images.d.ts ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ └── manifest.json ├── src │ ├── App.css │ ├── App.test.tsx │ ├── App.tsx │ ├── index.css │ ├── index.tsx │ ├── logo.svg │ └── registerServiceWorker.ts ├── tsconfig.json ├── tsconfig.prod.json ├── tsconfig.test.json ├── tslint.json └── yarn.lock ├── img ├── qzqdjx.jpg └── wx.jpg ├── lib ├── alibaba │ └── 阿里拍卖2020届毕业生校招启动.md ├── es6Env │ ├── .babelrc │ ├── .gitignore │ ├── index.html │ ├── index.js │ ├── package.json │ ├── src │ │ ├── index.js │ │ └── lib │ │ │ ├── diff.js │ │ │ ├── diffList.js │ │ │ ├── element.js │ │ │ ├── patche.js │ │ │ └── util.js │ └── webpack.config.js ├── img │ └── Wechat.jpeg ├── jsoo │ ├── .babelrc │ ├── .gitignore │ ├── dist │ │ └── index.js │ ├── index.html │ ├── package.json │ ├── src │ │ └── index.js │ ├── test.html │ └── webpack.config.js ├── preReact │ ├── .babelrc │ ├── .eslintignore │ ├── .eslintrc │ ├── .gitignore │ ├── README.md │ ├── package.json │ ├── playground.html │ ├── src │ │ ├── playground.js │ │ └── testDiff.js │ ├── test-diff │ │ ├── diff.js │ │ ├── element.js │ │ ├── list-diff.js │ │ ├── patch.js │ │ └── util.js │ └── webpack.config.js ├── testCli │ ├── .gitignore │ ├── bin │ │ ├── tcli │ │ ├── tcli-add │ │ ├── tcli-delete │ │ ├── tcli-init │ │ └── tcli-list │ ├── package-lock.json │ ├── package.json │ └── template.json └── underscore │ ├── test.html │ ├── test.js │ └── underscore.js ├── test.html └── webpack4-init ├── .babelrc ├── .gitignore ├── package-lock.json ├── package.json ├── src ├── index.html └── index.js └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | **/**/node_modules 3 | .vscode 4 | -------------------------------------------------------------------------------- /.idea/PersonalBlog.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | true 54 | DEFINITION_ORDER 55 | 56 | 57 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 13 | 14 | -------------------------------------------------------------------------------- /lib/jsoo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "neal", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "build": "babel src/index.js -o dist/index.js", 9 | "start": "npx webpack-dev-server --config webpack.config.js --color --progress --hot", 10 | "builds": "npx webpack --config webpack.config.js" 11 | }, 12 | "author": "Nealyang", 13 | "license": "ISC", 14 | "devDependencies": { 15 | "babel-cli": "^6.26.0", 16 | "babel-core": "^6.26.3", 17 | "babel-loader": "^7.1.5", 18 | "babel-plugin-transform-runtime": "^6.23.0", 19 | "babel-polyfill": "^6.26.0", 20 | "babel-preset-env": "^1.7.0", 21 | "clean-webpack-plugin": "^0.1.19", 22 | "webpack": "^4.16.2" 23 | }, 24 | "dependencies": { 25 | "babel-runtime": "^6.26.0", 26 | "webpack-cli": "^3.1.0" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/jsoo/src/index.js: -------------------------------------------------------------------------------- 1 | /* 2 | * @Author: 一凨 3 | * @Date: 2018-07-25 10:01:10 4 | * @Last Modified by: 一凨 5 | * @Last Modified time: 2018-07-25 17:25:56 6 | */ 7 | // $(function() { 8 | 9 | // var input = $('#J_input'); 10 | 11 | // //用来获取字数 12 | // function value(){ 13 | // return input.val(); 14 | // } 15 | 16 | // //渲染元素 17 | // function render(){ 18 | // var num = value(); 19 | // //没有字数的容器就新建一个 20 | // if ($('#J_input_text').length == 0) { 21 | // input.after('

'); 22 | // }; 23 | 24 | // $('#J_input_text').html(num); 25 | // } 26 | 27 | // //监听事件 28 | // input.on('keyup',function(){ 29 | // render(); 30 | // }); 31 | 32 | // //初始化,第一次渲染 33 | // render(); 34 | // }) 35 | 36 | 37 | // 单变量模拟命名空间 38 | 39 | // const bindValue = { 40 | // input: null, 41 | // init(config) { 42 | // this.input = $(config.id); 43 | // this.addListener(); 44 | // return this; 45 | // }, 46 | // addListener() { 47 | // let self = this; 48 | // this.input.on('keyup', () => { 49 | // self.render(); 50 | // }) 51 | // }, 52 | // getValue() { 53 | // return this.input.val(); 54 | // }, 55 | // render() { 56 | // let value = this.getValue(); 57 | // if ($('#J_input_text').length == 0) { 58 | // this.input.after('

'); 59 | // }; 60 | 61 | // $('#J_input_text').html(value); 62 | // } 63 | // } 64 | // $(function () { 65 | // bindValue.init({id:'#J_input'}).render() 66 | // }) 67 | 68 | // 闭包 69 | 70 | const BindValue = (function () { 71 | // 私有方法 72 | const _addListener = that => { 73 | that.input.on('keyup', () => { 74 | that.render(); 75 | }); 76 | } 77 | 78 | const _getValue = that => { 79 | return that.input.val(); 80 | } 81 | 82 | const ValueFunc = function (config) {}; 83 | ValueFunc.prototype.init = function (config) { 84 | this.input = $(config.id); 85 | _addListener(this); 86 | return this; 87 | } 88 | ValueFunc.prototype.render = function () { 89 | let value = _getValue(this); 90 | if ($('#J_input_text').length == 0) { 91 | this.input.after('

'); 92 | }; 93 | 94 | $('#J_input_text').html(value); 95 | } 96 | 97 | return ValueFunc; 98 | })(); 99 | 100 | $(function () { 101 | new BindValue().init({ 102 | id: '#J_input' 103 | }).render(); 104 | }) -------------------------------------------------------------------------------- /lib/jsoo/test.html: -------------------------------------------------------------------------------- 1 | testagergar 2 | eagreag 3 | 4 | 5 | aergreghrteh6j 6 | 7 | 8 | dfgshdytjuykliu;y 9 | 10 | 11 | fsgtrhjytkuytliikurjyrhstge 12 | -------------------------------------------------------------------------------- /lib/jsoo/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const CleanWebpackPlugin = require('clean-webpack-plugin'); 3 | module.exports = { 4 | entry: [ 5 | "babel-polyfill", 6 | path.join(__dirname, './src/index.js') 7 | ], 8 | output: { 9 | filename: "./index.js", 10 | }, 11 | module: { 12 | rules: [{ 13 | test: /\.js$/, 14 | use: ['babel-loader'], 15 | include: path.join(__dirname, 'src'), 16 | exclude: /node_modules/ 17 | }] 18 | }, 19 | resolve: { 20 | extensions: ['.js', '.jsx'] 21 | }, 22 | mode: 'development', 23 | plugins:[ 24 | new CleanWebpackPlugin(['bundle']) 25 | ], 26 | devServer: { 27 | contentBase: path.join(__dirname, 'dist'), //启动路径 28 | host:'localhost', //域名 29 | port: 8018, //端口号 30 | } 31 | }; -------------------------------------------------------------------------------- /lib/preReact/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/react", 4 | "@babel/stage-2" 5 | ], 6 | "plugins": [ 7 | [ 8 | "@babel/plugin-transform-react-jsx", 9 | { 10 | "pragma": "createElement", 11 | "pragmaFrag": "Fragment" 12 | } 13 | ], 14 | "@babel/plugin-proposal-class-properties" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /lib/preReact/.eslintignore: -------------------------------------------------------------------------------- 1 | **/node_modules/** 2 | **/dist/** 3 | **/coverage/** 4 | **/lib/** 5 | -------------------------------------------------------------------------------- /lib/preReact/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends":["eslint-config-airbnb"], 3 | "env":{ 4 | "browser":true, 5 | "node":true, 6 | "mocha":true, 7 | "jest":true, 8 | "es6":true 9 | }, 10 | "parser":"babel-eslint", 11 | "parserOptions":{ 12 | "ecmaVersion":6, 13 | "ecmaFeatures":{ 14 | "jsx":true, 15 | "experimentalObjectRestSpread":true 16 | } 17 | }, 18 | "plugins":[ 19 | "react", 20 | "babel"], 21 | "rules":{ 22 | "func-names":0, 23 | "arrow-body-style":0, 24 | "react/sort-comp":0, 25 | "react/prop-types":0, 26 | "react/jsx-first-prop-new-line":0, 27 | "react/jsx-filename-extension": 0, 28 | "react/react-in-jsx-scope": 0, 29 | "react/no-children-prop": 0, 30 | "import/no-unresolved":0, 31 | "no-param-reassign":0, 32 | "no-return-assign":0, 33 | "max-len":0, 34 | "consistent-return":0, 35 | "no-redeclare":0, 36 | "semi": [2, "never"], 37 | "no-extra-semi":2, 38 | "import/no-extraneous-dependencies": 0, 39 | "import/extensions": 0, 40 | "jsx-a11y/no-static-element-interactions": 0, 41 | "jsx-a11y/href-no-hash": 0, 42 | "react/no-find-dom-node": 0, 43 | "import/imports-first": 0, 44 | "react/no-string-refs": 0, 45 | "import/prefer-default-export": 0, 46 | "react/forbid-prop-types": 0, 47 | "no-plusplus": 0, 48 | "no-continue": 0, 49 | "no-underscore-dangle": 0, 50 | "no-template-curly-in-string": 0, 51 | "no-nested-ternary": 0, 52 | "no-useless-escape": 0, 53 | "no-unused-vars": ["error", { "varsIgnorePattern": "(createElement|JSDOM)" }] 54 | } 55 | } -------------------------------------------------------------------------------- /lib/preReact/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .idea/ 3 | .ipr 4 | .iws 5 | *~ 6 | ~* 7 | *.diff 8 | *.patch 9 | *.bak 10 | .DS_Store 11 | Thumbs.db 12 | .project 13 | .*proj 14 | .svn/ 15 | *.swp 16 | *.swo 17 | *.log 18 | node_modules/ 19 | .buildpath 20 | .settings 21 | npm-debug.log 22 | nohup.out 23 | _site 24 | _data 25 | dist 26 | lib 27 | typings 28 | coverage 29 | .next -------------------------------------------------------------------------------- /lib/preReact/README.md: -------------------------------------------------------------------------------- 1 | ## 第一堂作业:实现jsx解析器与渲染器 2 | - 先认真阅读doc目录下面的教材 3 | - 安装依赖运行npm start。 4 | - 调试playground.js,看看jsx编译后的结果是什么。 5 | - 实现一个数据结构,把jsx编译后的结构以嵌套形式保存在数据结构对象中(参考react渲染)。 6 | - 实现render,解析这个嵌套对象,并且把解析结果渲染到页面上。 7 | - 渲染可以调用dom.js里createElement函数。 8 | 9 | 有能力的同学可以自己实现事件,更新等内容。 10 | 11 | ## 提交方式 12 | - 每位同学需要自己建一个git仓库,可以选择github或者码云。 13 | - 每次作业写完后把代码提交到自己的github仓库里,并在README里写入自己的学习文章笔记,以增强学习效果,防止忘记 。 14 | - 然后把文章的链接提交到此地址,我看到后会把你拉入第二次课的微信群并发放第二次课程的资料,每周二一次课,如果过了截止日期将不再接受申请。 15 | - 本次课的开始时间为2018年7月17日23:59:59,截止时间为2018年7月30日23:59:59 16 | - 本次课程不收取任何费用 17 | -------------------------------------------------------------------------------- /lib/preReact/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ariesate/boilerplate", 3 | "version": "0.0.1", 4 | "description": "you should not publish this package.", 5 | "main": "index.js", 6 | "devDependencies": { 7 | "@babel/core": "^7.0.0-beta.44", 8 | "@babel/plugin-proposal-class-properties": "^7.0.0-beta.44", 9 | "@babel/plugin-transform-react-jsx": "^7.0.0-beta.44", 10 | "@babel/preset-stage-2": "7.0.0-beta.44", 11 | "@babel/preset-env": "^7.0.0-beta.44", 12 | "@babel/preset-react": "^7.0.0-beta.44", 13 | "@babel/preset-stage-0": "^7.0.0-beta.44", 14 | "babel-loader": "^8.0.0-beta.2", 15 | "webpack": "^4.5.0", 16 | "webpack-cli": "^2.0.14", 17 | "webpack-dev-server": "^3.1.3" 18 | }, 19 | "scripts": { 20 | "start": "webpack-dev-server", 21 | "lint": "eslint ./render/src", 22 | "eslint-fix": "eslint ./render/src --fix" 23 | }, 24 | "author": "ariesate@outlook.com", 25 | "license": "MIT" 26 | } 27 | -------------------------------------------------------------------------------- /lib/preReact/playground.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /lib/preReact/src/playground.js: -------------------------------------------------------------------------------- 1 | import render from '../lib/render'; 2 | import createElement from '../lib/createElement'; 3 | 4 | class Component { }; 5 | 6 | class HelloWorld extends Component { 7 | render() { 8 | return
Hello World 9 |

alert('testFunc')}>testFunc

10 |
11 | } 12 | } 13 | 14 | // render('hello world',document.getElementById("root")); 15 | // render(
alert(1)} style={{ color: 'red' }}>Nealyang:

study react

, document.getElementById("root")); 16 | render(,document.getElementById("root")); -------------------------------------------------------------------------------- /lib/preReact/src/testDiff.js: -------------------------------------------------------------------------------- 1 | 2 | import {Element as el} from '../test-diff/element'; 3 | import {patch} from '../test-diff/patch'; 4 | import {diff} from '../test-diff/diff'; 5 | var count = 0 6 | function renderTree () { 7 | console.log(1) 8 | debugger 9 | count++ 10 | var items = [] 11 | var color = (count % 2 === 0) 12 | ? 'blue' 13 | : 'red' 14 | for (var i = 0; i < count; i++) { 15 | items.push(el('li', ['Item #' + i])) 16 | } 17 | return el('div', {'id': 'container'}, [ 18 | el('h1', {style: 'color: ' + color}, ['simple virtal dom']), 19 | el('p', ['the count is :' + count]), 20 | el('ul', items) 21 | ]) 22 | } 23 | var tree = renderTree() 24 | // var root = tree.render() 25 | document.body.appendChild(root) 26 | // setInterval(function () { 27 | // var newTree = renderTree() 28 | // var patches = diff(tree, newTree) 29 | // console.log(patches) 30 | // patch(root, patches) 31 | // tree = newTree 32 | // }, 1000) -------------------------------------------------------------------------------- /lib/preReact/test-diff/diff.js: -------------------------------------------------------------------------------- 1 | var _ = require('./util') 2 | var patch = require('./patch') 3 | var listDiff = require('./list-diff') 4 | 5 | function diff (oldTree, newTree) { 6 | var index = 0 7 | var patches = {} 8 | dfsWalk(oldTree, newTree, index, patches) 9 | return patches 10 | } 11 | 12 | function dfsWalk (oldNode, newNode, index, patches) { 13 | var currentPatch = [] 14 | 15 | // Node is removed. 16 | if (newNode === null) { 17 | // Real DOM node will be removed when perform reordering, so has no needs to do anthings in here 18 | // TextNode content replacing 19 | } else if (_.isString(oldNode) && _.isString(newNode)) { 20 | if (newNode !== oldNode) { 21 | currentPatch.push({ type: patch.TEXT, content: newNode }) 22 | } 23 | // Nodes are the same, diff old node's props and children 24 | } else if ( 25 | oldNode.tagName === newNode.tagName && 26 | oldNode.key === newNode.key 27 | ) { 28 | // Diff props 29 | var propsPatches = diffProps(oldNode, newNode) 30 | if (propsPatches) { 31 | currentPatch.push({ type: patch.PROPS, props: propsPatches }) 32 | } 33 | // Diff children. If the node has a `ignore` property, do not diff children 34 | if (!isIgnoreChildren(newNode)) { 35 | diffChildren( 36 | oldNode.children, 37 | newNode.children, 38 | index, 39 | patches, 40 | currentPatch 41 | ) 42 | } 43 | // Nodes are not the same, replace the old node with new node 44 | } else { 45 | currentPatch.push({ type: patch.REPLACE, node: newNode }) 46 | } 47 | 48 | if (currentPatch.length) { 49 | patches[index] = currentPatch 50 | } 51 | } 52 | 53 | function diffChildren (oldChildren, newChildren, index, patches, currentPatch) { 54 | var diffs = listDiff(oldChildren, newChildren, 'key') 55 | newChildren = diffs.children 56 | 57 | if (diffs.moves.length) { 58 | var reorderPatch = { type: patch.REORDER, moves: diffs.moves } 59 | currentPatch.push(reorderPatch) 60 | } 61 | 62 | var leftNode = null 63 | var currentNodeIndex = index 64 | _.each(oldChildren, function (child, i) { 65 | var newChild = newChildren[i] 66 | currentNodeIndex = (leftNode && leftNode.count) 67 | ? currentNodeIndex + leftNode.count + 1 68 | : currentNodeIndex + 1 69 | dfsWalk(child, newChild, currentNodeIndex, patches) 70 | leftNode = child 71 | }) 72 | } 73 | 74 | function diffProps (oldNode, newNode) { 75 | var count = 0 76 | var oldProps = oldNode.props 77 | var newProps = newNode.props 78 | 79 | var key, value 80 | var propsPatches = {} 81 | 82 | // Find out different properties 83 | for (key in oldProps) { 84 | value = oldProps[key] 85 | if (newProps[key] !== value) { 86 | count++ 87 | propsPatches[key] = newProps[key] 88 | } 89 | } 90 | 91 | // Find out new property 92 | for (key in newProps) { 93 | value = newProps[key] 94 | if (!oldProps.hasOwnProperty(key)) { 95 | count++ 96 | propsPatches[key] = newProps[key] 97 | } 98 | } 99 | 100 | // If properties all are identical 101 | if (count === 0) { 102 | return null 103 | } 104 | 105 | return propsPatches 106 | } 107 | 108 | function isIgnoreChildren (node) { 109 | return (node.props && node.props.hasOwnProperty('ignore')) 110 | } 111 | 112 | module.exports = diff -------------------------------------------------------------------------------- /lib/preReact/test-diff/element.js: -------------------------------------------------------------------------------- 1 | var _ = require('./util') 2 | 3 | /** 4 | * Virtual-dom Element. 5 | * @param {String} tagName 6 | * @param {Object} props - Element's properties, 7 | * - using object to store key-value pair 8 | * @param {Array} - This element's children elements. 9 | * - Can be Element instance or just a piece plain text. 10 | */ 11 | function Element (tagName, props, children) { 12 | if (!(this instanceof Element)) { 13 | if (!_.isArray(children) && children != null) { 14 | children = _.slice(arguments, 2).filter(_.truthy) 15 | } 16 | return new Element(tagName, props, children) 17 | } 18 | 19 | if (_.isArray(props)) { 20 | children = props 21 | props = {} 22 | } 23 | 24 | this.tagName = tagName 25 | this.props = props || {} 26 | this.children = children || [] 27 | this.key = props 28 | ? props.key 29 | : void 666 30 | 31 | var count = 0 32 | 33 | _.each(this.children, function (child, i) { 34 | if (child instanceof Element) { 35 | count += child.count 36 | } else { 37 | children[i] = '' + child 38 | } 39 | count++ 40 | }) 41 | 42 | this.count = count 43 | } 44 | 45 | /** 46 | * Render the hold element tree. 47 | */ 48 | Element.prototype.render = function () { 49 | var el = document.createElement(this.tagName) 50 | var props = this.props 51 | 52 | for (var propName in props) { 53 | var propValue = props[propName] 54 | _.setAttr(el, propName, propValue) 55 | } 56 | 57 | _.each(this.children, function (child) { 58 | var childEl = (child instanceof Element) 59 | ? child.render() 60 | : document.createTextNode(child) 61 | el.appendChild(childEl) 62 | }) 63 | 64 | return el 65 | } 66 | 67 | module.exports = Element -------------------------------------------------------------------------------- /lib/preReact/test-diff/list-diff.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Diff two list in O(N). 3 | * @param {Array} oldList - Original List 4 | * @param {Array} newList - List After certain insertions, removes, or moves 5 | * @return {Object} - {moves: } 6 | * - moves is a list of actions that telling how to remove and insert 7 | */ 8 | function diff (oldList, newList, key) { 9 | var oldMap = makeKeyIndexAndFree(oldList, key) 10 | var newMap = makeKeyIndexAndFree(newList, key) 11 | 12 | var newFree = newMap.free 13 | 14 | var oldKeyIndex = oldMap.keyIndex 15 | var newKeyIndex = newMap.keyIndex 16 | 17 | var moves = [] 18 | 19 | // a simulate list to manipulate 20 | var children = [] 21 | var i = 0 22 | var item 23 | var itemKey 24 | var freeIndex = 0 25 | 26 | // first pass to check item in old list: if it's removed or not 27 | while (i < oldList.length) { 28 | item = oldList[i] 29 | itemKey = getItemKey(item, key) 30 | if (itemKey) { 31 | if (!newKeyIndex.hasOwnProperty(itemKey)) { 32 | children.push(null) 33 | } else { 34 | var newItemIndex = newKeyIndex[itemKey] 35 | children.push(newList[newItemIndex]) 36 | } 37 | } else { 38 | var freeItem = newFree[freeIndex++] 39 | children.push(freeItem || null) 40 | } 41 | i++ 42 | } 43 | 44 | var simulateList = children.slice(0) 45 | 46 | // remove items no longer exist 47 | i = 0 48 | while (i < simulateList.length) { 49 | if (simulateList[i] === null) { 50 | remove(i) 51 | removeSimulate(i) 52 | } else { 53 | i++ 54 | } 55 | } 56 | 57 | // i is cursor pointing to a item in new list 58 | // j is cursor pointing to a item in simulateList 59 | var j = i = 0 60 | while (i < newList.length) { 61 | item = newList[i] 62 | itemKey = getItemKey(item, key) 63 | 64 | var simulateItem = simulateList[j] 65 | var simulateItemKey = getItemKey(simulateItem, key) 66 | 67 | if (simulateItem) { 68 | if (itemKey === simulateItemKey) { 69 | j++ 70 | } else { 71 | // new item, just inesrt it 72 | if (!oldKeyIndex.hasOwnProperty(itemKey)) { 73 | insert(i, item) 74 | } else { 75 | // if remove current simulateItem make item in right place 76 | // then just remove it 77 | var nextItemKey = getItemKey(simulateList[j + 1], key) 78 | if (nextItemKey === itemKey) { 79 | remove(i) 80 | removeSimulate(j) 81 | j++ // after removing, current j is right, just jump to next one 82 | } else { 83 | // else insert item 84 | insert(i, item) 85 | } 86 | } 87 | } 88 | } else { 89 | insert(i, item) 90 | } 91 | 92 | i++ 93 | } 94 | 95 | //if j is not remove to the end, remove all the rest item 96 | var k = simulateList.length - j 97 | while (j++ < simulateList.length) { 98 | k-- 99 | remove(k + i) 100 | } 101 | 102 | 103 | function remove (index) { 104 | var move = {index: index, type: 0} 105 | moves.push(move) 106 | } 107 | 108 | function insert (index, item) { 109 | var move = {index: index, item: item, type: 1} 110 | moves.push(move) 111 | } 112 | 113 | function removeSimulate (index) { 114 | simulateList.splice(index, 1) 115 | } 116 | 117 | return { 118 | moves: moves, 119 | children: children 120 | } 121 | } 122 | 123 | /** 124 | * Convert list to key-item keyIndex object. 125 | * @param {Array} list 126 | * @param {String|Function} key 127 | */ 128 | function makeKeyIndexAndFree (list, key) { 129 | var keyIndex = {} 130 | var free = [] 131 | for (var i = 0, len = list.length; i < len; i++) { 132 | var item = list[i] 133 | var itemKey = getItemKey(item, key) 134 | if (itemKey) { 135 | keyIndex[itemKey] = i 136 | } else { 137 | free.push(item) 138 | } 139 | } 140 | return { 141 | keyIndex: keyIndex, 142 | free: free 143 | } 144 | } 145 | 146 | function getItemKey (item, key) { 147 | if (!item || !key) return void 666 148 | return typeof key === 'string' 149 | ? item[key] 150 | : key(item) 151 | } 152 | 153 | exports.makeKeyIndexAndFree = makeKeyIndexAndFree // exports for test 154 | exports.listDiff = diff -------------------------------------------------------------------------------- /lib/preReact/test-diff/patch.js: -------------------------------------------------------------------------------- 1 | var _ = require('./util') 2 | 3 | var REPLACE = 0 4 | var REORDER = 1 5 | var PROPS = 2 6 | var TEXT = 3 7 | 8 | function patch (node, patches) { 9 | var walker = {index: 0} 10 | dfsWalk(node, walker, patches) 11 | } 12 | 13 | function dfsWalk (node, walker, patches) { 14 | var currentPatches = patches[walker.index] 15 | 16 | var len = node.childNodes 17 | ? node.childNodes.length 18 | : 0 19 | for (var i = 0; i < len; i++) { 20 | var child = node.childNodes[i] 21 | walker.index++ 22 | dfsWalk(child, walker, patches) 23 | } 24 | 25 | if (currentPatches) { 26 | applyPatches(node, currentPatches) 27 | } 28 | } 29 | 30 | function applyPatches (node, currentPatches) { 31 | _.each(currentPatches, function (currentPatch) { 32 | switch (currentPatch.type) { 33 | case REPLACE: 34 | var newNode = (typeof currentPatch.node === 'string') 35 | ? document.createTextNode(currentPatch.node) 36 | : currentPatch.node.render() 37 | node.parentNode.replaceChild(newNode, node) 38 | break 39 | case REORDER: 40 | reorderChildren(node, currentPatch.moves) 41 | break 42 | case PROPS: 43 | setProps(node, currentPatch.props) 44 | break 45 | case TEXT: 46 | if (node.textContent) { 47 | node.textContent = currentPatch.content 48 | } else { 49 | // fuck ie 50 | node.nodeValue = currentPatch.content 51 | } 52 | break 53 | default: 54 | throw new Error('Unknown patch type ' + currentPatch.type) 55 | } 56 | }) 57 | } 58 | 59 | function setProps (node, props) { 60 | for (var key in props) { 61 | if (props[key] === void 666) { 62 | node.removeAttribute(key) 63 | } else { 64 | var value = props[key] 65 | _.setAttr(node, key, value) 66 | } 67 | } 68 | } 69 | 70 | function reorderChildren (node, moves) { 71 | var staticNodeList = _.toArray(node.childNodes) 72 | var maps = {} 73 | 74 | _.each(staticNodeList, function (node) { 75 | if (node.nodeType === 1) { 76 | var key = node.getAttribute('key') 77 | if (key) { 78 | maps[key] = node 79 | } 80 | } 81 | }) 82 | 83 | _.each(moves, function (move) { 84 | var index = move.index 85 | if (move.type === 0) { // remove item 86 | if (staticNodeList[index] === node.childNodes[index]) { // maybe have been removed for inserting 87 | node.removeChild(node.childNodes[index]) 88 | } 89 | staticNodeList.splice(index, 1) 90 | } else if (move.type === 1) { // insert item 91 | var insertNode = maps[move.item.key] 92 | ? maps[move.item.key].cloneNode(true) // reuse old item 93 | : (typeof move.item === 'object') 94 | ? move.item.render() 95 | : document.createTextNode(move.item) 96 | staticNodeList.splice(index, 0, insertNode) 97 | node.insertBefore(insertNode, node.childNodes[index] || null) 98 | } 99 | }) 100 | } 101 | 102 | patch.REPLACE = REPLACE 103 | patch.REORDER = REORDER 104 | patch.PROPS = PROPS 105 | patch.TEXT = TEXT 106 | 107 | module.exports = patch -------------------------------------------------------------------------------- /lib/preReact/test-diff/util.js: -------------------------------------------------------------------------------- 1 | var _ = exports 2 | 3 | _.type = function (obj) { 4 | return Object.prototype.toString.call(obj).replace(/\[object\s|\]/g, '') 5 | } 6 | 7 | _.isArray = function isArray (list) { 8 | return _.type(list) === 'Array' 9 | } 10 | 11 | _.slice = function slice (arrayLike, index) { 12 | return Array.prototype.slice.call(arrayLike, index) 13 | } 14 | 15 | _.truthy = function truthy (value) { 16 | return !!value 17 | } 18 | 19 | _.isString = function isString (list) { 20 | return _.type(list) === 'String' 21 | } 22 | 23 | _.each = function each (array, fn) { 24 | for (var i = 0, len = array.length; i < len; i++) { 25 | fn(array[i], i) 26 | } 27 | } 28 | 29 | _.toArray = function toArray (listLike) { 30 | if (!listLike) { 31 | return [] 32 | } 33 | 34 | var list = [] 35 | 36 | for (var i = 0, len = listLike.length; i < len; i++) { 37 | list.push(listLike[i]) 38 | } 39 | 40 | return list 41 | } 42 | 43 | _.setAttr = function setAttr (node, key, value) { 44 | switch (key) { 45 | case 'style': 46 | node.style.cssText = value 47 | break 48 | case 'value': 49 | var tagName = node.tagName || '' 50 | tagName = tagName.toLowerCase() 51 | if ( 52 | tagName === 'input' || tagName === 'textarea' 53 | ) { 54 | node.value = value 55 | } else { 56 | // if it is not a input or textarea, use `setAttribute` to set 57 | node.setAttribute(key, value) 58 | } 59 | break 60 | default: 61 | node.setAttribute(key, value) 62 | break 63 | } 64 | } -------------------------------------------------------------------------------- /lib/preReact/webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack') 2 | const path = require('path') 3 | 4 | const config = { 5 | entry: { 6 | playground: './src/playground.js', 7 | // playground: './src/testDiff.js', 8 | }, 9 | output: { 10 | filename: '[name].js', 11 | publicPath: '/', 12 | }, 13 | module: { 14 | rules: [ 15 | { test: /\.js?$/, exclude: /node_modules/, loader: 'babel-loader' }, 16 | ], 17 | }, 18 | plugins: [ 19 | new webpack.HotModuleReplacementPlugin(), 20 | ], 21 | mode: "development" 22 | } 23 | 24 | module.exports = config 25 | -------------------------------------------------------------------------------- /lib/testCli/.gitignore: -------------------------------------------------------------------------------- 1 | ./node_moduels/ -------------------------------------------------------------------------------- /lib/testCli/bin/tcli: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | 3 | // console.log('Hello Cli'); 4 | 5 | const program = require('commander'); 6 | 7 | program 8 | .version(require('../package').version) 9 | .usage(' [options]') 10 | .command('add' ,'add a new template') 11 | .command('delete' ,'delete a template') 12 | .command('list' ,'list all the templates') 13 | .command('init' ,'generate a new project form a template') 14 | 15 | // 解析命令行参数 16 | program.parse(process.argv); -------------------------------------------------------------------------------- /lib/testCli/bin/tcli-add: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const inquirer = require("inquirer"); 4 | 5 | const chalk = require("chalk"); 6 | 7 | const fs = require("fs"); 8 | 9 | const tplObj = require(`${__dirname}/../template`); 10 | 11 | // 自定义交互式命令行问题以及简单校验 12 | 13 | let question = [ 14 | { 15 | name: "name", 16 | type: "input", 17 | message: "请输入模板名称", 18 | validate(val) { 19 | if (val === "") { 20 | return "Name is required"; 21 | } else if (tplObj[val]) { 22 | return "Template has already existed!"; 23 | } else { 24 | return true; 25 | } 26 | } 27 | }, 28 | { 29 | name: "url", 30 | type: "input", 31 | message: "请输入模板地址", 32 | validate(val) { 33 | if (val === "") { 34 | return "The url is required!"; 35 | } else { 36 | return true; 37 | } 38 | } 39 | } 40 | ]; 41 | 42 | 43 | inquirer 44 | .prompt(question).then(answers =>{ 45 | let {url,name} = answers; 46 | // 过滤 Unicode 字符 47 | tplObj[name] = url.replace(/[\u0000-\u0019]/g,''); 48 | 49 | fs.writeFile(`${__dirname}/../template.json`,JSON.stringify(tplObj),'utf-8',err=>{ 50 | if(err) console.log(err) 51 | console.log('\n') 52 | console.log(chalk.green('Added successfully!\n')) 53 | console.log(chalk.grey('The latest template list is: \n')) 54 | console.log(tplObj) 55 | console.log('\n') 56 | }) 57 | }) -------------------------------------------------------------------------------- /lib/testCli/bin/tcli-delete: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const inquirer = require('inquirer') 4 | const chalk = require('chalk') 5 | const fs = require('fs') 6 | const tplObj = require(`${__dirname}/../template`) 7 | 8 | let question = [ 9 | { 10 | name: "name", 11 | message: "请输入要删除的模板名称", 12 | validate (val) { 13 | if (val === '') { 14 | return 'Name is required!' 15 | } else if (!tplObj[val]) { 16 | return 'Template does not exist!' 17 | } else { 18 | return true 19 | } 20 | } 21 | } 22 | ] 23 | 24 | inquirer 25 | .prompt(question).then(answers => { 26 | let { name } = answers; 27 | delete tplObj[name] 28 | // 更新 template.json 文件 29 | fs.writeFile(`${__dirname}/../template.json`, JSON.stringify(tplObj), 'utf-8', err => { 30 | if (err) console.log(err) 31 | console.log('\n') 32 | console.log(chalk.green('Deleted successfully!\n')) 33 | console.log(chalk.grey('The latest template list is: \n')) 34 | console.log(tplObj) 35 | console.log('\n') 36 | }) 37 | }) 38 | -------------------------------------------------------------------------------- /lib/testCli/bin/tcli-init: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const program = require("commander"); 4 | const chalk = require("chalk"); 5 | const ora = require("ora"); 6 | const download = require("download-git-repo"); 7 | const tplObj = require(`${__dirname}/../template`); 8 | 9 | program.usage(" [project-name]"); 10 | program.parse(process.argv); 11 | 12 | // 当没有输入参数的时候给个提示 13 | if (program.args.length < 1) return program.help(); 14 | 15 | let templateName = program.args[0]; 16 | let projectName = program.args[1]; 17 | 18 | console.log(tplObj,typeof tplObj) 19 | if (!tplObj[templateName]) { 20 | console.log(chalk.redBright("\n Template does not exit! \n")); 21 | process.exit(0); 22 | } 23 | 24 | if (!projectName) { 25 | console.log(chalk.red("\n Project should not be empty! \n ")); 26 | return; 27 | } 28 | 29 | url = tplObj[templateName]; 30 | 31 | console.log(chalk.white("\n Start generating... \n")); 32 | 33 | // 出现加载图标 34 | const spinner = ora("Downloading..."); 35 | spinner.start(); 36 | 37 | download(url, projectName, err => { 38 | if (err) { 39 | spinner.fail(); 40 | console.log(chalk.red(`Generation failed. ${err}`)); 41 | return; 42 | } 43 | // 结束加载图标 44 | spinner.succeed(); 45 | console.log(chalk.green("\n Generation completed!")); 46 | console.log("\n To get started"); 47 | console.log(`\n cd ${projectName} \n`); 48 | }); 49 | -------------------------------------------------------------------------------- /lib/testCli/bin/tcli-list: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | const tplObj = require(`${__dirname}/../template`) 4 | console.log(tplObj) 5 | -------------------------------------------------------------------------------- /lib/testCli/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "testcli", 3 | "version": "1.0.0", 4 | "description": "test cli", 5 | "main": "index.js", 6 | "bin": { 7 | "tcli": "./bin/tcli", 8 | "tcli-add": "./bin/tcli-add", 9 | "tcli-list": "./bin/tcli-list", 10 | "tcli-delete": "./bin/tcli-delete", 11 | "tcli-init": "./bin/tcli-init" 12 | }, 13 | "scripts": { 14 | "test": "echo \"Error: no test specified\" && exit 1" 15 | }, 16 | "keywords": [ 17 | "Nealyang", 18 | "testCli" 19 | ], 20 | "author": "Nealyang", 21 | "license": "ISC", 22 | "dependencies": { 23 | "chalk": "^2.4.2", 24 | "commander": "^2.20.0", 25 | "download-git-repo": "^2.0.0", 26 | "inquirer": "^6.3.1", 27 | "ora": "^3.4.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/testCli/template.json: -------------------------------------------------------------------------------- 1 | {"simple":"Nealyang/React-Fullstack-Dianping-Demo"} -------------------------------------------------------------------------------- /lib/underscore/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /lib/underscore/test.js: -------------------------------------------------------------------------------- 1 | var html = '吴小蛆的博客'; 2 | var escaped = _.escape(html); 3 | console.log(escaped); 4 | -------------------------------------------------------------------------------- /test.html: -------------------------------------------------------------------------------- 1 | static displayName = 'TitleZone'; 2 | 3 | static defaultProps = { 4 | lazyload: true, 5 | resizeMode: 'cover', 6 | titleTag: [] 7 | } 8 | 9 | render() { 10 | const { 11 | title, 12 | titleTag, 13 | lazyload, 14 | resizeMode, 15 | placeholder, 16 | styles 17 | } = this.props; 18 | 19 | return ( 20 | 21 | { 22 | titleTag && titleTag.map(function (titleTagUri, i) { 23 | return ( 24 |