Vue.js随学随记

1. v-bind和v-model理解

1.1 v-bind

v-bind代表元素的某个属性交给vue处理,实现元素属性和vue的绑定,v-bind="表达式",引号里面的本质是表达式。但是这种绑定是单向的。比如下面的代码,当你在网页中修改input中值的时候,上面的message内容不会随着修改。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <script type="text/javascript" src="vue.js"></script>
    </head>
    <body>
        <div id="app">
            <div>{{message}}</div>
            <div>
                <input type="text" v-bind:value="message"/>
            </div>
        </div>

        <script type="text/javascript">
            var vm = new Vue({
                el:"#app",
                data:{
                    message:"Welcome to Vue"
                }
            });
        </script>
    </body>
</html>

如果想实现双向绑定,还需要向下方一样为标签添加v-on指令,这样在修改input里面内容的时候,上面message的内容也会相应的修改。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <script type="text/javascript" src="vue.js"></script>
    </head>
    <body>
        <div id="app">
            <div>{{message}}</div>
            <div>
                <input type="text" v-on:input="message = $event.target.value" v-bind:value="message"/>
            </div>
        </div>
        <script type="text/javascript">
            var vm = new Vue({
                el:"#app",
                data:{
                    message:"Welcome to Vue"
                }
            });
        </script>
    </body>
</html>

1.2 v-model

v-model实际上是v-bind:和v-on:的语法糖,实现了简易的元素属性双向绑定。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <script type="text/javascript" src="vue.js"></script>
    </head>
    <body>
        <div id="app">
            <div>{{message}}</div>
            <div>
                <input type="text" v-model="message"/>
                <!--上方代码等同于下方代码
                <input type="text" v-on:input="message = $event.target.value" v-bind:value="message"/>
                -->
            </div>
        </div>
        <script type="text/javascript">
            var vm = new Vue({
                el:"#app",
                data:{
                    message:"Welcome to Vue"
                }
            });
        </script>
    </body>
</html>

2. v-on:click 事件调用函数的问题。

2.1 方法一:直接调用函数名

<button v-on:click="change">改变一下</button>

这种情况下,函数被调用时,自动传递$event参数。

2.2 方法二:调用函数名()

这种情况下,函数被调用时,不会自动传递$event参数,如果需要,则必须人工指定为函数名($event)。也就是说下面的代码等同于上面的代码:

<button v-on:click="change($event)">改变一下</button>

3. v-if和v-show的区别。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <script type="text/javascript" src="vue.js"></script>
    </head>
    <body>
        <div id="app">
            <button type="button" v-if="isShowButton">使用v-if判断</button>
            <button type="button" v-show="isShowButton">使用v-show判断</button>
        </div>
        <script type="text/javascript">
            var vm = new Vue({
                el:"#app",
                data:{
                    isShowButton:false
                }
            });
        </script>
    </body>
</html>

运行结果如下:
file

  • 对于v-if,如果=后面的表达式是false,则整个标签不会显示。
  • 对于v-show,如果=后面的表达式是false,则会以display:none的形式隐藏标签。

4. v-for对数组和对象的使用方法。

4.1 示例代码

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <script type="text/javascript" src="vue.js"></script>
    </head>
    <body>
        <div id="app">
            <table border="1" cellspacing="0" cellpadding="0">
                <tr><th>姓名</th><th>性别</th><th>分数</th></tr>
                <tr v-for="student,arrayIndex in students">
                    <td v-for="value,key,objectIndex in student">{{arrayIndex}} - {{objectIndex}} - {{key}} - {{value}}</td>
                </tr>
            </table>
        </div>
        <script type="text/javascript">
            var vm = new Vue({
                el:"#app",
                data:{
                    students:[
                        {name:"张三",gender:"男",score:"100"},
                        {name:"李四",gender:"女",score:"88"},
                        {name:"王五",gender:"男",score:"99"}
                    ]
                }
            });
        </script>
    </body>
</html>

运行结果如下:
file

4.2 对于数组

<tr v-for="student,arrayIndex in students">
</tr>

遍历students数组的每一个元素。

4.3 对于对象

<td v-for="value,key,objectIndex in student">{{arrayIndex}} - {{objectIndex}} - {{key}} - {{value}}</td>

遍历student对象的每一个属性。

5. Vue-cli 3.0 的使用

5.0 理解Vue-cli的关键点

vue-cli是将Node.js和webpack封装进了vue-cli内部。

5.1 安装Vue-cli 3.0

cnpm install -g @vue/cli

需要注意的是,如果之前安装过Vue-cli的2.X版本,需要先卸载之前的版本再安装。卸载方法在安装Vue-cli 3.0的时候有提示,这里不赘述。

5.2 创建项目

安装完Vue-cli 3.0工具后,我们在命令行里面就可以直接使用vue命令了,下面的命令用于创建一个Vue.js的项目框架:

vue create 项目名

