web杂谈

来源:互联网 发布:c语言小游戏源代码 编辑:程序博客网 时间:2024/06/05 07:24

前言:本人作为一个前端小白,梳理一下这段时间开发前端一个页面的过程,希望对自己起到备忘并思考的作用,希望我的经验对于别人也有一点帮助的作用。
由于本文碎碎念的部分过长,导致本文过长。还请读者见谅。—更新中

前端框架

现如今,前端框架也越来越多了,比如ember,angular,以及这里要说到的vuejs.。下面的内容首先要介绍vue.js的原理。

Vue.js ?

  • 原理

vue.js是一个 MVVM 前端框架,(Model / View / ViewModel)
这里的viewModel是什么含义呢?
这意味着我们不需要撰写任何 DOM 操作代码,被绑定增强的 HTML 模板(<template>)是底层数据状态的声明式的映射,数据不过是普通 JavaScript 对象。我们的视图完全由数据驱动。
这里写图片描述
vue将普通的对象(也就是js的普通的对象)的属性通过Object.defineProperty转换为[ES5特性]之一的 getter/setter。

OBJECTOBJECT.DEFINEPROPERTY()该方法直接在一个对象上定义一个新属性,或者修改一个已经存在的属性, 并返回这个对象。Object.defineProperties()与其一样,只是可以同时定义多个属性。该方法允许精确添加或修改对象的属性。常用的场景定义setter和getter。定义对象属性是否可枚举enumerable。可枚举的属性键值能够被for inObject.keys获得。最常见的例子就是,数组中索引属性是可枚举的,而成员方法就是不可枚举的。~! 这也是为什么我们不要使用for in遍历数组的原因,因为可能有一些拙劣的上下文代码,为数组添加了一个可枚举的方法,因此我们在扩展一个特殊对象属性时特别需要特别关注这一点OBJECT.KEYS()把对象的返回一个包括对象可枚举键值的数组。

模板中每个指令/数据绑定 都有一个对应的 watcher 对象, 当修改对象值的时,首先会触发属性的setter,在setter被调用时,会触发 watcher 重新计算 ,也就会导致它的关联指令更新 DOM。
上面的内容把vuejs的内容已说明的很清楚了,如果你能理解指令和数据绑定(下面还会有更多的解释)的话。
Vue.js 的核心是一个响应的数据绑定系统,它让数据与 DOM 保持同步非常简单。在使用 jQuery 手工操作 DOM 时,我们的代码常常是命令式的、重复的与易错的。Vue.js 拥抱数据驱动的视图概念。通俗地讲,它意味着我们在普通 HTML 模板中使用特殊的语法将 DOM “绑定”到底层数据。一旦创建了绑定,DOM 将与数据保持同步。每当修改了数据,DOM 便相应地更新。这样我们应用中的逻辑就几乎都是直接修改数据了,不必与 DOM 更新搅在一起。这让我们的代码更容易撰写、理解与维护。

  • 现在重要的问题是用vue来解决问题

比如我想在一个项目里面使用到一个灵活的jsoneditor,通过调研发现vuejs并没有直接的组件可以用,但是发现javascript有一个很好用的叫做jsoneditor的组件,那么我们如何在一个vue.js的工程里面加入这个jsoneditor?

这里就会包括很多要解决的问题了,下面的内容将一一道来。

模块系统

伴随着移动互联的大潮,当今越来越多的网站已经从网页模式进化到了 Webapp 模式。它们运行在现代的高级浏览器里,使用 HTML5、 CSS3、 ES6 等更新的技术来开发丰富的功能,网页已经不仅仅是完成浏览的基本需求,并且webapp通常是一个单页面应用,每一个视图通过异步的方式加载,这导致页面初始化和使用过程中会加载越来越多的 JavaScript 代码,这给前端开发的流程和资源组织带来了巨大的挑战。
前端开发和其他开发工作的主要区别,首先是前端是基于多语言、多层次的编码和组织工作,其次前端产品的交付是基于浏览器,这些资源是通过增量加载的方式运行到浏览器端,如何在开发环境组织好这些碎片化的代码和资源,并且保证他们在浏览器端快速、优雅的加载和更新,就需要一个模块化系统,这个理想中的模块化系统是前端工程师多年来一直探索的难题。

模块系统主要解决模块的定义、依赖和导出,先来看看已经存在的模块系统。

<script>标签<script src="module1.js"></script><script src="module2.js"></script><script src="libraryA.js"></script>

这是最原始的 JavaScript 文件加载方式,如果把每一个文件看做是一个模块,那么他们的接口通常是暴露在全局作用域下,也就是定义在 window 对象中。

CommonJS服务器端的 Node.js 遵循 CommonJS规范,该规范的核心思想是允许模块通过 require 方法来同步加载所要依赖的其他模块,然后通过 exportsmodule.exports 来导出需要暴露的接口。require("module");require("../file.js");exports.doStuff = function() {};module.exports = someValue;

上面的代码很好理解,但是看起来似乎能解决的问题并不多。那么期望的模块系统是什么样子的呢?

webpack

webpack 就是一个很好的模块化系统。

  • 可以兼容多种模块风格,尽量可以利用已有的代码,不仅仅只是 JavaScript 模块化,还有 CSS、图片、字体等资源也需要模块化。
  • 前端模块是怎么加载的呢?前端模块要在客户端中执行,所以他们需要增量加载到浏览器中。模块的加载和传输,我们首先能想到两种极端的方式,一种是每个模块文件都单独请求,另一种是把所有模块打包成一个文件然后只请求一次。显而易见,每个模块都发起单独的请求造成了请求次数过多,导致应用启动速度慢;一次请求加载所有模块导致流量浪费、初始化过程慢。这两种方式都不是好的解决方案,它们过于简单粗暴。分块传输,按需进行懒加载,在实际用到某些模块的时候再增量更新,才是较为合理的模块加载方案。要实现模块的按需加载,就需要一个对整个代码库中的模块进行静态分析、编译打包的过程
  • 所有资源都是模块:在上面的分析过程中,我们提到的模块仅仅是指JavaScript模块文件。然而,在前端开发过程中还涉及到样式、图片、字体、HTML 模板等等众多的资源。这些资源还会以各种方言的形式存在,比如 coffeescript、 less、 sass、众多的模板库等等。如果他们都可以视作模块,并且都可以通过require的方式来加载,将带来优雅的开发体验,比如:require("./style.css");
    require("./style.less");
    require("./template.jade");
    require("./image.png");

静态分析

如何做到让 require 能加载各种资源呢?在编译的时候,要对整个代码进行静态分析,分析出各个模块的类型和它们依赖关系,然后将不同类型的模块提交给适配的加载器来处理。比如一个用 LESS 写的样式模块,可以先用 LESS 加载器将它转成一个CSS 模块,在通过 CSS 模块把他插入到页面的 <style> 标签中执行。

Webpack 是一个模块打包器。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。Webpack 本身只能处理原生的 JavaScript 模块,但是 loader 转换器可以将各种类型的资源转换成 JavaScript 模块。这样,任何资源都可以成为 Webpack 可以处理的模块。

NODE_ENV

