袁凤鸣的博客 | Fleeming's Blog Front-end Dev Engineer

Vue2.0+Node.js+MongoDB全栈打造商城系统(5—6章)

2017-10-11
袁凤鸣
vue

Vue2.0+Node.js+MongoDB全栈打造商城系统(5—6章)

用前端技术开发的商城整站
项目已部署上线,你可抢先体验:http://imooc.51purse.com/
收费项目介绍:http://coding.imooc.com/class/113.html

第5章 ES6常用语法

5-1 ES6简介

5-2 ES6常用命令

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ES6Demo演示</title>
  <style>
    .log {
      background-color: black;
      color: white;
      padding: 10px 20px;
    }
  </style>
</head>
<body>
  <h2>ES6Demo演示</h2>
  <div id="log" class="log"></div>

  <script>
    //模板语言
    var str = `
    console.log("a"+a);
    var a = 1;
    console.log("b"+b);
    let b = 2;
    ------------------
    function user() {
      var a = 1;
    }
    console.log("a"+a);
    var a = 1;
    -------------------
    //块级作用域
    {
      let a = 1;
      var b = 2;
    }

    console.log("b:"+b);
    console.log("a:"+a); //errorr
    ---------------------
     let a  = 1;
    a = 2;
    const  b = 2 ;
//    b  = 3;  //error ES6.html?_ijt=f1b25lpo249eskl9mi7gbhji:46 Uncaught TypeError: Assignment to constant variable.
    ------------------------
    const  c = {d:1};
    c.d = 2;
    c.e = 3;
//    c = {f:1}; // error
    -------------
    // 模板语言  可以直接拼接 字符串和变量
//    let  userName = "Jack";
//    printLog(\`I'm $删除这5字{userName}\`);  //中文是分割作用看时自己删除
    --------------
    function es5(flag) {
      if (flag) {
        return " es5 true";
      }else {
        return "es5 error";
      }
    }
    console.log(es5());
    // ES6默认参数  开发中可以进行容错处理
    function es6(num1, num2 =4) {
      return num1 + num2;
    }
    console.log(es6(7)); //结果11 即使少传了一个参数也不会报错
    ---------------------------------
    //箭头函数演示
    var  arr = [3, 6, 9];
    //遍历数组 以前写法
    var  newArr = arr.map(function (item) {
      return item + 2;
    })
    console.log(newArr);

    // ES6箭头函数 遍历数组  当表达式只有一行时可以 直接=>接表达式。否则要用{}包着
    var  newArr1 = arr.map((item)=>item+2);
    console.log("newArr1:"+ newArr1);

    `;
    printLog(str);
    //数组的解构
    var [a,b,c] = [3,8,10]; //数组的分解

    var [x,y,z] = "Vue";  //字符串的分解
    console.log(`x:${x},y:${y},z:${z}`);

    var {m,n} = {m:3,n:4};  //对象的解构,对key进行拆分 (m和n的顺序不同也可以)
    console.log(`m:${m},n:${n}`);

    //函数解构
    function sum([x,y]) {
      return x + y;
    }

    var  total = sum([2,8]);
    console.log(`total:${total}`);
    
    function printLog(str) {
      document.getElementById("log").innerText = str;
    }
  </script>

</body>
</html>

