使用webpack+vue.js构建前端工程化

参考文章:https://blog.csdn.net/qq_40208605/article/details/80661572javascript

使用webpack+vue.js构建前端工程化
本篇主要介绍三块知识点:css

node.jshtml

vue.js前端

webpack前端工程化vue

本篇不是写给零基础的同窗看的,读者应具有一些服务器开发、前端开发基础java

本篇目标
使用webpack+vue.js构建前端工程化本篇目标node.js基本入门node.js介绍环境搭建npm介绍npm淘宝镜像使用cnpm安装包node.js模块化程序结构node.js重要模块(API)介绍node.js全局对象node.js原生模块实现一个用户管理模块vue.js基本入门介绍基本编程模型(模板 + 模型)使用Vue指令定义模板使用Vue定义数据模型经常使用指令介绍组件化开发组件结构实现一个购物车程序使用webpack构建前端工程化webpack介绍整体结构图安装webpack使用webpack重构购物车程序node

node.js基本入门
node.js介绍
node.js可让javascript程序在后端运行起来。咱们以前所熟知的javascript都是运行在前端浏览器,咱们编写好了javascript代码后,由浏览器解释执行。而node.js,可让咱们编写javascript,而后在后端运行起来。如今的javascript和java、python同样,能够操做I/O、操做数据库、或者其余各种操做系统资源。python

 


上面这张图,和下面的这张图很像。能够认为,node.js是javascript的一种跨平台运行在主机的实现。webpack

 

环境搭建
下载node.js (运行环境)web

https://nodejs.org/en/

下载Visual Studio Code(开发环境)

https://code.visualstudio.com/

npm介绍
写过Java的同窗应该都知道,咱们要编写程序每每都须要导入不少其余额外的JAR包(官方的JavaSE包默认提供了)。早期在Maven出现以前,咱们都是须要手动去下载各类框架的JAR包。自从有了Maven以后,咱们再也不须要手动下载了,直接在一个POM.XML文件中引入须要的依赖便可。


在node中,运行一个node程序也会依赖于其余的一些模块。固然node也会自带一些基本模块。那当咱们须要使用这些模块的时候,咱们须要从网络上下载。这个去网上下载很是麻烦。node官方提供了一个管理工具npm,这个工具能够根据须要自动从服务器下载各类包。这就省去了,咱们本身去网上下载包的过程。

npm淘宝镜像
官方的npm在国内速度是比较慢的,可使用淘宝的镜像

npm install -g cnpm --registry=https://registry.npm.taobao.org

安装完成后,就可使用cnpm从淘宝镜像来下载、安装node包

使用cnpm安装包
cnpm install <包的名称>

包的名称能够去https://npm.taobao.org/上搜索

node.js模块化程序结构
每个js文件就是一个模块(json等其实也能够做为一个模块),对应的就是一个module对象。下面这一段程序,表示从外部引入一个模块,而后执行模块中的函数。

var fs = require("fs"); // 引入fs模块

var data = fs.readFileSync('input.txt'); // 调用fs模块中的readFileSync方法

console.log(data.toString());
第一行的, required表示引入一个包,返回的就是module对象。这个fs包,是node自带的包,引入一个包后就能够调用这个包下的方法。可是包中的方法不是均可以被调用的,只有相似:


exports.world = function() {
   console.log('Hello World');
}
这样的代码,才能被调用。更简单来讲,在包中定义的函数都是对外不可见的,要想被外部调用,须要使用exports来定义函数。

 

这个require函数有点相似于C语言中的#include。它首先会从文件cache缓存中查找传入的模块名,若是没有找到再查找原生模块,最后查找文件中加载。

node.js重要模块(API)介绍
node.js全局对象
变量名 注释
__filename 表示当前正在执行的脚本的文件名
__dirname 表示当前执行脚本所在的目录。
console.log 输出日志
node.js原生模块
模块名称 介绍
os模块 获取操做系统相关的信息,例如:获取临时文件夹,获取主机名、获取操做系统名称
http模块 提供了开发服务器后端程序的相关API
path模块 提供了处理文件路径相关的API
net模块 提供了网络编程API
实现一个用户管理模块
建立项目