这里面有几个注意点:

  1. vue create 项目名命令只对Vue-cli 3.0及以后版本有效,2.X版本无法使用vue create命令
  2. 运行这个命令后,会自动在cmd当前目录下创建【项目名】文件夹,然后在里面生成Vue.js的项目框架。
  3. 这里要特别解释下“脚手架”这个词。初次学Vue.js的时候,对“脚手架”工具特别不理解,不明白啥叫脚手架。说白了,“脚手架”就是辅助工具。Vue-cli的作用就是辅助进行大型的Vue.js项目开发。如果只是在项目中一般性的使用Vue.js,在网页中使用script引入Vue.js文件就够了,不是必须使用Vue-cli脚手架工具。
  4. 项目创建好后,项目的目录结构如下:
    file
    从上面的截图能看出来,其实vue create命令创建的是个node.js项目。其目的和原因也很简单:通过Node.js模拟服务器运行及热更新环境,这样可以让开发过程更加简单、高效。所以,如果要使用Vue-cli工具,前提是机器中必须提前安装了Node.js(如果不使用Vue-cli工具而是只用Vue.js,可以没有Node.js环境)。

5.3 构建项目

既然vue create项目创建的是Node.js项目,那么当时用npm run命令的时候,就可以直接调用package.json里面<script>标签下的三个命令。

5.1.1 serve命令:开发环境构建
npm run serve

这一步最主要的操作是通过Node.js启动一个Web服务器,这样可以直接在本地模拟服务器环境。

5.1.2 build命令:生产环境构建
npm run build

运行这个命令后,会在项目根目录生成一个【dist】文件夹,这里面的文件是经过编译、打包、压缩后,最终用于部署到服务器上的代码。
实际上,这个操作是webpack做的,vue-cli只是把webpack封装进去了。。

5.1.3 lint命令:代码检查工具
npm run lint

6 vue-router路由库使用

6.1 关于SPA

vue-router路由一般使用在SPA(Single Page Application)单页面程序上。SPA的简单的来说就是无论程序有多复杂,所有程序代码都写在一个页面上。
当然,在开发阶段,SPA项目开始分模块开发的,开发完毕后会通过构建工具将各类模块组成一个单页面程序。
SPA的有点有很多,比如:一次加载后,页面无需再跳转和下载新内容,页面速度快;再比如:有效降低网页被复制和爬取的风险。缺点也很明显,搜索引擎索引起来不是很好。不过SPA程序一开始就不是为搜索引擎而设计的。

6.2 vue-router

vue-router是vue.js的官方路由工具。第三方路由如Page.js、Director也很好用,与vue.js的集成也比较容易。

6.3 vue-router的安装

cnpm install vue-router --save

或者直接下载vue-router.js导入到项目中。

6.4 vue-router的使用

6.4.1 HTML代码
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>

<div id="app">
  <h1>Hello App!</h1>
  <p>
    <!-- 使用 router-link 组件来导航. -->
    <!-- 通过传入 `to` 属性指定链接. -->
    <!-- <router-link> 默认会被渲染成一个 `<a>` 标签 -->
    <router-link to="/foo">Go to Foo</router-link>
    <router-link to="/bar">Go to Bar</router-link>
  </p>
  <!-- 路由出口 -->
  <!-- 路由匹配到的组件将渲染在这里 -->
  <router-view></router-view>
</div>
6.4.2 Javascript代码
// 0. 如果使用模块化机制编程,导入 Vue 和 VueRouter,要调用 Vue.use(VueRouter)

// 1. 定义(路由)组件。
// 可以从其他文件 import 进来
const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }

// 2. 定义路由
// 每个路由应该映射一个组件。 其中"component" 可以是
// 通过 Vue.extend() 创建的组件构造器,
// 或者,只是一个组件配置对象。
// 我们晚点再讨论嵌套路由。
const routes = [
  { path: '/foo', component: Foo },
  { path: '/bar', component: Bar }
]

// 3. 创建 router 实例,然后传 `routes` 配置
// 你还可以传别的配置参数, 不过先这么简单着吧。
const router = new VueRouter({
  routes // (缩写)相当于 routes: routes
})

// 4. 创建和挂载根实例。
// 记得要通过 router 配置参数注入路由,
// 从而让整个应用都有路由功能
const app = new Vue({
  router
}).$mount('#app')

// 现在,应用已经启动了!

当然,上面代码也可以稍微简化一下:

const Foo = { template: '<div>foo</div>' }
const Bar = { template: '<div>bar</div>' }

const router = new VueRouter({
  routes = [
    { path: '/foo', component: Foo },
    { path: '/bar', component: Bar }
  ]
})

const app = new Vue({
  router
}).$mount('#app')

Node.js随学随记

0. Node.js动态文件编译的问题

在一切开始之前,先要明白一点:Node.js虽然使用Javascript语言编写,但是他的运行机制和Java、C++等编译型语言类似。也就是说,使用Node.js编写的代码如果要正常运行,是先要经历一个类似编译的过程的。
Node.js的这种运行机制所直接引发的结果就是:

  1. Node.js比普通Javascript运行速度要快。是否比Java和C++快我不清楚,但是至少应该比PHP快(因为PHP是解释性语言)。
  2. Node.js代码再修改后,必须重新运行node XXX.js命令后才能生效。

1. 利用NPM

npm有几个比较重要的命令:install,uninstall,init,run

1.1 install

带参数的install

当项目需要添加一个新的包的时候,使用npm install 包名称 --参数的形式,这时有四种安装方式可能:

npm install 包名称             //安装到当前cmd所在目录,不将包的依赖关系写入package.json文件
npm install 包名称 --save      //安装到当前cmd所在目录,将包的依赖关系写入package.json的dependencies节点
npm install 包名称 --save-dev  //安装到当前cmd所在目录,不将包的依赖关系写入package.json的devDependencies节点
npm install 包名称 -g          //安装到全局目录下,不将包的依赖关系写入package.json文件,且安装的这个包全局可用。

所以呢,对于Node.js使用的工具类包,比如:查询Node.js对ES6的支持度,使用--g是比较合适的,因为你肯定不希望每次使用这个工具的时候还要特意的将cmd目录切换到安装目录下。
而对于Node.js项目中使用的第三方类库比如express等,使用--save是比较合适的。因为这个类库只对当前项目有效。

不带参数的install

上面提到了,如果使用npm install 包名称 --save命令,会将安装的包的信息添加到package.json文件中。
package.json可以通过npm init命令创建,也可以在第一次使用npm install 包名称 --save命令的时候创建。
package.json文件有四个比较重要的节点信息:dependencies、devDependencies、script、main。

  • dependencies
    你的Node.js项目可能会通过npm install 包名称 --save命令安装很多包,当你把你的项目给别人的时候,你不需要把这些安装的包文件发给他们,因为你的这个包信息都写在了dependencies节点下面,拿到你项目文件的人只需要在项目目录中运行npm install,就可以安装所有package.json的dependencies节点下面的包了。这就极大的提升了项目和系统移植的便捷性。
  • devDependencies
    和dependencies节点的功能类似,只不过devDependencies节点下面的包只在你开发的时候有效,换句话说这些包是你在开发的时候临时用的。
  • script
    在项目目录中使用npm run 命令的时候,运行的实际上就是script节点下预先定义好的命令。
  • main
    指定整个Node.js项目的入口文件。

1.2 uninstall

卸载安装的包,如果这个包存在于package.json文件的dependencies节点中,相关信息将会被移除。

1.3 init

初始化一个新的Node.js项目,自动生成package.json文件架构。

1.4 run

npm run 命令
运行package.jsons文件cript节点下预先定义好的命令

2. events事件模块

events模块只提供了一个对象:events.EventEmitter。EventEmitter的核心就是事件触发事件监听

var events = require('events');   //引入events模块
var emitter = new events.EventEmitter();    //新建EventEmitter对象
emitter.on('someEvent', function(arg1, arg2) { 
    console.log('listener1', arg1, arg2); 
}); //事件监听
emitter.on('someEvent', function(arg1, arg2) { 
    console.log('listener2', arg1, arg2); 
}); //事件监听
emitter.emit('someEvent', 'byvoid', 1991); //事件触发。一个事件触发可以对应多个事件监听

3. fs文件系统模块

3.1 fs模块概述

Node.js 文件系统(fs 模块)模块中的方法均有异步和同步版本,例如读取文件内容的函数有异步的 fs.readFile() 和同步的 fs.readFileSync()。
异步的方法函数最后一个参数为回调函数,回调函数的第一个参数包含了错误信息(error)。
建议大家使用异步方法,比起同步,异步方法性能更高,速度更快,而且没有阻塞。

3.2 readFile,writeFile

读取和写入文件,适用于读取和写入数据量不大的情况。如果读取写入数据量很大,建议使用后面的stream相关函数。

var fs = require("fs");
// 读取文件
fs.readFile('input.txt', function (err, data) {
   if (err) {
       return console.error(err);
   }
   console.log("读取: " + data.toString());
});
// 写入文件
fs.writeFile('input.txt', '我是通 过fs.writeFile写入文件的内容',  function(err) {
   if (err) {
       return console.error(err);
   }
   console.log("数据写入成功!");
});

3.3 createReadStream,createWriteStream,pipe

对于大型文件的输入输出,使用stream相关函数。这样可以将大文件切分为小的块通过stream进行传输。
先看数据读取:

var fs = require("fs");
var data = '';
// 创建可读流
var readerStream = fs.createReadStream('video.mp4');
// 数据读取进行时
readerStream.on('data', function(chunk) {
   console.log(chunk);//这里面打印的就是buffer信息。
});
// 数据读取结束时
readerStream.on('end',function(){
   console.log("程序执行完毕");
});
// 数据读取出错时
readerStream.on('error', function(err){
   console.log(err.stack);
});

再看数据输出

var fs = require("fs");

var readerStream = fs.createReadStream('video.mp4');
var writerStream = fs.createWriteStream('video-bk.mp4');

readerStream.on('data', function(chunk) {
   writerStream.write(chunk);
});

pipe直接对接输入输出流

上面的输出代码可以通过pipe简化为:

var fs = require("fs");

var readerStream = fs.createReadStream('video.mp4');
var writerStream = fs.createWriteStream('video-bk.mp4');

readerStream.pipe(writerStream);

4. http和https模块

4.1 创建http服务器。

//server.js
const http = require('http');

const hostname = '127.0.0.1';
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});
//在cmd下运行node server.js即可。

4.2 爬取网页内容

http继承于stream类,所以其监听事件与stream很像。
如果是http网站。

const http = require('http');
http.get("http://www.royotech.com",function(response){
    var html = "";
    response.on("data", function(data){
        html = html + data;
    });
    response.on("end", function(data){
        console.log("网页爬取结束");
        console.log(html); 
    });
});

如果是https网站。