通过NODE_ENV可以来设置环境变量(默认值为development)。一般我们通过检查这个值来分别对开发环境和生产环境下做不同的处理。可以在命令行中通过下面的方式设置这个值:linux & mac: export NODE_ENV=productionwindows: set NODE_ENV=production比方说如果代码中要对生产环境下做一些处理,可以这样写:if (process.env.NODE_ENV === 'production') {    // just for production code}

express结合webpack实现hmr

webpack 和 Express 实现前后端热更新开发。
比如在package.json使用到的这两块的版本号是:

"webpack-dev-middleware": "^1.6.1"
"webpack-hot-middleware": "^2.10.0"

Webpack dev middleware 是 WebPack 的一个中间件。它用于在 Express 中分发需要通过 WebPack 编译的文件。单独使用它就可以完成代码的热重载(hot reloading)功能。

Webpack hot middleware 它通过订阅 Webpack 的编译更新,之后通过执行 webpack 的 HMR api 将这些代码模块的更新推送给浏览器端。
那么什么是是HMR api呢?

HMR 即 Hot Module Replacement 是 Webpack 一个重要的功能。它可以使我们不用通过手动地刷新浏览器页面实现将我们的更新代码实时应用到当前页面中
不需要手动刷新浏览器看起来是非常高级的功能,那么这个功能是怎么做到的呢?
HMR 的实现原理是在我们的开发中的应用代码中加入了 HMR Runtime,它是 HMR 的客户端(浏览器端
client)用于和开发服务器通信,接收更新的模块。服务端工作就是前面提到的 Webpack hot middleware
的,它会在代码更新编译完成之后通过以 json 格式输出给HMR Runtime 就会更具 json 中描述来动态更新相应的代码。

这里写图片描述

那么怎么配置这样的热加载环境呢?
我们知道webpack是用来配置输入输出的,那在这个环节之中输入一些小小的魔法,便可以达到我们的的这一目的了。
是怎样的魔法呢,看下面的代码:

var webpack = require('webpack')...module.exports = merge(baseWebpackConfig, {     ...   entry: [       // 添加一个和HotMiddleWare通信的客户端    HotMiddleWareConfig,    // 添加web应用入口文件    './client.js'  ],  plugins: [    // https://github.com/glenjamin/webpack-hot-middleware#installation--usage    new webpack.optimize.OccurenceOrderPlugin(),    new webpack.HotModuleReplacementPlugin(),    new webpack.NoErrorsPlugin(),  ]})

getEntries 是自动根据我们规则获取到入口文件并加上 webpack hot middle 配置

express

在 Express 的配置主要就4个步骤:
引入 webpack 的配置文件和 生成 webpack 的编译器
将编译器连接至 webpack dev middleware
将编译器连接至 webpack hot middleware
定义 express 配置

为了提供诸如图像、CSS 文件和 JavaScript 文件之类的静态文件,请使用 Express 中的 express.static内置中间件函数。express.static是一个内置的中间件

app.use(express.static('public'));现在,可以装入位于 public 目录中的文件:http://localhost:3000/images/kitten.jpghttp://localhost:3000/css/style.csshttp://localhost:3000/js/app.jshttp://localhost:3000/images/bg.pnghttp://localhost:3000/hello.html

Express 相对于静态目录查找文件,因此静态目录的名称不是此 URL 的一部分。

app.use(express.static('public'));app.use(express.static('files'));

要为 express.static 函数提供的文件创建虚拟路径前缀(路径并不实际存在于文件系统中),请为静态目录指定安装路径,如下所示:

app.use('/static', express.static('public'));现在,可以装入具有 /static 路径前缀的 public 目录中的文件。http://localhost:3000/static/images/kitten.jpghttp://localhost:3000/static/css/style.csshttp://localhost:3000/static/js/app.jshttp://localhost:3000/static/images/bg.pnghttp://localhost:3000/static/hello.html

path

Node.js path 模块提供了一些用于处理文件路径的小工具,我们可以通过以下方式引入该模块:

var path = require("path")

path.join([path1][, path2][, …])
用于连接路径。该方法的主要用途在于,会正确使用当前系统的路径分隔符,Unix系统是”/”,Windows系统是”\”。

npm run

最后在package.json定义一些scripts,就可以使用npm run来运行了。

 "scripts": {    "dev": "node build/dev-server.js",    "build": "node build/build.js"  }

那么npm run的具体用法是怎样的呢?
语法:

npm run-script <command> [-- <args>...]alias: npm run

来自官方文档的具体用法:

This runs an arbitrary command from a package’s “scripts” object. If no “command” is provided, it will list the available scripts. run[-script] is used by the test, start, restart, and stop commands, but can be called directly, as well. When the scripts in the package are printed out, they’re separated into lifecycle (test, start, restart) and directly-run scripts.
可以运行像上面定义的那样的scripts对象的任何一个命令。如果没有任何命令被指定,它就会列出所有可用的脚本。run[-script]可以用于测试,开始、重启、和结束的命令;也可以直接使用。(这里的生命周期是什么含义?)
也就是说npm run test和npm run start是可以的命令。当然也可以直接用成npm test和npm start这样子的。
也就是说我们定义的任务脚本是有生命周期的。

As of npm@2.0.0, you can use custom arguments when executing scripts. The special option – is used by getopt to delimit the end of the options. npm will pass all the arguments after the – directly to your script:
对于2.0版本以上的npm,你可以使用自定义的参数,–是作为参数的最后的分隔符的。

npm run test – –grep=”pattern”
The arguments will only be passed to the script specified after npm run and not to any pre or post script.
这个参数只会传递给npm
关于node,后续还有更深入的剖析。

常见的loader和作用

Loader 可以理解为是模块和资源的转换器,它本身是一个函数,接受源文件作为参数,返回转换的结果。这样,我们就可以通过 require 来加载任何类型的模块或文件,比如 CoffeeScript、 JSX、 LESS 或图片。
Loader 本身也是运行在 node.js 环境中的 JavaScript 模块,它通常会返回一个函数。大多数情况下,我们通过 npm 来管理 loader,但是你也可以在项目中自己写 loader 模块。

通常在webpack.config.js的module.exports中导出的对象中:
比如css loader

module: {    loaders: [      {test: /\.css$/, loader: 'style-loader!css-loader'}    ]  }

Adds CSS to the DOM by injecting a <style> tag
npm install style-loader –save-dev
style-loader的用法如何?
It’s recommended to combine it with the css-loader: require(“style-loader!css-loader!./file.css”).
add rules in file.css to document
The css-loader interprets @import and url() like import/require() and will resolve them.
Loader 可以通过管道方式链式调用,每个 loader 可以把资源转换成任意格式并传递给下一个 loader ,但是最后一个 loader 必须返回 JavaScript。
loader 一般以 xxx-loader 的方式命名,xxx 代表了这个 loader 要做的转换功能,比如 json-loader。
Loader 可以在 require() 引用模块的时候添加,也可以在 webpack 全局配置中进行绑定,还可以通过命令行的方式使用。

加载 CSS 需要 css-loader 和 style-loader,他们做两件不同的事情,css-loader会遍历 CSS 文件,然后找到 url() 表达式然后处理他们,style-loader 会把原来的 CSS 代码插入页面中的一个 style 标签中。

require(“!style-loader!css-loader!./style.css”)

因为本文要将的是vue.js,所以下面还会仔细分析vue-loader。
在webpack中加入:

{        test: /\.vue$/,        loader: 'vue'      },

而vue-loader的定义:

module.exports = function (content) {  this.cacheable()  var isServer = this.target === 'node'  var isProduction = this.minimize || process.env.NODE_ENV === 'production'  var loaderContext = this  var query = loaderUtils.getOptions(this) || {}  var options = this.options.__vueOptions__ = Object.assign({}, this.options.vue, this.vue, query)  var rawRequest = getRawRequest(this, options.excludedPreLoaders)  var filePath = this.resourcePath  var fileName = path.basename(filePath)  var context = (this._compiler && this._compiler.context) || this.options.context || process.cwd()  var moduleId = 'data-v-' + genId(filePath, context, options.hashKey)  var cssLoaderOptions = ''  if (!isProduction && this.sourceMap && options.cssSourceMap !== false) {    cssLoaderOptions += '?sourceMap'  }  '''   // final export    if (options.esModule) {      output += '\nexports.__esModule = true;\nexports["default"] = Component.exports\n'    } else {      output += '\nmodule.exports = Component.exports\n'    }  } else {    // inject-loader support    output =      '\n/* dependency injection */\n' +      'module.exports = function (injections) {\n' + output + '\n' +      '\nreturn Component.exports\n}'  }  // done  return output}

除此之外,还需要了解的两个loader分别是url-loader和babel-loader.
url-loader的实现源码如下:

    var limit = (this.options && this.options.url && this.options.url.dataUrlLimit) || 0;    if(query.limit) {        limit = parseInt(query.limit, 10);    }    var mimetype = query.mimetype || query.minetype || mime.lookup(this.resourcePath);    if(limit <= 0 || content.length < limit) {        return "module.exports = " + JSON.stringify("data:" + (mimetype ? mimetype + ";" : "") + "base64," + content.toString("base64"));    } else {        var fileLoader = require("file-loader");        return fileLoader.call(this, content);    }}module.exports.raw = true;

作为url-loader的package.json的文件中,就已经有这些依赖了:

 "dependencies": {    "loader-utils": "^1.0.2",    "mime": "1.3.x"  },  "peerDependencies": {    "file-loader": "*"  },

而file-loader的源码是像这样:

var publicPath = "__webpack_public_path__ + " + JSON.stringify(url);    if (config.publicPath !== false) {        // support functions as publicPath to generate them dynamically        publicPath = JSON.stringify(            typeof config.publicPath === "function"            ? config.publicPath(url)            : config.publicPath + url        );    }    if (query.emitFile === undefined || query.emitFile) {        this.emitFile(outputPath, content);    }    return "**module.exports** = " + publicPath + ";";

var url = require(“file-loader!./file.png”);
// => emits file.png as file in the output directory and returns the
public url //
=> returns i. e. “/public-path/0dcbbaa701328a3c262cfd45869e351f.png”

The url loader works like the file loader, but can return a Data Url if the file is smaller than a byte limit.The limit can be specified with a query parameter. (Defaults to no limit,没有限制最好了,最大的文件也会被潜入到网页中)If the file is greater than the limit (in bytes) the file-loader is used and all query parameters (url查询参数)are passed to it.

网页优化的一大首要任务是减少HTTP 请求 (http request) 的次数,例如通过合并多个JS文件,合并CSS样式文件。除此之外,还有一个data URL 的密技,让我们直接把图像的内容崁入网页里面,这个密技的官方名称是 data URI scheme
(哈哈,如果用url-loader的话,我的那个文件请求就能得到正确的格式)(在本地内存中加载)

不然就会报错(变成了相关的请求报错,因为其实就是本地文件而已)

This package allows transpiling JavaScript files using Babel and webpack.

  • babel
    This package allows transpiling JavaScript files using Babel and webpack.Babel是一个广泛使用的转码器,可以将ES6代码转为ES5代码,从而在现有环境执行。你可以现在就用ES6编写程序,而不用担心现有环境是否支持

  • markdown-highlight-loader;

安装

$ npm i -S markdown-highlight-loader

使用npm 安装,出入的参数是i 和-S i代表可能是install -S代表的应该是save…

用法其实很简单:

/*include highlight.js theme styles, for example in "vendor" chunk:entry: {    vendor: [        …        'highlight.js/styles/railscasts.css'    ],    …}*/module: {    loaders: [ {        test: /\.md$/,        loader: 'html!markdown-highlight'        // loader: 'html!markdown-highlight?+breaks&-smartLists'    } ]

hightlight的作用,使得代码高亮

更加简单的,如果不需要代码高亮的,直接使用markdown就好了:

{    module: {        rules: [{                test: /\.md$/,                use: [                    {                        loader: "html-loader"                    },                    {                        loader: "markdown-loader",                        options: {                            /* your options here */                        }                    }                ]            }]    }}

插件系统

Webpack 还有一个功能丰富的插件系统。大多数内容功能都是基于这个插件系统运行的,还可以开发和使用开源的 Webpack 插件,来满足各式各样的需求。
插件可以完成更多loader不能完成的功能。
插件的会用一般是在webpack的配置信息plugins选项中指定。
我们利用一个最简单的 BannerPlugin 内置插件来实践插件的配置和运行,这个插件的作用是给输出的文件头部添加注释信息。

var webpack = require('webpack')module.exports = {  entry: './entry.js',  output: {    path: __dirname,    filename: 'bundle.js'  },  module: {    loaders: [      {test: /\.css$/, loader: 'style-loader!css-loader'}    ]  },  plugins: [    new webpack.BannerPlugin('This file is created by zhaoda')  ]}

再比如第三方插件extract-text-webpack-plugin:Extract text from bundle into a file.

for webpack 2
npm install –save-dev extract-text-webpack-plugin
for webpack 1
npm install –save-dev extract-text-webpack-plugin@1.0.1
const ExtractTextPlugin = require(“extract-text-webpack-plugin”);

module.exports = {
module: {
rules: [
{
test: /.css$/,
use: ExtractTextPlugin.extract({
fallback: “style-loader”,
use: “css-loader”
})
}
]
},
plugins: [
new ExtractTextPlugin(“styles.css”),
]
}这个插件的作用是什么呢?它会将所有通过require("style.css")s的entry块放到一个单一的css文件中去,使得你的styles不再嵌入到JS文件中,如果你的所有的css量很大,这会更快(因为css bundle是并行的导入到js bundle中去的)

node

node涉及到的知识点比较少。

node 模块和应用

  • Node应用由模块组成,采用CommonJS模块规范。根据这个规范,每个文件就是一个模块,有自己的作用域,Node内部提供一个Module构建函数所有模块都是Module的实例。
    module.id 模块的识别符,通常是带有绝对路径的模块文件名。
    module.filename 模块的文件名,带有绝对路径。
    module.loaded 返回一个布尔值,表示模块是否已经完成加载。
    module.parent 返回一个对象,表示调用该模块的模块。
    module.children 返回一个数组,表示该模块要用到的其他模块。
    **module.exports 表示模块对外输出的值。**

    npm做nodejs的包依赖管理,bower做javascript的包依赖管理

  • javascript的import 语句用于导入从外部模块,另一个脚本等导出的函数,对象或原语。

  • 关于默认导出方式,每个模块只有一个默认导出。一个默认导出可以是一个函数,一个类,一个对象等。当最简单导入的时候,这个值是将被认为是”入口”导出值。export default{} 对于只导出一部分的值来说 命名导出的方式很有用。。。在导入时候,可以使用相同的名称来引用对应导出的值。
  • require
    最早的时候,所有Javascript代码都写在一个文件里面,只要加载这一个文件就够了。后来,代码越来越多,一个文件不够了,必须分成多个文件,依次加载。下面的网页代码,相信很多人都见过。
      <script src="1.js"></script>
      <script src="2.js"></script>

     这段代码依次加载多个js文件。
    这样的写法有很大的缺点。首先,加载的时候,浏览器会停止网页渲染,加载文件越多,网页失去响应的时间就会越长;其次,由于js文件之间存在依赖关系,因此必须严格保证加载顺序(比如上例的1.js要在2.js的前面),依赖性最大的模块一定要放到最后加载,当依赖关系很复杂的时候,代码的编写和维护都会变得困难。require.js的诞生,就是为了解决这两个问题。

node核心功能

如果只是在服务器运行JavaScript代码,用处并不大,因为服务器脚本语言已经有很多种了。Node.js的用处在于,它本身还提供了一系列功能模块,与操作系统互动。这些核心的功能模块,不用安装就可以使用,下面是它们的清单。

http:提供HTTP服务器功能
url:解析URL
fs:与文件系统交互。
querystring:解析URL的查询字符串
child_process:新建子进程
util:提供一系列实用小工具
path:处理文件路径(就像上面所提到过的那样)
crypto:提供加密和解密功能,基本上是对OpenSSL的包装

上面这些核心模块,源码都在Node的lib子目录中。为了提高运行速度,它们安装时都会被编译成二进制文件。
核心模块总是最优先加载的。如果你自己写了一个HTTP模块,require(‘http’)加载的还是核心模块。

var path = require('path')var express = require('express')var webpack = require('webpack')

比如上面的path就是nodejs内置的核心功能,express和webpack是第三方的一些模块,功能非常强大,像上面所论述的那样。

node命令的使用

node可以直接写node命令行。
安装完成之后,直接运行 node 命令就可以启动 node.js 提供的命令行。在命令行中可以直接输入 JavaScript 代码并运行。也可以通过 node server.js 的方式来运行一个 JavaScript 文件 server.js 。
比如:

D:\code\trunk\webapps\sysman-web>node> var path = require('path')undefined> path{ resolve: [Function: resolve],  normalize: [Function: normalize],  isAbsolute: [Function: isAbsolute],  join: [Function: join],  relative: [Function: relative],  _makeLong: [Function: _makeLong],  dirname: [Function: dirname],  basename: [Function: basename],  extname: [Function: extname],  format: [Function: format],  parse: [Function: parse],  sep: '\\',  delimiter: ';',  win32: [Circular],  posix:   { resolve: [Function: resolve],     normalize: [Function: normalize],     isAbsolute: [Function: isAbsolute],     join: [Function: join],     relative: [Function: relative],     _makeLong: [Function: _makeLong],     dirname: [Function: dirname],     basename: [Function: basename],     extname: [Function: extname],     format: [Function: format],     parse: [Function: parse],     sep: '/',     delimiter: ':',     win32: [Circular],     posix: [Circular] } }

再比如express就更了不得了:

> var express = require('express')undefined> express{ [Function: createApplication]  application:   { init: [Function: init],     defaultConfiguration: [Function: defaultConfiguration],     lazyrouter: [Function: lazyrouter],     handle: [Function: handle],    。。。  request:   IncomingMessage {     header: [Function: header],     get: [Function: header],   。。。  response:   ServerResponse {     status: [Function: status],     links: [Function],   。。。  Route: [Function: Route],  Router:   { [Function]     param: [Function: param],     handle: [Function: handle],  。。。  query: [Function: query],  static:   { [Function: serveStatic]     mime:      Mime {        types: [Object],        extensions: [Object],        default_type: 'application/octet-stream',        Mime: [Function: Mime],        charsets: [Object] } } }

在 node.js 可以运行的 JavaScript 代码中,可以使用一些全局的对象:process 、用来加载模块的 require() 方法、 __filename 、 __dirname 和与浏览器中相似的用来执行定时任务的 setTimeout() 和 setInterval() 方法等,[具体参考]https://nodejs.org/docs/latest/api/synopsis.html(https://nodejs.org/docs/latest/api/globals.html#globals_dirname)。

node [options] [v8 options] [script.js | -e "script"] [arguments]

process对象是Node的一个全局对象,提供当前Node进程的信息。它可以在脚本的任意位置使用,不必通过require命令加载。

proxy:http-proxy-middleware

用法,比如:

var express = require('express');var proxy = require('http-proxy-middleware');var app = express();app.use('/api', proxy({target: 'http://www.example.org', changeOrigin: true}));app.listen(3000);

这个表示代理/ api请求到http://www.example.org,

var proxy = require('http-proxy-middleware');var apiProxy = proxy('/api', {target: 'http://www.example.org'});//                   \____/   \_____________________________/ //                     |                    | //                   context             options // 'apiProxy' is now ready to be used as middleware in a server. context:确定应将哪些请求代理到目标主机。 (更多关于上下文匹配)options.target:目标主机到代理。 (协议+主机)

ring和compojure

compojure是用作路由作用的。

(GET "/user/:id" [id] (str "hello user " id ""))

routes 返回值为 Ring-handler 函数。
匹配 HTTP 方法 – GET

compojure 定义了一系列 route 宏,包括 POST,PUT,DELETE,OPTIONS,PATCH 和 HEAD。如果要匹配任何一种 HTTP request ,可以使用 ANY。注意:这些宏全部都是大写。

匹配 URI – “/user/:id”

这个字符串用于定义 routing(语法来自于 Clout 模块),很多语法格式同 Ruby on Rails 和 Sinatra 一致。
:id 将匹配 /user/ 后的所有余下部分,结果存入 “id” 参数。
如果 URI 不匹配定义的路径,route 函数将返回 nil。

包管理器 npm

  • –save

    当你为你的模块安装一个依赖模块时,正常情况下你得先安装他们(在模块根目录下npm install
    module-name),然后连同版本号手动将他们添加到模块配置文件package.json中的依赖里(dependencies)。

    -save和save-dev可以省掉你手动修改package.json文件的步骤。 npm install module-name -save 自动把模块和版本号添加到dependencies部分 npm install module-name -save-dev 自动把模块和版本号添加到devdependencies部分

  • package.json
    dependencies部分:字段指定了项目运行所依赖的模块
    devdependencies部分:字段指定了项目开发所依赖的模块

If someone is planning on downloading and using your module in their program, then they probably don’t want or need to download and build the external test or documentation framework that you use.In this case, it’s best to map these additional items in a devDependencies object.
如果有人想下载并使用你的模块,但是他们可能不想或者不需要下载或安装额外的文档框架。就最好使用devDependencies 这个对象。
These things will be installed when doing npm link or npm install from the root of a package, and can be managed like any other npm configuration param. See npm-config for more on the topic.
For build steps that are not platform-specific, such as compiling CoffeeScript or other languages to JavaScript, use the prepare script to do this, and make the required package a devDependency.
这写东西会在安装的时候就用npm安装到package的root下面。

这两者的区别?
npm install 在安装 npm 包时,有两种命令参数可以把它们的信息写入 package.json 文件:

–save
–save-dev
但它的文档里1,只提到一个小区别,–save 会把依赖包名称添加到 package.json 文件 dependencies 键下,–save-dev 则添加到 package.json 文件 devDependencies 键下。
。它们真正的区别是,devDependencies 下列出的模块,是我们开发时用的,比如 grunt-contrib-uglify,我们用它混淆 js 文件,它们不会被部署到生产环境。dependencies 下的模块,则是我们生产环境中需要的依赖。

dependencies配置的依赖是在正常运行(一般为生产环境)该包时必须要的依赖项

什么意思?很简单,就是假设你的包被别人依赖了,那么别人在安装你的包时会自动安装你的包里的dependencies中配置的这些依赖包,也就是说你的包没有这些包就不能正常使用。

devDependencies配置的依赖是你在开发你的包时安装的一些在生产环境非必要的依赖项。

那什么是生产环境非必要的依赖项?比如说:你想使用mocha来测试你的包,那么就可以安装mocha到devDependencies,而不是dependencies,因为他不是生产环境所必须的。依赖你的包的人,是想依赖你的核心代码,而不是需要使用你包里的mocha

CSS /LESS/stylus

Less 是一门 CSS 预处理语言,它扩充了 CSS 语言,增加了诸如变量、混合(mixin)、函数等功能,让 CSS 更易维护、方便制作主题、扩充。

stylus 是一个CSS的预处理框架,2010年产生,来自Node.js社区,主要用来给Node项目进行CSS预处理支持,所以 Stylus 是一种新型语言,可以创建健壮的、动态的、富有表现力的CSS。比较年轻,其本质上做的事情与 SASS/LESS 等类似,应该是有很多借鉴,所以近似脚本的方式去写CSS代码。Stylus默认使用 .styl 的作为文件扩展名,支持多样性的CSS语法。

全局安装:
npm install stylus -g

比如&就是一个非常灵活的用法:

ul    li a        display: block        color: blue        padding: 5px        html.ie &            padding: 6px        &:hover            color: red

编译为css:

ul li a {  display: block;  color: #00f;  padding: 5px;}html.ie ul li a {  padding: 6px;}ul li a:hover {  color: #f00;}

下面具体一点:

就CSS本身而言,对于大多数Web前端从业人员来说就不是问题。学过CSS的人都知道,它不是一种编程语言。你可以用它开发网页样式,但是没法用它编程。换句话说,CSS基本上是设计师的工具,不是程序员的工具。在程序员的眼里,CSS是很头痛的事情,它并不像其它程序语言,比如说PHP、Javascript等等,有自己的变量、常量、条件语句以及一些编程语法,只是一行行单纯的属性描述,写起来相当的费事,而且代码难易组织和维护。

很自然的,有人就开始在想,能不能给CSS像其他程序语言一样,加入一些编程元素,让CSS能像其他程序语言一样可以做一些预定的处理。这样一来,就有了“CSS预处器(CSS
Preprocessor)”。
一、什么是CSS预处器

CSS预处理器定义了一种新的语言,其基本思想是,用一种专门的编程语言,为CSS增加了一些编程的特性,将CSS作为目标生成文件,然后开发者就只要使用这种语言进行编码工作。通俗的说,CSS预处理器用一种专门的编程语言,进行Web页面样式设计,然后再编译成正常的CSS文件,以供项目使用。CSS预处理器为CSS增加一些编程的特性,无需考虑浏览器的兼容性问题,例如你可以在CSS中使用变量、简单的逻辑程序、函数等等在编程语言中的一些基本特性,可以让你的CSS更加简洁、适应性更强、可读性更佳,更易于代码的维护等诸多好处。

CSS预处理器技术已经非常的成熟,而且也涌现出了很多种不同的CSS预处理器语言,比如说:Sass(SCSS)、LESS、Stylus、Turbine、Swithch CSS、CSS Cacheer、DT CSS等。如此之多的CSS预处理器,那么“我应该选择哪种CSS预处理器?”也相应成了最近网上的一大热门话题,在Linkedin、Twitter、CSS-Trick、知呼以及各大技术论坛上,很多人为此争论不休。相比过计我们对是否应该使用CSS预处理器的话题而言,这已经是很大的进步了。

到目前为止,在众多优秀的CSS预处理器语言中就属Sass、LESS和Stylus最优秀,讨论的也多,对比的也多。本文将分别从他们产生的背景、安装、使用语法、异同等几个对比之处向你介绍这三款CSS预处理器语言。相信前端开发工程师会做出自己的选择——我要选择哪款CSS预处理器。

less是2009年的一个开源项目,LESS提供了多种方式能平滑的将写好的代码转化成标准的CSS代码,在很多流行的框架和工具中已经能经常看到LESS的身影了(例如Twitter的Bootstrap框架就使用了LESS著作权归作者所有。
Stylus,2010年产生,来自于Node.js社区,主要用来给Node项目进行CSS预处理支持,在此社区之内有一定支持者,在广泛的意义上人气还完全不如Sass和LESS。

[Stylus]被称为是一种革命性的新语言,提供一个高效、动态、和使用表达方式来生成CSS,以供浏览器使用。Stylus同时支持缩进和CSS常规样式书写规则。

Sass、LESS和Stylus源文件(除了LESS源文件在客户端下运行之外)都不能直接被浏览器直接识别,这样一来,要正常的使用这些源文件,就需要将其源文件转译成浏览器可以识别的CSS样式文件,这也是使用CSS预处理器很关键的一步,如果这一步不知道如何操作,那么意味着写出来的代码不可用著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。
原文: https://www.w3cplus.com/css/css-preprocessor-sass-vs-less-stylus-2.html © w3cplus.com
Stylus的语法花样多一些,它的文件扩展名是“.styl”,Stylus也接受标准的CSS语法,但是他也像Sass老的语法规则,使用缩进控制,同时Stylus也接受不带大括号({})和分号的语法,如下所示:

/style.styl/
/类似于CSS标准语法/
h1 {
color: #963;
background-color:#333;
}
/省略大括号({})/
h1
color: #963;
background-color: #333;
/省略大括号({})和分号(;)/
h1
color:#963
background-color:#333
在Stylus样式中,你也可以在同一个样式文件中使用不同的语法规则,下面这样的写法也不会报错:

/style.styl/
h1 {
color #963
}
h2
font-size:1.2em

小区插曲:
早在90年代中期到后期起草的 CSS1规范中就介绍过!important,它能够帮助开发者和用户在修改样式表的时候轻松覆盖原本的权重。著作权归作者所有。
样式的应用依赖具体的情况,一个更加具体的选择器往往会比一个笼统选择器获得更大的权重。
样式的应用依赖样式出现的顺序(即,后面的会覆盖前面的)
从这个提纲中,你可能已经明白!important会如何改变权重以及它在层叠中扮演一个什么样的角色。接下来让我们看一下!important更多的细节。

举一个例子就可以很好的说明了:

语法和描述!important为开发者提供了一个增加样式权重的方法。应当注意的是!important是对整条样式的声明,包括这个样式的属性和属性值(感谢Brad Czerniak指出其中的差别)。这里有个简单的代码示例可以清晰地说明!important是如何应用于原本的样式中的:#example {  font-size: 14px !important;   }#container #example {  font-size: 10px;}   在上面的代码示例中,由于使用了!importantid为“example”的元素字号将被设置为14px。如果不使用!important,第二个样式声明的代码块很自然地比第一个的权重要大,原因有二:在样式表中第二个代码块要比第一个出现的晚(即,它位列第二);第二个代码块有更大的权重(是由两个id#container #example组合而成,而不是只有一个id#example。但是因为第一个代码块里面包含了!important,所以对于字号设置来说它有更大的权重。

体(@media)
@media工作原理和在常规CSS中一样,但是,要使用Stylus的块状符号。
@media print
#header
#footer
display none
生成为:
@media print {
#header,
#footer {
display: none;
}
}

那么在css中这个@media到底是什么呢?width 媒体属性描述了输出设备渲染区域(如可视区域的宽度或打印机纸盒的宽度)的宽度。

HTML JADE

jade语法:
Tags
默认,每行开始的第一个单词代表一个标签,可以是自定义的标签:

jade:

h1 h1 tag
custom custom tag
img(src=”/images/logo.png”, alt=”“)

使用缩进能进行标签嵌套:jade:ul  li Item A    a(href="javascript:;") a link  li Item B  li Item C
属性必须用括号包起来,多个属性用逗号分隔,classid,可以直接用 (.) 和 (#) 而不需要放到括号内;div.container.flow#container Contenta(class="btn", href="javascript:;", title="submit") Buttonhtml:<div id="container" class="container flow">Content</div><a href="javascript:;" title="submit" class="btn">Button</a>对于 classid, 还可以省略 tag 而直接用,最终会自动生成一个 div:jade:.content content#content.content.box contenthtml:<div class="content">content</div><div id="content" class="content box">content</div>

javascript

  1. Promise 对象用于异步计算,一个 Promise表示一个现在、将来或永不可能可用的值。
  2. -那么,关于lodash的一个用法:
    .defaultsDeep(object, [sources]):This method is like .defaults except that it recursively assigns default properties.比如说:
_.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } });// => { 'a': { 'b': 2, 'c': 3 } }
  1. setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式。

vuejs指令

vuej指令是vue编程中非常灵活的一个因素所在。
v-if指令可以完全根据表达式的值在DOM中生成或移除一个元素。

  • v-if

如果v-if表达式赋值为false,那么对应的元素就会从DOM中移除;否则,对应元素的一个克隆将被重新插入DOM中

<div id="example-2">    <p v-if="greeting">Hello!</p></div><script type="text/javascript">    var exampleVM2 = new Vue({        el: '#example-2',        data: {            greeting: true        }    })</script>

上面这种写法可能是最最正宗的写法,设定一个el ,创建一个vue对象。

  • v-show
    v-show指令是根据表达式的值来显示或者隐藏HTML元素。当v-show赋值为false时,元素被隐藏。查看DOM时,会发现元素上多了一个内联样式style=”display:none”。

    一般来说,v-if有更高的切换消耗,而v-show有更高的初始渲染消耗(可能稍微改变的开销并不大了)。因此,如果需要频繁的切换,则使用v-show较好;如果在运行时条件不大可能改变,则使用v-if较好。

  • v-else
    v-else就是JavaScript中的else的意思,它必须跟着v-if或者v-show使用。
  • v-model
    v-model指令用来在input、select、text、checkbox、radio等表单控件元素上创建双向数据绑定的。根据控件类型v-model**自动选取正确的方法更新元素**。

使用$index来获得相应的数组索引。
v-text指令可以更新元素的textContent.
v-html指令更新元素的innerHTML。
v-bind指令用于响应更新HTML特性,将一个或者多个attribute,或者一个组件prop动态绑定到表达式..

  • v-bind
a v-bind:href="url"></a><!-- 缩写 --><a :href="url"></a>
  • 子组件的绑定
在绑定prop时,prop必须在子组件中声明。可以用修饰符指定不同的绑定类型。修饰符为:.sync——双向绑定,只能用于prop绑定。.once——单次绑定,只能用于prop绑定
  • v-on指令用于绑定事件监听器。事件类型由参数指定。

    如果访问原始DOM事件,可以使用$event传入方法。

    ```<button v-on:click="doThis('hello',$event)"></button> <!--缩写--><!-- 阻止单击事件冒泡 --><a v-on:click.stop="doThis"></a><!-- 提交事件不再重载页面 --><form v-on:submit.prevent="onSubmit"></form>```

    那么什么是单击事件冒泡呢?

在一个对象上触发某类事件(比如单击onclick事件),如果此对象定义了此事件的处理程序,那么此事件就会调用这个处理程序,如果没有定义此事件处理程序或者事件返回true,那么这个事件会向这个对象的父级对象传播,从里到外,直至它被处理(父级对象所有同类事件都将被激活),或者它到达了对象层次的最顶层,即document对象(有些浏览器是window)

自定义指令

  • 那么怎么写自定义指令呢?
    这个问题怎么解决 比如在vue.js 1.0中 http://v1-cn.vuejs.org/guide/custom-directive.html
    除了内置指令,Vue.js 也允许注册自定义指令。自定义指令提供一种机制将数据的变化映射为 DOM 行为。

可以用 Vue.directive(id, definition) 方法注册一个全局自定义指令,它接收两个参数指令 ID 与定义对象。也可以用组件的 directives 选项注册一个局部自定义指令,例子:

<div id="demo" v-demo:hello.a.b="msg"></div>Vue.directive('demo', {  bind: function () {    console.log('demo bound!')  },  update: function (value) {,    this.el.innerHTML =      'name - '       + this.name + '<br>' +      'expression - ' + this.expression + '<br>' +      'argument - '   + this.arg + '<br>' +      'modifiers - '  + JSON.stringify(this.modifiers) + '<br>' +      'value - '      + value  }})var demo = new Vue({  el: '#demo',  data: {    msg: 'hello!'  }})

这下可以回到我在此文开头的时候抛出来的问题了:

一个项目里面使用到一个灵活的jsoneditor,通过调研发现vuejs并没有直接的组件可以用,但是发现javascript有一个很好用的叫做jsoneditor的组件,那么我们如何在一个vue.js的工程里面加入这个jsoneditor?
虽然我首先调研得到的可用的组件是vue-json-tree-view,用法

npm install --save vue-json-tree-viewimport TreeView from "vue-json-tree-view"Vue.use(TreeView)

但是这个组件的功能还是不够完善。
顺便提一句:
Vue.use(plugin)用于安装vuejs的插件,use是Vue提供的一个全局的api,另外类似的api还有set,directive,filter等。
set:

参数:{Object} object{string} key{any} value返回值: 设置的值.用法:设置对象的属性。如果对象是响应式的,确保属性被创建后也是响应式的,同时触发视图更新。这个方法主要用于避开 Vue 不能检测属性被添加的限制。注意对象不能是 Vue 实例,或者 Vue 实例的根数据对象

这是和vue的相应式原理对应的一个api。
受现代 JavaScript 的限制(以及废弃 Object.observe),Vue 不能检测到对象属性的添加或删除。由于 Vue 会在初始化实例时对属性执行 getter/setter 转化过程,所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的。
Vue 不允许在已经创建的实例上动态
Vue.set(vm.someObject, ‘b’, 2)
您还可以使用 vm.setVue.setthis.set(this.someObject,’b’,2)添加新的根级响应式属性(root-level reactive property)。然而它可以使用 Vue.set(object, key, value) 方法将响应属性添加到嵌套的对象上
有时你想向已有对象上添加一些属性,例如使用 Object.assign() 或 _.extend() 方法来添加属性。但是,添加到对象上的新属性不会触发更新。在这种情况下可以创建一个新的对象,让它包含原对象的属性和新的属性:
// 代替 Object.assign(this.someObject, { a: 1, b: 2 })
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
- Vue 异步执行 DOM 更新

vuejs的编程原理和响应式原理

/** * A watcher parses an expression, collects dependencies, * and fires callback when the expression value changes. * This is used for both the $watch() api and directives. * * @param {Vue} vm * @param {String|Function} expOrFn * @param {Function} cb * @param {Object} options *                 - {Array} filters *                 - {Boolean} twoWay *                 - {Boolean} deep *                 - {Boolean} user *                 - {Boolean} sync *                 - {Boolean} lazy *                 - {Function} [preProcess] *                 - {Function} [postProcess] * @constructor */

watcher是用来调动callback函数的(当检测到监测的表达式的值发生变化的时候),可以选择的监控的options参数有:
twoWay
deep
lazy等
就同前面那样描述到的,这个对于$watch() 和指令来说,同样是生效的。

响应式原理就是因为指令和数据有绑定watcher对象。把一个普通的js对象传给Vue实例的data,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter.用户看不到 getter/setter,但是在内部它们让 Vue 追踪依赖,在属性被访问和修改时通知变化。

由于 Vue 会在初始化实例时对属性执行 getter/setter 转化过程,所以属性必须在 data 对象上存在才能让 Vue 转换它,这样才能让它是响应的
.

解决问题

update

当只需要 update 函数时,可以传入一个函数替代定义对象:Vue.directive('my-directive', function (value) {  // 这个函数用作 update()})

使用自定义指令操作dom

在github上面有jsoneditor的使用方法:

   var container = document.getElementById("jsoneditor");        var options = {};        var editor = new JSONEditor(container, options);        // set json        var json = {            "Array": [1, 2, 3],            "Boolean": true,            "Null": null,            "Number": 123,            "Object": {"a": "b", "c": "d"},            "String": "Hello World"        };        editor.set(json);

但是当我在vue.js中想要引入jsoneditor却很为难。就像vue.js是数据响应式那样,vue.js并没有操作dom的能力。所以要怎么办呢?
使用自定义指令可以。它有操作dom的能力!可以使用this.el来表示上面html中的container

import Vue from 'vue'import JSONEditor from "jsoneditor"export default {   update: function(value){    console.log("arg:",this.arg)    var options ={mode: this.arg ,search:true}    var editor = new JSONEditor(**this.el**, options);    editor.set(value.data);  }}

这样创建的指令jsoneditor就可以被用于vue的元素中,比如div(v-jsoneditor)。
这样,基本功能就完成了

深入用法

editor.set(json);editor.expandAll();还有collapse等用法。schema

监听事件 实现双向数据绑定

遇到了一个问题,我觉得可能需要深入了解下dom的事件:
比如input click

schema验证

Ajv: Another JSON Schema ValidatorThe fastest JSON Schema validator for node.js and browser.

那么怎么利用ajv编程呢?
比如:
支持type参数,properties参数等。

var schema = {        "title": "Example Schema",        // "type": "obje",        "properties": {          "type": { "enum": value.schema },          "动作": {"enum": value.schema2 },          'opAction': {"enum":value.ops},          // 'constraints':{          //   '动作': {"enum":value.ops},          // }        },

type keyword requires that the data is of certain type (or some of types). Its value can be a string (the allowed type) or an array of strings (multiple allowed types).
也就是说type可以写一个,也可以写一组。
Type can be: number, integer, string, boolean, array, object or null.

schema: { "type": ["number", "string"] }valid: 1, 1.5, "abc", "1"invalid: [], {}, null, trueAll examples above are JSON schemas that only require data to be of certain type to be valid.

而嵌套的:

{    "$schema": "http://json-schema.org/draft-04/schema#",    "title": "TextLinks",    "description": "文字链接",    "type": "array",    "items": {        "type": "object",        "properties": {            "text": {                "type": "string",                "title": "文字"            },            "href": {                "type": "string",                "title": "链接地址(URL)"            }        }    }}

现在,针对ajv的schema验证问题,又要提出一个深入的问题来解决:

对于一个动态嵌套格式的json串,如果只要里面有一个”op”属性,我就要求这个要满足一个枚举的schema验证,这个怎么用ajv来定义?

这个问题看起来还比较难以解决,需要深入到ajv的深入编程,或许连ajv本身就不提供这个功能。

semantic ui

semantic ui是一个非常好用又漂亮的工具。或许在了解semantic ui之前,需要先了解一个叫做gulp的工具。gulp是用来运行任务的一个工具。
那么gulp可以被用来做什么使用呢?可以用来做自动任务管理工具,那么是否也就相当与后台任务的rundeck呢?gulpfile.js是配置文件

gulp管道又是什么呢?
比如:

项目根目录中的gulpfile.js,是Gulp的配置文件。下面就是一个典型的gulpfile.js文件。var gulp = require('gulp');var uglify = require('gulp-uglify');gulp.task('minify', function () {  gulp.src('js/app.js')    .pipe(uglify())    .pipe(gulp.dest('build'))});上面代码中,gulpfile.js加载gulp和gulp-uglify模块之后,使用gulp模块的task方法指定任务minify。task方法有两个参数,第一个是任务名,第二个是任务函数。在任务函数中,使用gulp模块的src方法,指定所要处理的文件,然后使用pipe方法,将上一步的输出转为当前的输入,进行链式处理。task方法的回调函数使用了两次pipe方法,也就是说做了两种处理。第一种处理是使用gulp-uglify模块,压缩源码;第二种处理是使用gulp模块的dest方法,将上一步的输出写入本地文件,这里是build.js(代码中省略了后缀名js)。执行minify任务时,就在项目目录中执行下面命令就可以了。$ gulp minify从上面的例子中可以看到,gulp充分使用了“管道”思想,就是一个数据流(stream):src方法读入文件产生数据流,dest方法将数据流写入文件,中间是一些中间步骤,每一步都对数据流进行一些处理

gulp和grunt server又有什么区别?

grunt是什么?我曾经在安装elastic search的head的时候用到了这个工具。

为何要用构建工具?
一句话:自动化。对于需要反复重复的任务,例如压缩(minification)、编译、单元测试、linting等,自动化工具可以减轻你的劳动,简化你的工作。当你在 Gruntfile 文件正确配置好了任务,任务运行器就会自动帮你或你的小组完成大部分无聊的工作。

那么可以拿grunt练手了:

假定Grunt CLI已经正确安装,并且已经有一份配置好package.json 和 Gruntfile 文件的项目了,接下来就很容易拿Grunt练手了:将命令行的当前目录转到项目的根目录下。执行npm install命令安装项目依赖的库。执行 grunt 命令。OK,就是这么简单。还可以通过grunt --help 命令列出所有已安装的Grunt任务(task),但是一般更建议去查看项目的文档以获取帮助信息。
Gruntfile.js 或 Gruntfile.coffee 文件是有效的 JavaScript 或 CoffeeScript 文件,应当放在你的项目根目录中,和package.json文件在同一目录层级,并和项目源码一起加入源码管理器。Gruntfile由以下几部分构成:"wrapper" 函数项目与任务配置加载grunt插件和任务自定义任务

这个跟我用node写的某些js的内容(webpack)的作用已经差不多了,不过grunt自有他的作用。
这类的构建工具实在是有太多,目前
这篇文章说到grunt 和gulp基本上是不太必要的工具,有npm scripts就可以了。npm scripts,我在前面说到过的。
这篇文章讲到了这些构建工具之间的区别。

另外browserify,据说可以让浏览器端运行nodejs代码,这里也不去深入了解了。

Semantic UI uses Gulp to provide command line tools for building
themed versions of the library with just the components you need.

也就是说,semantic UI使用Gulp这个工具编译semantic的库。为什么这么说呢,请看:

npm install semantic-ui --savecd semantic/gulp build

Running the gulp build tools will compile CSS and Javascript for use in your project.
当然你也可以使用一些cdn的方式去访问这些css和js文件。比如:

...    <link rel="stylesheet" type="text/css" href="cdn/semantic-ui/2.2.6/semantic.min.css">  </head>  <body>    <div id="app"></div>    <script src="cdn/jquery/3.1.1/jquery.min.js"></script>    <script src="cdn/jqueryui/1.11.4/jquery-ui.min.js"></script>    <script src="cdn/semantic-ui/2.2.6/semantic.min.js"></script>   ...

semantic UI是github上面的一个开源项目,

semantic ui的特点: 50多个UI 元素(element) 3000多个CSS变量 3 Levels of variable
inheritance

比如button
field inputs这些 做出的内容确实就非常漂亮 还有icons

使用主题:
semantic中使用到了12种命名的颜色。有颜色变量的组件

组件默认:
组件继承了site.variables 的默认变量,组件的默认当然可以再指定。

bootstrap也是一个前端UI框架。以及jquery ui

总之,感觉怎么样都说不好semantic ui的用法,但是用起来却真的很简单,基本上在官方文档上可以找到各种用法,包括button,form,divider,container,标题,message,header,table等。不过要用好却不是那么容易。

ag-grid

漂亮又有用的一个表格组件
bulid的方式和semantic ui类似:

npm installnpm install gulp -ggulp or gulp release

Vuejs 设计模式之一– Mixins

这是一种很好的设计模式,

混合是一种灵活的分布式复用 Vue
组件的方式。混合对象可以包含任意组件选项。以组件使用混合对象时,所有混合对象的选项将被混入该组件本身的选项。

// 定义一个混合对象var myMixin = {  created: function () {    this.hello()  },  methods: {    hello: function () {      console.log('hello from mixin!')    }  }}// 定义一个使用混合对象的组件var Component = Vue.extend({  mixins: [myMixin]})var component = new Component() // -> "hello from mixin!"

可以发现这个created选项的自定义函数会在组件创建的时候,说到created选项的时候,这就涉及到vue实例的生命周期了。

vue实例生命周期

vue实例在被创建之前都要经过一系列的初始化过程,比如配置数据观测(data),编辑模版,挂载实例到dom等。实例也可以调用生命周期钩子。现在让我依然疑惑不解的是,那么route和watch是不是生命周期钩子?
不是。
route是监控页面调用的时候执行的一些。
watch是监控到某个值或某些值变化的时候执行的函数

设计模式之一—slot

slot就是vuejs中的插槽。

You build a component like this:<!-- FormHelper.vue --><form class="form">  <h3>{{ title }}</h3>  <slot></slot><!-- children will go here -->  <button>Submit</button></form>And you use the helper like this:<!-- App.vue --><form-helper title="Password Reset">  <input type="text" name="name" value="">  <input type="text" name="email" value=""></form-helper>

以及可命名的slot

!-- FormHelper.vue --><form class="form">  <h3>{{ title }}</h3>  <slot name="help"></slot>  <slot name="elements"></slot><!-- children will go here -->  <slot name="buttons"></slot></form>And here's how you use the same form:<!-- App.vue --><form-helper title="Request Form">  <div slot="help">    Please ask your manager before requesting hardware.  </div>  <div slot="elements">    <input type="text" name="item_name" value="">    <input type="text" name="item_value" value="">  </div>  <div slot="buttons">    <button type="button" name="button">Request</button>  </div></form-helper>

使用slot的主要思想 是 :
怎么看待slots呢?就相当于把组件当作props传给孩子组件一样。就像传递字符串,数字和对象一样,你也可以传递整个sub-dom树。可以使用slot的场景一般是这样考虑的:
子组件用于设计和排版,逻辑结构可以在你使用的地方写上。

http请求和响应

http请求和响应都是用消息作为载体。
http消息头对于理解这些消息非常重要。
比如:
Content-Type的作用
该实体头的作用是让服务器告诉浏览器它发送的数据属于什么文件类型。
比如application/octet-stream,。这个类型主要是用来下载使用。或者未知类型,你可以发现 nginx 默认的 mime-type 就是 octet-stream,这个是无类型的含义。

Content-Disposition 的作用
当Content-Type 的类型为要下载的类型时 , 这个信息头会告诉浏览器这个文件的名字和类型。
常规的HTTP应答中,Content-Disposition 消息头指示回复的内容该以何种形式展示,是以内联的形式(即网页或者页面的一部分),还是以附件的形式下载并保存到本地。
inline就是内联的模式; attachment是附件的模式;attachment; filename=”filename.jpg”这个是以附件的形式并且指定文件名字。

这两个字段对于下载来说是非常有用的。

ring和liberator

Ring is a Clojure web applications library inspired by Python’s WSGI and Ruby’s Rack. By abstracting the details of HTTP into a simple, unified API, Ring allows web applications to be constructed of modular components that can be shared among a variety of applications, web servers, and web frameworks.

ring是一个clojure 脚本语言的web server,就像Python的WSGI那样应用。通过抽象http的具体细节使得web应用程序更方便。

1 0
原创粉丝点击