创建一个空的文件夹用于保存该项目

进入命令提示符,使用npm init初始化项目,结束后会自动生成一个package.json文件,这个文件中包含了项目的全部依赖包,能够把这个package.json文件理解为项目文件

建立客户Service模块


/**
* 客户Service
*/
exports.CustomerService = function() {
   this.customers = [];

   // 添加客户
   this.add = function(cstm) {
       this.customers.push(cstm);
  }

   // 根据客户名字移除
   this.remove = function(name) {
       for(var i = 0; i < this.customers.length; ++i) {
           if(this.customers[i].name === name) {
               this.customers.splice(i, 1);
               break;
          }
      }
  }

   // 获取全部客户
   this.findAll = function() {
       return this.customers;
  }
}
建立入口模块index.js


var customerService = require('./customerService');

var cm = new customerService.CustomerService();
cm.add({name: '小乔', age: 20, sex: '女'});
cm.add({name: '二乔', age: 21, sex: '女'});
cm.add({name: '大乔', age: 22, sex: '女'});

// 查询全部客户
var cstms = cm.findAll();
console.log("---");
console.log(cstms);

// 删除客户
cm.remove("小乔");
console.log("---");
console.log(cm.findAll())
执行node index.js


PS H:\code\nodejs\02> node .\index.js
---
[ { name: '小乔', age: 20, sex: '女' },
{ name: '二乔', age: 21, sex: '女' },
{ name: '大乔', age: 22, sex: '女' } ]
---
[ { name: '二乔', age: 21, sex: '女' },
{ name: '大乔', age: 22, sex: '女' } ]
vue.js基本入门
介绍
Vue是一套前端框架。它实现了前端页面视图(HTML/CSS)和模型数据的分离,并且它提供了快速简单构建组件的方式。让咱们以一种全新的方式来开发前端。

 

基本编程模型(模板 + 模型)
使用Vue指令定义模板

<div id="app">
   <span>
      {{name}}
   </span>
</div>
使用Vue定义数据模型

var app2 = new Vue({
   el: '#app',
   data: { // 定义模型数据
       name: 'Hello, Tom!'
  },
   method: { // 定义绑定数据方法
       sayHello: function() {
           alert('hello!');
      }
  }
})
经常使用指令介绍
指令 用途
{{模型名称}} 插值,绑定模型数据(单向绑定)
v-bind:标签属性,能够缩写为:标签属性 绑定模型数据到HTML标签的属性
v-if 条件判断
v-for="item in list" foreach循环
v-on:click,能够缩写为@click 绑定用户事件
v-model 绑定表单数据
指令.修饰符 .number(将输入的数据转换为数字)、.trim(去除输入的数据后面的空格)
详细语法参见:https://cn.vuejs.org/v2/guide/

组件化开发
在前端开发中引入组件化是一个大的进步。其实,若是咱们用过一些UI框架就会知道,大多数的UI框架都定义了不少的组件,例如:button按钮、datagrid表格组件、tree树形组件、dialog对话框组件等等。可是,以前咱们都是使用别人给咱们开发好的框架。咱们今天要学习如何使用Vue来开发一个本身的组件。未来,咱们能够本身开发一套本身的组件库,而后使用这些组件库来构建咱们的前端应用程序。

组件结构
能够把组件理解为就是一个小的页面视图。使用Vue开发的组件也分为两个部分:

视图模板

属性(模型数据)

视图模板依旧是使用HTML/CSS+Vue指令,可是模型数据如今跟以前不太同样,模型数据应该是使用组件的时候,动态传入进来的。因此,模型数据须要先定义出来。

 

实现一个购物车程序

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <meta http-equiv="X-UA-Compatible" content="ie=edge">
   <title>购物车</title>
   <link rel="stylesheet" href="./bootstrap/css/bootstrap.css">