const http = require('http');
http.get("https://www.sina.com",function(response){
    var html = "";
    response.on("data", function(data){
        html = html + data;
    });
    response.on("end", function(data){
        console.log("网页爬取结束");
        console.log(html); 
    });
});

5. cheerio模块

该模块可以用来分析html代码。

const http = require('http');
const cheerio = require('cheerio');

http.get("http://www.royotech.com",function(response){
    var html = "";
    response.on("data", function(data){
        html = html + data;
    });
    response.on("end", function(data){
        console.log("网页爬取结束");
        const $ = cheerio.load(html);
        let linksSet = $('a');
        for(let i=0; i<linksSet.length; i++){
            let url = linksSet[i].attribs.href;
            if(url && url.search("http") != -1)
                console.log(url);
        }
    });
});

6. express框架

express框架本质上是基于Node.js的web相关模块进行的封装。

6.1 使用express框架搭建一个web服务器。

const express = require("express");
const app = express();
app.listen(3030,function(err){
    if(err){
        console.log(err);
        return;
    } else {
        console.log("服务器已经启动,请访问http://localhost:3030");
    }
});
app.get("/",function(request,response){
    response.send("这里是首页");
 });

cmd下运行node index.js后访问:http://localhost:3030/

6.2 express的get方法。

const express = require("express");
const app = express();
app.listen(3030,function(err){
    if(err){
        console.log(err);
        return;
    } else {
        console.log("服务器已经启动,请访问http://localhost:3030");
    }
});
app.get("/",function(request,response){
    response.send(`这里是首页!<br/>
    你可以<a href="http://localhost:3030/get_username/">点我</a>进入get_username页面,或者直接在浏览器上输入"http://localhost:3030/get_username/"访问
    `);
 });
app.get("/get_username",function(request,response){
   response.send({
       name:"张三",
       sex:"男"
   });
});

cmd下运行node index.js后访问:http://localhost:3030/

6.3 express的post方法。

//根目录下index.js文件
const express = require("express");
const app = express();
app.listen(3030,function(err){
    if(err){
        console.log(err);
        return;
    } else {
        console.log("服务器已经启动,请访问http://localhost:3030");
    }
});

const bodyParser = require("body-parser");
app.use(bodyParser.json());//分析提交上来的数据,将数据转换为json后挂在到request的body属性上。
// 创建 application/x-www-form-urlencoded 编码解析
var urlencodedParser = bodyParser.urlencoded({ extended: false });
app.post("/doRegister", urlencodedParser, function(request,response){
    response.send({
        username:request.body.username,
        password:request.body.password
    });
});

根目录下register.html文件的内容如下:

<html>
    <head>
        <title>注册页面</title>
    </head>
    <body>
        <div>
            <form action="/doRegister" method="post">
                用户名:<input name="username" type="text">
                密码:<input name="password" type="password">
                <input type="submit" value="注册提交">
            </form>
        </div>
    </body>
</html>

6.4 使用express.static来设置静态文件。

加入我们在项目根目录中建立一个public文件夹,里面增加两个静态文件:

  • admin.html
  • flower.png
    admin.html的内容如下:

    <html>
    <head>
        <title>Hello Index</title>
    </head>
    <body>
        你好!绝对路径下的花朵
        <img src="/flower.png">
        <hr/>
        你好!相对路径下的花朵
        <img src="./flower.png">
    </body>
    </html>

    再在根目录创建index.js文件,代码如下:

    const express = require("express");
    const app = express();
    app.listen(3030,function(err){
    if(err){
        console.log(err);
        return;
    } else {
        console.log("服务器已经启动,请访问http://localhost:3030");
    }
    });
    app.use(express.static(__dirname + "/public"));

    cmd下运行node index.js后,浏览器中访问http://localhost:3030/admin.html 的结果如下:
    file

这里要表达的是:
当某个文件夹A使用express.static设置为静态文件存储目录后,无论之前文件夹A所处的实际目录在什么位置,被设置后的A文件夹都被视为网站的根目录,对应的A文件夹下面的所有文件都被视为在网站根目录下,且文件类型都是静态文件。

6.5 配合axios实现Ajax功能。

//index.js
const express = require("express");
const app = express();
app.listen(3030,function(err){
    if(err){
        console.log(err);
        return;
    } else {
        console.log("服务器已经启动,请访问http://localhost:3030");
    }
});
app.use(express.static(__dirname + "/public"));

app.get("/get_username",function(request,response){
   response.send({
       name:"张三",
       sex:"男"
   });
});
<!--index.html-->
<html>
    <head>
        <title>Hello Index</title>
        <script src="https://cdn.bootcss.com/axios/0.19.0/axios.min.js"></script>
        <script>
                function getUserName(){
                    axios.get("./get_username").then(function(result){
                        document.getElementById("user_name").innerHTML = result.data.name;
                    });
                }
        </script>
    </head>
    <body>
        这里是网站首页
        <button onClick="getUserName()">获取用户名,通过Ajax请求</button>
        <div id="user_name"></div>
    </body>
</html>

6.6 使用Express的Router路由

const express = require("express");
const app = express();
app.listen(3030,function(err){
    if(err){
        console.log(err);
        return;
    } else {
        console.log("服务器已经启动,请访问http://localhost:3030");
    }
});
app.use(express.static(__dirname + "/public"));