注意:

  • const 声明的普通变量将会是常量,它的值不能改变,如果用 const 声明一个对象类型,那么他的指针或者说是内存地址是常量,具体的属性值可以改变
  • 模板语言用的不是单引号‘ ’,而是esc下面的反引号 `
  • {} 块级作用域。var 有变量提升的作用;let 没有变量提升的作用 是块级变量;var 函数级作用域,在函数中有效; let const 块级作用域,大括号中有效,不提升, const 定义常量,就不可以修改。 const 声明的内存中的数据不能修改,基本数据,则值不可改变,对象,则指向的对象不可改变。 var 会造成内存泄漏,建议使用let声明变量。 模板语言中输出变量名 ·膜拜语言+${变量名}· 膜拜语言可以不可以引入函数结果 声明函数的默认参数。
  • ES6 的写法
    • 自定义函数 xxx() {...}
    • 回调函数 (parameter)=> {...}
  • 非ES6的写法
    • 自定义函数 function xxx() {...}
    • 回调函数 function (parameter) {...}

5-3 拓展参数讲解

demo/ES6-2.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>ES6-2Demo演示</title>

</head>
<body>
  <h2>ES6-2Demo演示</h2>
  <script>
    function sum(x,y,z) {
      let total = 0;
      if (x) total += x;
      if (y) total += y;
      if (z) total += z;
      console.log(`total:${total}`);
    }
    sum(2,"",8);

    function sum2(...m) { //动态参数三个点
      let total2 = 0;
      for (var i of m) {
        total2 += i;
      }
      console.log(`total2:${total2}`);  //total2:12
    }
    sum2(2,2,4,4);

    //ES6写法
    let  sum3 = (...m)=>{
      let total2 = 0;
      for (var i of m) {
        total2 += i;
      }
      console.log(`total3:${total2}`); //total3:12
    };
    sum3(2,2,4,4);

    //数组扩展
    var [x,y] = [4,8];
    console.log(...[4,7]); //4 7

    var arr1 = [1,3]; var arr2 = [4,5];
    console.log("concat:"+arr1.concat(arr2)); //concat:1,3,4,5
    console.log("concat2:"+[...arr1,...arr2]); //concat2:1,3,4,5

    var [e,...f] = [2,3,4,5];
    console.log("f:"+f); //f:3,4,5

    let [a,b,c] = "ES6";
    console.log(`a:${a},b:${b},c:${c}`); //a:E,b:S,c:6

    let xy = [..."ES6"];
    console.log(`xy:${xy}`);//xy:E,S,6
  </script>
</body>
</html>

注意:

  • …运算符
    • 1) …和参数一起代表动态参数,不确定传参个数可使用…代替;
    • 2) …和数组一起,会拆解数组成每单个元素;
    • 3) …三个点和数组一起解构,将代表动态数组;
    • 4) …和字符串一起,将拆解字符串
  • …进行数据合并 var sum=[...arr1,...arr2]
  • 数组的遍历另一种方式是通过 of 语法 例子: for(var i of array){}javafor each等价

5-4 Promise讲解

demo/Promise.js:

let checkLogin = function () {
  return new Promise(function (resolve,reject) {
    let  falg = document.cookie.indexOf("userId")> -1? true: false;
    if (falg = true) {
      resolve({
        satatus:0,
        result:true
      })
    }else  {
      reject("error");
    }
  })
};

let getUserInfo = ()=>{
  return new Promise((resolve,reject)=>{
    let  userInfo = {
      userId: "101"
    }
    resolve(userInfo);
  });
};

checkLogin().then((res)=>{
  if (res.satatus == 0) {
    console.log("login success")
    return getUserInfo();
  }
}).catch((error)=>{
  console.log(`errs:${error}`)
}).then((res2)=>{
  console.log(`userId:${res2.userId}`); //userId:101
})

Promise.all([checkLogin(),getUserInfo()]).then(([res1,res2])=>{
  console.log(`res1:${res1.satatus} ; res2:${res2.userId}`); //res1:0 ; res2:101

})

直接写在 HTML 中会报错 ES6 语法错误,故采取引用js文件:
Promise.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Promise</title>
    <script src="Promise.js"></script>
</head>
<body>
</body>
</html>

5-5 ES6模块化开发讲解

代码演示 import 和 export

main.js:

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import {router} from './router' //等同于下面一行
// import {router} from {router:router}

// import {sum,minus} from './util' //或者如下 minus和sum封装在util中
import * as util from './util'

Vue.config.productionTip = false

//切换到工作空间。 cnpm run dev
// console.log(`sum:${sum(1,7)}`); //sum:8
// console.log(`minus:${minus(8,1)}`); //minus:7  //或者如下
console.log(`sum:${util.sum(1,7)}`); //sum:8
console.log(`minus:${util.minus(8,1)}`); //minus:7

/* eslint-disable no-new */
new Vue({
  // el: '#app',
  router,
  template: '<App/>',
  components: { App }
  // render: function (h) {
  //   return h(App);
  // }  //等同于上面两行
}).$mount("#app"); // .$mount("#app")挂载 和 el:的效果是一样的

util.js:

export let sum = (x,y)=> {
  return x + y;
}

export let minus = (m,n)=> {
  return m - n;
}

说明:

  • 三种挂载方式:
    • 1)通过el属性设置挂载对象选择器
    • 2)通过$mount('选择器')挂载
    • 3)通过底层封装的render方法
  • export let router = new Router({XXXXX})

      import {router} from './router' //等同于下面一行
      // import {router} from {router:router}
    
  • 在使用过程中可以通过import函数进行异步加载js文件。 实际上import并不是异步加载,是按需加载,通过import可以实现按需加载。如:import(文件地址)

优秀问答:

  • 问: 想问一下为什么我们在<script>中使用export default呢,比如

      export default {
          props: {
      ......
    

    这样,一个子组件肯定是包括前面的template的,那为什么不从template前面开始export default,而是在<script>下开始export default

    • 答: 这个问题问得很好,但是你忽略了一个问题,这是一个.vue文件,不是一个js文件,这种格式Vuees6根本不认识,它需要通过Vue-loader进行加载解析,实际上Vue loader底层会按照你说的格式进行封装,最后扔给Vue解析。

5-6 AMD、CMD、CommonJS和ES6差异




  • AMD:requirejs在推广过程中对模块定义的规范化产出(异步模块) 特点:依赖前置,异步
  • CMD:seajs在推广过程中对模块定义的规范化产出(同步模块) 特点:依赖就近,在什么时候使用就在时候时候引入
  • Commonjs:nodejs在推广过程中对模块定义的规范

第6章 商品列表模块实现

6-1 商品列表组件拆分

<template>
	<div>
    <nav-header></nav-header>
    <nav-bread>
      <span>Goods</span>
    </nav-bread>
    <div class="accessory-result-page accessory-page">
      <div class="container">
        <div class="filter-nav">
          <span class="sortby">Sort by:</span>
          <a href="javascript:void(0)" class="default cur">Default</a>
          <a href="javascript:void(0)" class="price">Price <svg class="icon icon-arrow-short"><use xlink:href="#icon-arrow-short"></use></svg></a>
          <a href="javascript:void(0)" class="filterby stopPop">Filter by</a>
        </div>
        <div class="accessory-result">
          <!-- filter -->
          <div class="filter stopPop" id="filter">
            <dl class="filter-price">
              <dt>Price:</dt>
              <dd><a href="javascript:void(0)">All</a></dd>
              <dd>
                <a href="javascript:void(0)">0 - 100</a>
              </dd>

            </dl>
          </div>

          <!-- search result accessories list -->
          <div class="accessory-list-wrap">
            <div class="accessory-list col-4">
              <ul>
                <li>
                  <div class="pic">
                    <a href="#"><img src="static/1.jpg" alt=""></a>
                  </div>
                  <div class="main">
                    <div class="name">XX</div>
                    <div class="price">999</div>
                    <div class="btn-area">
                      <a href="javascript:;" class="btn btn--m">加入购物车</a>
                    </div>
                  </div>
                </li>

              </ul>
            </div>
          </div>
        </div>
      </div>
    </div>
    <nav-footer></nav-footer>
	</div>
</template>

<style >
</style>

<script >
  import './../assets/css/base.css'
  import './../assets/css/product.css'
  import NavHeader from './NavHeader.vue'
  import NavFooter from './NavFooter.vue'
  import NavBread from './NavBread.vue'

  export default {
		data (){
			return {
				msg:'hello Vue!'
			}
		},
    components:{
		  NavHeader,
      NavFooter,
      NavBread
    }
	}
</script>

说明:

  • 组件拆分: 将主项目拆分成多个组件:NavBread.vueNavFooter.vueNavHeader.vue

    其中的类似 <nav-header></nav-header>就是引用组件

  • assets里面的静态资源往往作用于组件,而static则考虑资源本身。比如assets里面的img通过webpack打包时文件过小就会转换为base64的形式,而static里面的img不会
  • slot插槽可能会经常使用到,详细可参考官网文档,简单说组件和页面都通过组件用slot标签、页面用slot属性的方式呼应,给slot标签赋上name属性,再在页面中给slot属性赋上对应的值,可区分多个的情况

6-2 商品列表数据渲染实现

GoodList.vue

<template>
	<div>
    <nav-header></nav-header>
    <nav-bread>
      <span>Goods</span>
    </nav-bread>
    <div class="accessory-result-page accessory-page">
      <div class="container">
        <div class="filter-nav">
          <span class="sortby">Sort by:</span>
          <a href="javascript:void(0)" class="default cur">Default</a>
          <a href="javascript:void(0)" class="price">Price <svg class="icon icon-arrow-short"><use xlink:href="#icon-arrow-short"></use></svg></a>
          <a href="javascript:void(0)" class="filterby stopPop">Filter by</a>
        </div>
        <div class="accessory-result">
          <!-- filter -->
          <div class="filter stopPop" id="filter">
            <dl class="filter-price">
              <dt>Price:</dt>
              <dd><a href="javascript:void(0)">All</a></dd>
              <dd>
                <a href="javascript:void(0)">0 - 100</a>
              </dd>

            </dl>
          </div>

          <!-- search result accessories list -->
          <div class="accessory-list-wrap">
            <div class="accessory-list col-4">
              <ul>
                <li v-for="(item,index) in goodslist">
                  <div class="pic">
                    <a href="#"><img v-bind:src="'static/' + item.productImg" alt=""></a>
                  </div>
                  <div class="main">
                    <div class="name"></div>
                    <div class="price"></div>
                    <div class="btn-area">
                      <a href="javascript:;" class="btn btn--m">加入购物车</a>
                    </div>
                  </div>
                </li>

              </ul>
            </div>
          </div>
        </div>
      </div>
    </div>
    <nav-footer></nav-footer>
	</div>
</template>

<style >
</style>

<script >
  import './../assets/css/base.css'
  import './../assets/css/product.css'
  import NavHeader from './NavHeader.vue'
  import NavFooter from './NavFooter.vue'
  import NavBread from './NavBread.vue'
  import axios from 'axios'


  export default {
		data (){
			return {
				goodslist:[]
			}
		},
    components:{
		  NavHeader,
      NavFooter,
      NavBread
    },
    mounted:function () {
        this.getGoodsList();
    },
    methods:{
        getGoodsList:function () {
            axios.get("/goods").then((result)=>{
              var  res = result.data;
              this.goodslist = res.result;
            })
        }
    }
	}
</script>

dev-server.js新增:

var app = express()
        .
        .
        .
var router = express.Router();
var  goodsData = require('./../mock/goods.json');

router.get("/goods",function (req,res,next) {
    res.json(goodsData);
});
app.use(router);
        .
        .
        .
var compiler = webpack(webpackConfig)

说明:

  • 问:前面那节讲AMDCMDcommonJS的时候,提到了require的写法,本章这里的require属于哪一种用法呢,在node里面,是commonJS吗?但是json文件没有model.export导出,不太明白
    • 答: var goodsData = require(...) Node加载js必须是common规范,否则拿不到数据。它不仅仅可以抓取js,也可以加载json等等格式的文件,加载非js后缀的文件时则直接缓存到内存中。它不同于js文件

6-3 实现图片懒加载

GoodsList.vue

<template>
	<div>
    <nav-header></nav-header>
    <nav-bread>
      <span>Goods</span>
    </nav-bread>
    <div class="accessory-result-page accessory-page">
      <div class="container">
        <div class="filter-nav">
          <span class="sortby">Sort by:</span>
          <a href="javascript:void(0)" class="default cur">Default</a>
          <a href="javascript:void(0)" class="price">Price <svg class="icon icon-arrow-short"><use xlink:href="#icon-arrow-short"></use></svg></a>
          <a href="javascript:void(0)" class="filterby stopPop" v-on:click="showFilerPop">Filter by</a>
        </div>
        <div class="accessory-result">
          <!-- filter -->
          <div class="filter stopPop" id="filter" v-lazy="{'filterby-show':filerBy}">
            <dl class="filter-price">
              <dt>Price:</dt>
              <dd><a href="javascript:void(0)" :class="{'cur':priceCheck=='all'}" @click="setPriceCheck('all')">All</a></dd>
              <dd v-for="(price,index) in priceFilter">
                <a href="javascript:void(0)" @click="setPriceCheck(index)" :class="{'cur':priceCheck == index}"> - </a>
              </dd>

            </dl>
          </div>

          <!-- search result accessories list -->
          <div class="accessory-list-wrap">
            <div class="accessory-list col-4">
              <ul>
                <li v-for="(item,index) in goodslist">
                  <div class="pic">
                    <a href="#"><img v-bind:src="'static/' + item.productImg" alt=""></a>
                  </div>
                  <div class="main">
                    <div class="name"></div>
                    <div class="price"></div>
                    <div class="btn-area">
                      <a href="javascript:;" class="btn btn--m">加入购物车</a>
                    </div>
                  </div>
                </li>

              </ul>
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="md-overlay" v-show="overLayFlag" @click="closePop"></div>
    <nav-footer></nav-footer>
	</div>
</template>

<style >
</style>

<script >
  import './../assets/css/base.css'
  import './../assets/css/product.css'
  import NavHeader from './NavHeader.vue'
  import NavFooter from './NavFooter.vue'
  import NavBread from './NavBread.vue'
  import axios from 'axios'


  export default {
		data (){
			return {
				goodslist:[],
        priceFilter:[
          {
            startPrice:'0.00',
            endPrice:'500.00'
          },
          {
            startPrice:'500.00',
            endPrice:'1000.00'
          },
          {
            startPrice:'1000.00',
            endPrice:'2000.00'
          },
        ],
        priceCheck:'all',   //价格选中的状态
        filerBy:false,      //小屏幕价格菜单显示
        overLayFlag:false   //遮罩显示

			}
		},
    components:{
		  NavHeader,
      NavFooter,
      NavBread
    },
    mounted:function () {
        this.getGoodsList();
    },
    methods:{
        getGoodsList:function () {
            axios.get("/goods").then((result)=>{
              var  res = result.data;
              this.goodslist = res.result;
            })
        },
        showFilerPop() {
           this.filerBy = true;
           this.overLayFlag = true;

        },
        closePop(){
          this.filerBy = false;
          this.overLayFlag = false;
        },
        setPriceCheck(index){
           this.priceCheck = index;
           this.closePop();
        }
    }
	}
</script>

main.js中新增懒加载插件:

import VueLazyLoad from 'vue-lazyload'

Vue.use(VueLazyLoad,{
  loading:"/static/loading-svg/loading-bars.svg"
})


如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

¥ 打赏博主

Music

Search

Content