</head>
<body>
   <div id="app" class="container">
       <h1>购物车</h1>
       <hr>
       <btn-grp :buttons="buttons"></btn-grp>
       <btn-grp :buttons="buttons_test"></btn-grp>
       <btn-grp :buttons="buttons"></btn-grp>
       <btn-grp :buttons="buttons_test"></btn-grp>
       <br>
       <br>
       <table class="table table-bordered table-striped table-hover">
           <tr>
               <th>ID</th>
               <th>商品名称</th>
               <th>商品价格</th>
               <th>商品数量</th>
               <th>商品总价</th>
           </tr>
           <tr v-for="(prod, index) in products">
               <td>{{index+1}}</td>
               <td>{{prod.name}}</td>
               <td>{{prod.price}}</td>
               <td>
                   <button @click="changeCount(prod, -1)">-</button>
                   <input type="text" v-model="prod.count">
                   <button @click="changeCount(prod, 1)">+</button>
               </td>
               <td>{{prod.price * prod.count}}</td>
           </tr>
           <tr>
               <td colspan="4" class="text-right">总价:</td>
               <td class="text-primary">{{getTotalMoney()}}</td>
           </tr>
       </table>
   </div>
   <script src="./vue.js"></script>
   <script>
       // 自定义组件,这里实现了一个按钮组组件
       Vue.component('btn-grp', {
           props: ['buttons'],
           template:
               '<div class="btn-group" role="group">'
                   + '<button type="button" @click="btn.handler" v-for="btn in buttons" :class="\'btn \' + (btn.class == null || btn.class == \'\' ? \'btn-default\':btn.class)">'
                       + '{{btn.title}}'
                   + '</button>'
               + '</div>'
      });

       var app = new Vue({
           el: '#app',
           data: {
               // 按钮组件测试
               buttons_test: [
                  {title: '测试1', class: 'btn-danger'},{title: '测试2'},{title: '测试3'},{title: '测试4'},
              ],
               buttons: [{
                   title: '添加',
                   class: 'btn-primary',
                   handler: function() {
                       alert('点击添加按钮');
                  }
              }, {
                   title: '修改',
                   class: 'btn-default',
                   handler: function() {
                       alert('点击修改按钮');
                  }
              }, {
                   title: '删除',
                   class: 'btn-default',
                   handler: function() {
                       alert('点击删除按钮');
                  }
              }, ],
               products: [
                  {
                       name: '小米6S',
                       price: 3999,
                       count: 1,
                  },
                  {
                       name: '锤子2',
                       price: 4999,
                       count: 1,
                  },
                  {
                       name: '华为P20',
                       price: 3599,
                       count: 1,
                  },
                  {
                       name: 'OPPO R15',
                       price: 2999,
                       count: 1,
                  },
                  {
                       name: 'OPPO R11',
                       price: 1999,
                       count: 1,
                  },
              ],
          },
           methods: {
               // 用户点击加减数量时调用
               changeCount: function(prod, num) {
                   if(num < 0) {
                       if(prod.count > 0) {
                           prod.count += num;
                      }
                  }
                   else {
                       prod.count += num;
                  }
              },
               // 获取总金额
               getTotalMoney: function() {
                   var totalMoney = 0.0;

                   for(var i = 0; i < this.products.length; ++i) {
                       totalMoney += parseFloat(this.products[i].price * this.products[i].count);
                  }

                   return totalMoney;
              }
          }
      });
   </script>
</body>
</html>
效果图

 

使用webpack构建前端工程化
webpack介绍
webpack是一个前端项目构建工具。使用webpack能够把前端当成一个工程来开发。并且可以很好地把前端的各种资源统一管理、编译、打包。

它是一个“编译器”,能够经过各类插件将基于node.js、sass、less编写代码编译成可以运行在前端浏览器的javascript、和css

它是一个打包工具,能够将全部前端的资源打包到一个bundle.js中

有了webpack,咱们能够像开发后端应用同样开发前端。

整体结构图


webpack是基于node.js开发的一款应用,其实webpack就是一个node.js的模块。

 

安装webpack
建立一个空的文件夹

使用npm init建立package.json

安装cnpm淘宝镜像

使用cnpm install vue-cli -g全局安装vue-cli模块

使用vue init webpack cart建立基于webpack购物车项目

使用cnpm install bootstrap --save安装bootstrap模块