const userRouter = express.Router();
const genderRouter = express.Router();
userRouter.get("/",function(request,response){
    response.send({
        name:"张三",
    });
 });
 genderRouter.get("/",function(request,response){
    response.send({
        gender:"男",
    });
 });
app.use("/get_username",userRouter);
app.use("/get_gender",genderRouter);

// //等同于下面的代码
// app.get("/get_username",function(request,response){
//    response.send({
//        name:"张三",
//    });
// });

// app.get("/get_gender",function(request,response){
//     response.send({
//         gender:"男",
//     });
//  });

7. Node.js连接MongoDB数据库

7.1 安装mongodb模块。

cmd切换到工作目录,然后:

cnpm install mongodb --save

7.2 连接数据库代码

//数据库名:product
//集合名:product_info
const mongodb = require("mongodb");
const mongoClient = mongodb.MongoClient;
var DB_CONN_STR = "mongodb://localhost:27017";
mongoClient.connect(DB_CONN_STR,function(err,client){
    if(err){
        console.log(err);
    } else {
        console.log("数据库连接成功!");
    }
    client.db("product").collection("product_info").find({}).toArray(function(err,result){
        if(err){
            console.log(err);
        } else {
            console.log(result);
        }
    });
    client.close();
});

彻底搞懂npm -g,npm -save,npm -save-dev

1. 回顾 npm install 命令

最近在写Node程序的时候,突然对 npm install 的-save和-save-dev 这两个参数的使用比较混乱。其实博主在这之前对这两个参数的理解也是模糊的,各种查资料和实践后对它们之间的异同点略有理解。遂写下这篇文章避免自己忘记,同时也给node猿友一点指引。

我们在使用 npm install 安装模块的模块的时候 ,一般会使用下面这几种命令形式:

npm install moduleName # 安装模块到项目目录下

npm install -g moduleName # -g 的意思是将模块安装到全局,具体安装到磁盘哪个位置,要看 npm config prefix 的位置。

npm install -save moduleName # -save 的意思是将模块安装到项目目录下,并在package.json文件的dependencies节点写入依赖。

npm install -save-dev moduleName # -save-dev 的意思是将模块安装到项目目录下,并在package.json文件的devDependencies节点写入依赖。

那么问题来了,在项目中我们应该使用四个命令中的哪个呢?这个就要视情况而定了。下面对这四个命令进行对比,看完后你就不再这么问了。

2. npm install moduleName 命令

  1. 安装模块到项目node_modules目录下。
  2. 不会将模块依赖写入package.json的devDependencies或dependencies节点。
  3. 运行 npm install 初始化项目时不会下载模块。

3. npm install -g moduleName 命令

  1. 安装模块到全局,不会在项目node_modules目录中保存模块包。
  2. 不会将模块依赖写入package.json的devDependencies或dependencies 节点。
  3. 运行 npm install 初始化项目时不会下载模块。

4. npm install -save moduleName 命令

  1. 安装模块到项目node_modules目录下。
  2. 将模块依赖写入package.json的dependencies节点。
  3. 运行 npm install 初始化项目时,会将模块下载到项目目录下。
  4. 运行npm install --production或者注明NODE_ENV变量值为production时,会自动下载模块到node_modules目录中。

5. npm install -save-dev moduleName 命令

  1. 安装模块到项目node_modules目录下。
  2. 将模块依赖写入package.json的devDependencies节点。
  3. 运行 npm install 初始化项目时,会将模块下载到项目目录下。
  4. 运行npm install --production或者注明NODE_ENV变量值为production时,不会自动下载模块到node_modules目录中。

6. 总结

devDependencies 节点下的模块是我们在开发时需要用的,比如项目中使用的 gulp ,压缩css、js的模块。这些模块在我们的项目部署后是不需要的,所以我们可以使用 -save-dev 的形式安装。像 express 这些模块是项目运行必备的,应该安装在 dependencies 节点下,所以我们应该使用 -save 的形式安装。

本文转自:https://www.limitcode.com/detail/59a15b1a69e95702e0780249.html

ECMAScript6随学随记

1.let

ES6新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。
可以简单的理解为,var声明的是全局变量,let声明的局部变量。

function f1() {
    var n = 5;
    if (true) {
      var n = 10;
    }
    console.log(n);
  }
  f1();//输出结果为10

  function f2() {
    var n = 5;
    if (true) {
      let n = 10;
    }
    console.log(n);
  }
  f2();//输出结果为5

2. const

const声明一个只读的常量。一旦声明,常量的值就不能改变。
这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。

但对于复合类型的变量,变量名不指向数据,而是指向数据所在的地址。const命令只是保证变量名指向的地址不变,并不保证该地址的数据不变,所以将一个对象声明为常量必须非常小心。

3. 模板字符串

传统的JavaScript语言,输出模板通常是这样写的($('#xxx')是JQuery语法)。

$('#result').append(
  'There are <b>' + basket.count + '</b> ' +
  'items in your basket, ' +
  '<em>' + basket.onSale +
  '</em> are on sale!'
);

上面这种写法相当繁琐不方便,ES6引入了模板字符串解决这个问题。

$('#result').append(`
  There are <b>${basket.count}</b> items
   in your basket, <em>${basket.onSale}</em>
  are on sale!
`);

模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。

// 普通单行字符串
`In JavaScript '\n' is a line-feed.`

// 多行字符串
`In JavaScript this is
 not legal.`

console.log(`string text line 1
string text line 2`);

// 字符串中嵌入变量
var name = "Bob";
var time = "today";

//模板字符串中嵌入变量,需要将变量名写在${}之中。
var nameTime = `Hello ${name}, how are you ${time}?`;
console.log(nameTime);//输出:Hello Bob, how are you today?

//大括号内部可以放入任意的JavaScript表达式,可以进行运算,以及引用对象属性。
var x = 1;
var y = 2;
`${x} + ${y} = ${x + y}`// "1 + 2 = 3"
`${x} + ${y * 2} = ${x + y * 2}`// "1 + 4 = 5"
var obj = {x: 1, y: 2};
`${obj.x + obj.y}`// 3

//模板字符串之中还能调用函数。
function fn() {
  return "Hello World";
}
`foo ${fn()} bar`// foo Hello World bar

4. 标签模板

模板字符串的功能,不仅仅是上面这些。它可以紧跟在一个函数名后面,该函数将被调用来处理这个模板字符串。这被称为“标签模板”功能(tagged template)。

alert`123`
// 等同于
alert(123)

“标签模板”的一个重要应用,就是过滤HTML字符串,防止用户输入恶意内容。

var sender = '<script>alert("abc")</script>'; // 恶意代码
var message = SaferHTML`<p>${sender} has sent you a message.</p>`;//SaferHTML是个自定义函数。

console.log(message);// <p><script>alert("abc")</script> has sent you a message.</p>

5. 对象扩展

ES6允许在对象之中,只写属性名,不写属性值。这时,属性值等于属性名所代表的变量。下面是另一个例子。

function f(x, y) {
  return {x, y};
}
// 等同于
function f(x, y) {
  return {x: x, y: y};
}
f(1, 2) // Object {x: 1, y: 2}

6. Module

6.1 解决Javascript的模块化问题。

早期的Javascript,最让人头痛的就是js代码无法互相引用的问题。这对于大型项目而言就像噩梦一般。
ES6原生了代码引用功能,从根本上解决了js代码模块化的问题。

6.2 export和import语法。

6.2.1 使用export暴露模块。
// profile.js
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
function v1() { ... }
export {
  firstName,
  lastName,
  year,
  v1 as streamV1,
};
6.2.2 使用export default暴露模块
export default function foo() {
  console.log('foo');
}
//等同于
function foo() {
  console.log('foo');
}
export default foo;

每个模块只能有一个export default

6.2.3 使用import使用模块。
// 使用export default输出
export default function crc32() {
  // ...
}
// 针对export default的输入语法
import anyName from 'crc32';

// 使用普通export输出
export function crc32() {
  // ...
};
// 针对普通export的输入语法
import {crc32} from 'crc32';

上面代码的两组写法,第一组是使用export default时,对应的import语句不需要使用大括号;第二组是不使用export default时,对应的import语句需要使用大括号。

export default命令用于指定模块的默认输出。显然,一个模块只能有一个默认输出,因此export deault命令只能使用一次。所以,import命令后面才不用加大括号,因为只可能对应一个方法。

本质上,export default就是输出一个叫做default的变量或方法,然后系统允许你为它取任意名字。

6.4 ECMAScript6和CommonJS在模块化上的区别

参考:https://www.w3cschool.cn/ecmascript/ueqp1q5g.html

6.4.1 Node.js不支持ES6的模块语法

做这个比较主要是由于Node.js不支持ES6的import和export功能导致的。说来也奇怪,Node.js已经支持了92%的ES6语法,唯独对ES6这个最重要的模块功能不支持。这一点可以通过安装ES-Checker模块来查看Node.js对ES6的支持:

$ npm install -g es-checker
$ es-checker

结果如下:
file

6.4.2 Node.js使用CommonJS解决模块问题

在Node.js中默认集成了CommonJS,所以一般都用CommonJS来实现模块的输入输出。
CommonJS的模块语法是使用require和exports。
exports示例如下:

//  ./utils/util.js
var textHello = "Hello World!";

function addFun(a,b){
    return a+b;
}
function sayHello(){
    return "Say Hello!";
}

//完整写法:module.exports.在外面被引用的名字 = 模块内的名字
module.exports.textHello = textHello;
//简写:exports.在外面被引用的名字 = 模块内的名字
exports.addFun = addFun;
//在外面被引用的名字和模块内的名字可以不一样
exports.sayH = sayHello;

//上面三个export语句等同于下面一句
module.exports = {
    textHello:textHello,    //完整写法 - 在外面被引用的名字:模块内的名字
    addFun,                 //简写 - 在外面被引用的名字和模块内的名字相同,可以只写一个
    sayH:sayHello           //如在外面被引用的名字与模块内的名字不同,则必须用:方式
}

require示例如下:

// main.js
moduleUtil = require("./utils/util");
console.log(moduleUtil.textHello);
console.log(moduleUtil.addFun(2,3));
console.log(moduleUtil.sayH());
/*以上三行输出:
Hello World!
5
Say Hello!
*/

当然,如果你必须要在Node.js中使用ES6原生的import和export也是可以的,前提是必须借助Babel这类的转换器。