具体步骤请参考:https://www.webpackjs.com/guides/installation/

使用webpack重构购物车程序
使用vue-cli生成项目脚手架以下图:

 

将原来编写的btn-grp组件单独编写到BtnGrp.vue文件中

能够看到如今代码清晰了不少,template标签部分编写模板,script标签部分编写组件的交互代码,编写方式和原先写在HTML的代码一致

如今整个前端应用都是基于组件化的,代码变得更加清晰了


<template>
 <div class="btn-group" role="group">
     <button :key="btn.title"
       type="button" @click="btn.handler"
       v-for="btn in buttons"
       :class="'btn ' + (btn.class == null || btn.class == '' ? 'btn-outline-secondary':btn.class)">
        {{btn.title}}
     </button>
 </div>
</template>

<script>
export default {
 props: ['buttons']
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
</style>

将原来写在HTML中的代码重构到App.vue中

此处由于须要用到BtnGrp组件,因此须要先import 组件,而后在components中引用该组件


<template>
   <div id="app" class="container">
       <h1>WEBPACK + VUE&nbsp;实现购物车</h1>
       <BtnGrp :buttons="buttons"></BtnGrp>
       <br/>
       <br/>
       <table class="table table-bordered table-striped table-hover">
           <tr>
               <th>ID</th>
               <th>商品名称</th>
               <th>商品价格</th>
               <th>商品数量</th>
               <th>商品总价</th>
           </tr>
           <tr :key="index+1" v-for="(prod, index) in products">
               <td>{{index+1}}</td>
               <td>{{prod.name}}</td>
               <td>{{prod.price}}</td>
               <td>
                   <button class="btn btn-outline-info btn-sm" @click="changeCount(prod, -1)">-</button>
                   <input style="width:50px" type="text" v-model="prod.count">
                   <button class="btn btn-outline-info btn-sm" @click="changeCount(prod, 1)">+</button>
               </td>
               <td>{{prod.price * prod.count}}</td>
           </tr>
           <tr>
               <td colspan="4" class="text-right">总价:</td>
               <td class="text-primary">{{getTotalMoney()}}</td>
           </tr>
       </table>
   </div>
</template>

<script>
/* eslint-disable no-new */
import 'bootstrap/dist/css/bootstrap.min.css'
import BtnGrp from './components/BtnGrp'

export default {
 name: 'App',
 components: {BtnGrp},
 data () {
   return {
     products: [
      {
           name: '小米6S',
           price: 3999,
           count: 1,
      },
      {
           name: '锤子2',
           price: 4999,
           count: 1,
      },
      {
           name: '华为P20',
           price: 3599,
           count: 1,
      },
      {
           name: 'OPPO R15',
           price: 2999,
           count: 1,
      },
      {
           name: 'OPPO R11',
           price: 1999,
           count: 1,
      },
    ],
     buttons: [{
         title: '添加',
         class: 'btn-outline-primary',
         handler: function() {
             alert('点击添加按钮');
        }
    }, {
         title: '修改',
         class: 'btn-outline-primary',
         handler: function() {
             alert('点击修改按钮');
        }
    }, {
         title: '删除',
         class: 'btn-outline-danger',
         handler: function() {
             alert('点击删除按钮');
        }
    }, ],
     changeCount: function(prod, num) {
         if(num < 0) {
             if(prod.count > 0) {
                 prod.count += num;
            }
        }
         else {
             prod.count += num;
        }
    },
     getTotalMoney: function() {
         var totalMoney = 0.0;

         for(var i = 0; i < this.products.length; ++i) {
             totalMoney += parseFloat(this.products[i].price * this.products[i].count);
        }

         return totalMoney;
    }
  }
}
}
</script>

<style>
#app {
 font-family: 'Avenir', Helvetica, Arial, sans-serif;
 -webkit-font-smoothing: antialiased;
 -moz-osx-font-smoothing: grayscale;
 text-align: center;
 color: #2c3e50;
 margin-top: 60px;
}
</style>
由于npm安装的bootstrap是bootstrap4,因此稍微对原先的样式调整了下。最终的效果图以下:

 

.

相关文章
相关标签/搜索