6.4.3 两者的区别

ES6模块加载的机制,与CommonJS模块完全不同。CommonJS模块输出的是一个值的拷贝,而ES6模块输出的是值的引用。

CommonJS模块输出的是被输出值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。

ES6模块的运行机制与CommonJS不一样,它遇到模块加载命令import时,不会去执行模块,而是只生成一个动态的只读引用。等到真的需要用到时,再到模块里面去取值,换句话说,ES6的输入有点像Unix系统的“符号连接”,原始值变了,import输入的值也会跟着变。

7. 属性和方法的简写

var name = "Tom";
var app = {
    name = name,
    run:function(){
        console.log(`${name} is running!`);
    }
}

等同于:

var name = "Tom";
var app = {
    name, //前提是属性名和属性值相同
    run(){
        console.log(`${name} is running!`);
    }
}

8. 箭头函数

箭头函数可以理解为是对匿名函数的一种缩写。但是与匿名函数不同的是,箭头函数里面的this指向的是上下文。

8.1 极简示例。

function (x) {
    return x * x;
}

等同于

(x)=>{return x * x;}

8.2 另一个示例。

setTimeout(function(){
    console.log("Hello!There!");
},1000);

等同于

setTimeout(()=>{
    console.log("Hello!There2!");
},1000);

通过Vue-cli创建Vue项目流程

0 .Vue.js,Vue-cli,Node.js的理解。

一个js文件就是Vue.js

项目中,通过<script>标签引入一个vue.js文件,这就是我们理解的Vue.js。

命令行里运行vue就是Vue-cli

如果想要在cmd里面运行vue命令,那么就需要安装vue-cli工具。

Node.js就是Javascript的JVM

Node.js就好像是Javascript世界里面的JVM。
vue-cli工具是通过npm的安装的。

1. 安装Node.js

Node.js环境具体安装方法见:http://www.moonlightgate.com/archives/278

2. 安装vue-cli

vue-cli在vue官网上叫做“脚手架工具”,其实就是个vue的客户端(client)。安装命令如下:

npm install -g vue-cli  //这是npm命令

3. 基于webpack-simple初始化项目

当然,你可以不基于webpack-simple初始化项目,通过vue list命令可以看到,有以下几种初始化方式备选:
file
通过命令行切换到你的项目创建目录,运行如下命名:

vue init webpack-simple my-project //这是vue命令

这时,基于webpack-simple创建的项目就建好了。

4. 安装相关的依赖。

第三步只是创建了项目骨架,在你实际运行这个项目前,还需要根据自动生成的package.json文件,安装相关的依赖,安装依赖命令如下:

cd my-project //先进到项目目录。
npm install //或者cnpm install,这是npm命令

5. 运行项目

npm run dev //这也是npm命令,npm run命令将会运行项目中的package.json文件中的script部分内容。run后面跟dev,就是运行package.json文件中script部分的dev部分内容。

什么是Node.js?在CentOS8下和Windows10下安装Node.js详细步骤

1. 什么是Node.js

1.1 百度解释

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。 Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型。
Node 是一个让 JavaScript 运行在服务端的开发平台,它让 JavaScript 成为与 等服务端语言平起平坐的脚本语言。

1.2 简单理解

之前我们提到服务器端脚本语言,都会说PHP、Python、Perl、Ruby等。然后有一天,有个程序员安耐不住寂寞,想要把Javascript也运行在服务器端,然后Node.js就诞生了。

2. 为什么要用Node.js

Node.js当初火爆的最直接原因是其非阻塞式I/O的工作机制。

阻塞式

比如我们来看一段PHP代码:

<?php
echo "开始执行函数superFunction";
superFuncion("这个程序要运行很久");
echo "函数执行完毕,开始执行第二个函数helloWorld";
helloWorld("我只是想问个好!");
?>

在上面的代码中,superFunction()这个函数如果要运行很久的话,无论后面的helloWorld()函数的任务多么简单,都必须等待superFunction()函数执行完毕后才可以运行。换句话说,superFunction()函数把后面的的任务都阻塞了。

非阻塞式

我们再来看一段Node.js代码:

var fs = require("fs");
fs.readFile('input.txt', function (err, data) {
    if (err) return console.error(err);
    console.log(data.toString());
});
console.log("程序执行结束!");

上面程序中,我们不需要等待文件读取完,这样就可以在读取文件时同时执行接下来的代码,大大提高了程序的性能。

高流量、高并发

由于阻塞是按顺序执行的,而非阻塞是不需要按顺序的。所以Node.js的这种非阻塞机制已经被应用于目前很多高并发、高流量的大型网站的后端上。

3. “Node.js”好还是“PHP们”好

这其实是个伪命题!
在Node.js出现前,不是有“PHP、Python、Perl、Ruby哪个好?”这样的讨论吗?最终有结果吗?—没有。人家四门语言任然都活的好好的!
所以不要纠结于Node.js是否好用,是否有前途的问题。记住以下几点就好了:

  1. 如果你是PHP、Python、Perl、Ruby程序员,可以仍然坚持自己的主线技术,把其用到极致。Node.js可以作为扩充知识面的技术,学习了解下。这样真用到的时候,不至于过于陌生。
  2. Node.js与其它服务器端技术没有谁更好的问题,只有谁更合适的问题。

4. Node.js和npm

4.1 npm

npm是Node Package Manager的简称,是Node.js的包依赖管理工具。类似JAVA的MAVEN和PHP的Composer。
Node项目中如果要引入某个包或者库,都是先通过NPM安装到本地,然后再引用即可。

4.2 全局安装和本地安装

npm 的包安装分为本地安装(local)、全局安装(global)两种,从敲的命令行来看,差别只是有没有-g而已,比如:

npm install express          # 本地安装
npm install express -g       # 全局安装

A. 本地安装

  1. 将安装包放在 ./node_modules 下(运行 npm 命令时所在的目录),如果没有 node_modules 目录,会在当前执行 npm 命令的目录下生成 node_modules 目录。
  2. 可以通过 require() 来引入本地安装的包。

B. 全局安装

  1. 将安装包放在node的安装目录或node指定的目录中。
  2. 可以直接在命令行里使用。

5. Node.js在Windows10下的安装

5.1 下载安装文件

Node.js官网:https://nodejs.org
我下载的版本是:node-v12.15.0-x64.msi
下载链接:https://nodejs.org/dist/v12.15.0/node-v12.15.0-x64.msi

5.2 安装

Windows下的安装和普通软件安装过程一样,非常简单:
file
安装完毕后,进入cmd,用以下命令分别查看下Node.js和NPM的版本号:

node -v
npm -v

5.3 配置

其实截止到上一步,Node.js已经安装完成了,但是为了后期使用的方便,我们最好配置一下npm在安装全局模块时(4.2.B)的路径和缓存cache的路径。因为如果配置,那么在执行例如npm install webpack -g等命令全局安装的时候,默认会将模块安装在C:\Users\用户名\AppData\Roaming路径下的npm和npm_cache中,不方便管理且占用C盘空间,所以这里配置自定义的全局模块安装目录。

  1. 在node.js安装目录下新建两个文件夹node_globalnode_cache
  2. 在cmd命令下执行如下两个命令:
    npm config set prefix "D:\Program Files\nodejs\node_global"
    npm config set cache "D:\Program Files\nodejs\node_cache"
  3. 配置环境变量:
    • “环境变量” -> “系统变量”:新建一个变量名为 “NODE_PATH”, 值为“D:\Program Files\nodejs\node_global”
    • “环境变量” -> “用户变量”:编辑用户变量里的Path,将相应npm的路径(“C:\Users\用户名\AppData\Roaming\npm”)改为:“D:\Program Files\nodejs\node_global”
  4. 测试npm
    安装npm(npm的china版,用的淘宝镜像,国内访问速度快)测试一下,在cmd里面运行:

    npm install cnpm -g

    安装完成后,在刚刚新建的两个文件夹node_globalnode_cache下面,会出现相应的文件。

5.4 运行第一个Node.js服务器

在你自己的工作目录下建一个app.js文件,内容如下:

const http = require('http');

const hostname = '127.0.0.1';
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

在cmd中,用node命令运行这个文件:

node app.js

file

这时,打开浏览器在地址栏输入:http://127.0.0.1:3000/看到Hello World就代表成功了!

file

6. Node.js在CentOS8下的安装(方法一)

6.1 下载源代码包至/usr/local/tmp

wget https://nodejs.org/dist/v12.15.0/node-v12.15.0.tar.gz

6.2 解压

tar zxvf node-v12.15.0.tar.gz

6.3 安装前置环境

Node.js的运行需要Python2,如果CentOS8中默认没有安装,需要先安装:

yum install python2 //安装python2

6.4 编译安装

cd node-v12.15.0
./configure --prefix=/usr/local/node/12.15.0
make
make install

7. Node.js在CentOS8下的安装(方法二)

7.1 下载编译好的二进制包至/usr/local/tmp

wget https://nodejs.org/dist/v12.15.0/node-v12.15.0-linux-x64.tar.xz

7.2 解压、移动

tar xvf node-v12.15.0-linux-x64.tar.xz
mv node-v12.15.0-linux-x64 /usr/local/node

7.3 创建node和npm的软连接

ln -s /usr/local/node/bin/node /usr/bin/node
ln -s /usr/local/node/bin/npm /usr/bin/npm

7.4 设置node环境变量

vim /etc/profile

增加以下两行:

export NODE_HOME=/usr/local/node
export PATH=NODE_HOME/bin:$PATH

source使生效:

source /etc/profile

7.5 npm测试

同样以安装npm作为测试:

npm install cnpm -g

/usr/local/node/lib/node_modules目录下出现cnpm目录代表安装成功。

7.6 node测试

在你自己的工作目录下建一个app.js文件,内容如下:

const http = require('http');

const hostname = '0.0.0.0';
const port = 3000;

const server = http.createServer((req, res) => {
  res.statusCode = 200;
  res.setHeader('Content-Type', 'text/plain');
  res.end('Hello World');
});

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`);
});

在bash中,用node命令运行这个文件:

node app.js

关掉CentOS8防火墙,或者放行3000端口,你就可以在外网访问了。

划重点

上面代码和在Windows中的代码有些不一样,hostname地址改为了'0.0.0.0'。
在Window中,我们是通过本机访问,而CentOS8安装在虚拟机中,实际上是通过外网访问,所以如果写'127.0.0.1'的话外网会访问不到。