node中间层

/ 思路:给当前的运行环境加上标识 系统环境变量 (内存) // 怎么设置环境变量在内存 // windows SET NODE_ENV=production // windows SET NODE_ENV=development // 可以去跨平台设置环境变量 cross-env 第三方命令行工具 // npm i -g cross-env // cross-env NODE_ENV=production 或者 cross-env NODE_ENV=development // 在设置完成环境变量的同时 启动项目 // 那么能够在项目代码 获取当前设置的环境变量 去区分运行环境 // 开发 cross-env NODE_ENV=development nodemon app.js // 生产 cross-env NODE_ENV=production node app.js // package.json scripts 进行配置php

"scripts": { "test": "echo "Error: no test specified" && exit 1", "dev": "cross-env NODE_ENV=development nodemon app.js", "start": "cross-env NODE_ENV=production node app.js" },css

// 获取 环境变量 判断环境 req.app.get('env')html

NODE中间层项目-day02前端

01-反馈html5

姓名 意见或建议
*** 1. req.query 不是接受get传送的数据吗 它是中间件吗 2. 老师template第二个参数 必须是对象形式吗 3.提交表单的数据不是json格式吗能够用app.use(express.json())吗仍是必须用app.use(express.urlencoded({extended: false})) 这句话是对bodypaser的设置吗 设置完了能够用req.body来接受post的数据 这几个中间件有点弄不清楚 *** 刚哥把提取母的文件部分再细细的讲一下呐 艾尼哟node

  • // template('id',数据)   数据能够为任何类型  模版内容获取传入的数据$data
    复制代码
  • express.json() 解析前端提交的json格式字符串
  • express.urlencoded({extended: false}) 提交表单的数据post

02-回顾ios

  • node中间层
  • mvc思想
  • 介绍中间件类型
  • 错误处理
    • app.use((req,res,next))
    • app.use((err,req,res,next))
    • 设置环境变量
  • 模版抽离

03-抽离公用模版ajax

{{include '../components/header.art'}}
复制代码

04-维护网站头部信息express

config.jsnpm

// 1. 网站头部信息
const site = {
  title: '品优购(PYG.COM)-正品低价、品质保障、配送及时、轻松购物!',
  description: '品优购(PYG.COM)-专业的综合网上购物商城,为您提供正品低价的购物选择、优质便捷的服务体验。商品来自全球数十万品牌商家,囊括家电、手机、电脑、服装、居家、母婴、美妆、个护、食品、生鲜等丰富品类,知足各类购物需求。',
  Keywords:'网上购物,网上商城,家电,手机,电脑,服装,居家,母婴,美妆,个护,食品,生鲜,京东'
}

导出模块:

module.exports = {site}

exports = {site}

相同:导出模块

区别:module.exports 是最终使用的导出内容,exports为了语法简单

结论:当你直接赋值  module.exports  当你是挂载属性   使用谁同样的

导入模块:

require('')
复制代码

遵循:commonJS 模块化规范

  • AMD require.js 提早加上全部模块 CMD sea.js 按需加载模块

  • nodejs 实现同步加载模块 commonJS

  • ES6模块化规范

  • 实现思路: global 污染 ----》 app 没法在模版内使用 ----》 render 每一个页面须要这个数据 ----》res.locals 挂载的数据能够在模版内使用 ----》 在中间件 公用中间件

05-提取路由模块和控制器

// 定义路由规则   不去实现具体的业务 controller
const express = require('express')
const router = express.Router()

const homeController = require('./controllers/homeController')
const userController = require('./controllers/userController')

router.get('/', homeController.home)
router.get('/login',userController.login)

module.exports = router
复制代码

06-提取axios模块

// 返回  已经配置好的 axios 实例
const axios = require('axios')
const instance = axios.create({
  baseURL: 'http://localhost:8000/v1/',
  auth: {
    username: 'newshop-frontend',
    password: 'd8667837fce5a0270a35f4a8fa14be479fadc774'
  }
})

module.exports = instance
复制代码

07-首页-渲染轮播图

<!--banner轮播-->
<div id="banner" data-ride="carousel" data-interval="4000" class="sui-carousel slide">
  <ol class="carousel-indicators">
    {{each banner item i}}
    <li data-target="#banner" data-slide-to="{{i}}" class="{{i===0?'active':''}}"></li>
    {{/each}}
  </ol>
  <div class="carousel-inner">
    {{each banner item i}}
    <div class="item {{i===0?'active':''}}"><a href="{{item.link}}"><img src="{{item.image}}" title="{{item.title}}"></a></div>
    {{/each}}
  </div>
  <a href="#banner" data-slide="prev" class="carousel-control left">‹</a>
  <a href="#banner" data-slide="next" class="carousel-control right">›</a>
</div>
复制代码

08-首页-复习promise

  • 在then函数中直接返回 封装成一个promise对象 必定是成功的调用

  • 在catch函数中直接返回 封装成一个promise对象 必定是成功的调用

  • 在catch函数中返回 promise对象 失败的状况 Promise.reject(err)

    return axios.get('settings/home_slides') .then(res => res.data) .catch(err => Promise.reject(err))

  • Promise.reject() 错误回调

  • Promise.resolve() 成功回调

  • Promise.all() 同时执行多个promise对象 全部的promise操做结束后触发then()

  • Promise.race() 同时执行多个promise对象 等最快的异步操做结束触发then()

09-首页-渲染猜你喜欢

获取数据:

Promise.all([homeModel.getBanner(), homeModel.getLike()])
  .then(results => {
    // results 全部的异步操做的返回结果  且顺序和你传入promise对象的顺序一致
    res.locals.banner = results[0]
    res.locals.like = results[1]
    res.render('home.art')
  }).catch(err=> next(err))
复制代码

渲染页面:

{{each like item i}}
<li class="yui3-u-1-6">
  <a href="/item/{{item.id}}" class="pic"><img src="{{item.thumbnail}}"></a>
  <p>{{item.name}}</p><h3>¥{{item.price}}</h3>
</li>
{{/each}}
复制代码

10-首页-定义猜你喜欢接口

exports.like = (req, res, next) => {
  homeModel.getLike()
    .then(data => {
      res.send({
        status: 200,
        result: data
      })
    })
    .catch(err => {
      res.send({
        status: 500,
        msg: '获取猜你喜欢数据失败'
      })
    })
}
复制代码

11-首页-猜你喜欢换一换

// 点击换一换按钮  发生ajax请求  成功的时候  更新列表
$('#xxlChg').on('click', function () {
  $.get('/like', function (data) {
    if (data.status !== 200) return alert(data.msg)
    var html = ''
    data.result.forEach(function (item) {
      html += `
      <li class="yui3-u-1-6">
        <a href="/item/${item.id}" class="pic"><img src="${item.thumbnail}"></a>
        <p>${item.name}</p>
        <h3>¥${item.price}</h3>
      </li>
      `
    })
    $('#picLBxxl').fadeOut(function () {
      $(this).html(html).fadeIn()
    })
  })
})
复制代码

12-首页-获取分类数据

// 全局的处理
exports.global = (req, res, next) => {
  // 1. 设置网站头部
  res.locals.site = site
  // 2. 获取分类数据且设置模版使用
  // 2.1 数据获取时间太长  优化
  categoryModel.getCategory().then(data => {
    res.locals.category = data
    next()
  }).catch(err => next(err))
}
复制代码

13-首页-渲染分类模块

{{each category item i}}
<div class="item">
  <h3><a href="/list/{{item.id}}">{{item.name}}</a></h3>
  <div class="item-list clearfix">
    <div class="subitem">
      {{each item.children subItem i}}
      <dl>
        <dt><a href="/list/{{subItem.id}}">{{subItem.name}}</a></dt>
        <dd>
          {{each subItem.children lastItem i}}
          <em><a href="/list/{{lastItem.id}}">{{lastItem.name}}</a></em>
          {{/each}}
        </dd>
      </dl>
      {{/each}}
    </div>
  </div>
</div>
{{/each}}
复制代码

14-首页-分类数据缓存

  • 分类的数据获取时间好久
  • 获取一次后 缓存在node中间层
  • 在内存中存储 一个变量 存储分类信息
  • // 2. 获取分类数据且设置模版使用
    // 2.1 数据获取时间太长  优化
    // 2.2 在 app 实例存储数据  缓存分类
    // 2.3 req.locals  每次请求都是新的对象
    // 2.4 req.app.locals 挂载数据的对象
    // 2.5  判断是否缓存数据 若是缓存走缓存 若是没有走接口
    if (req.app.locals.category) {
      res.locals.category = req.app.locals.category
      next()
    } else {
      categoryModel.getCategory().then(data => {
        // 缓存
        req.app.locals.category = data
        res.locals.category = data
        next()
      }).catch(err => next(err))
    }
    复制代码

15-分类商品列表-路由规则定义

// 商品列表
router.get('/list/:id', productController.list)
复制代码

16-分类商品列表-获取路径传参

exports.list = (req, res, next) => {
  // 获取路径传参   req.params
  // 获取地址?传参  req.query
  // 获取post传参  req.body
  res.send(req.params.id)
}
复制代码

17-分类商品列表-获取列表数据

// 获取分类下的商品
exports.getProductsPager = (id, page, per_page) =>{
  return axios.get(`categories/${id}/products?page=${page}&per_page=${per_page}`)
    .then(res => {
      // 还须要分页数据  在响应头中
      // res 响应报文对象  res.headers 获取响应头
      // console.log(res.headers)
      return {
        list: res.data,
        totalPage: + res.headers['x-total-pages']
      }
    })
    .catch(err => Promise.reject(err))
}

// 获取post传参  req.body
const id = req.params.id
// 在?后提交数据  page
const page = req.query.page || 1
// 经过分类ID去获取商品列表数据且带分页
categoryModel.getProductsPager(id, page, 10)
  .then(data => {
    res.send(data)
  }).catch(err => next(err))
复制代码

18-分类商品列表-渲染列表

<ul class="yui3-g">
  {{each list item i}}
  <li class="yui3-u-1-5">
    <div class="p-img"><a href="/item/{{item.id}}"><img src="{{item.thumbnail}}"></a></div>
    <div class="price"><strong><em>¥</em><i>{{item.price}}</i></strong></div>
    <div class="attr"><em>{{item.name}}</em></div>
    <div class="commit"><i class="command">已有2000人评价</i></div>
    <div class="operate">
      <a href="/cart/add" class="sui-btn btn-bordered btn-danger">加入购物车</a>
      <a href="#" class="sui-btn btn-bordered">对比</a>
      <a href="#" class="sui-btn btn-bordered">关注</a>
    </div>
  </li>
  {{/each}}
</ul>
复制代码

19-分类商品列表-面包屑渲染

<!--bread-->
<div class="bread">
  <ul class="fl sui-breadcrumb">
    {{if bread.parent && bread.parent.parent}}
    <li><a href="/list/{{bread.parent.parent.id}}">{{bread.parent.parent.name}}</a></li>
    {{/if}}
    {{if bread.parent}}
    <li><a href="/list/{{bread.parent.id}}">{{bread.parent.name}}</a></li>
    {{/if}}
    <li class="active">{{bread.name}}</li>
  </ul>
</div>
复制代码

数据:

Promise.all([
  categoryModel.getProductsPager(id, page, 10),
  categoryModel.getCategoryAndParent(id)
]).then(results => {
  res.locals.list = results[0].list
  res.locals.bread = results[1]
  res.render('list.art')
  //res.send(res.locals)
}).catch(err => next(err))
复制代码

20-分类商品列表-排序功能实现

<a href="/list/{{bread.id}}?sort=commend">综合</a>
复制代码

获取请求的地址 不包含域名 不包含?传参

<ul class="sui-nav">
  <li class="{{sort==='commend'?'active':''}}"><a href="{{currUrl}}?sort=commend">综合</a></li>
  <li class="{{sort==='quantity'?'active':''}}"><a href="{{currUrl}}?sort=quantity">销量</a></li>
  <li class="{{sort==='market_time'?'active':''}}"><a href="{{currUrl}}?sort=market_time">新品</a></li>
  <li class="{{sort.includes('price')?'active':''}}">
    {{if sort==='-price'}}
    <a href="{{currUrl}}?sort=price">价格 <span class="sui-icon icon-tb-fold"></span></a>
    {{else if sort==='price'}}
    <a href="{{currUrl}}?sort=-price">价格 <span class="sui-icon icon-tb-unfold"></span></a>
    {{else}}
    <a href="{{currUrl}}?sort=-price">价格</a>
    {{/if}}
  </li>
</ul>

const sort = req.query.sort || 'commend'

// req.url 当前请的地址
// 解析url地址 获得pathname
const urlObject = url.parse(req.url)
res.locals.currUrl = urlObject.pathname
复制代码

NODE中间层项目-day02

01-反馈

姓名 意见或建议
*** 1. req.query 不是接受get传送的数据吗 它是中间件吗 2. 老师template第二个参数 必须是对象形式吗 3.提交表单的数据不是json格式吗能够用app.use(express.json())吗仍是必须用app.use(express.urlencoded({extended: false})) 这句话是对bodypaser的设置吗 设置完了能够用req.body来接受post的数据 这几个中间件有点弄不清楚 *** 刚哥把提取母的文件部分再细细的讲一下呐 艾尼哟

  • // template('id',数据)   数据能够为任何类型  模版内容获取传入的数据$data
    复制代码
  • express.json() 解析前端提交的json格式字符串
  • express.urlencoded({extended: false}) 提交表单的数据post

02-回顾

  • node中间层
  • mvc思想
  • 介绍中间件类型
  • 错误处理
    • app.use((req,res,next))
    • app.use((err,req,res,next))
    • 设置环境变量
  • 模版抽离

03-抽离公用模版

{{include '../components/header.art'}}
复制代码

04-维护网站头部信息

config.js

// 1. 网站头部信息
const site = {
  title: '品优购(PYG.COM)-正品低价、品质保障、配送及时、轻松购物!',
  description: '品优购(PYG.COM)-专业的综合网上购物商城,为您提供正品低价的购物选择、优质便捷的服务体验。商品来自全球数十万品牌商家,囊括家电、手机、电脑、服装、居家、母婴、美妆、个护、食品、生鲜等丰富品类,知足各类购物需求。',
  Keywords:'网上购物,网上商城,家电,手机,电脑,服装,居家,母婴,美妆,个护,食品,生鲜,京东'
}

导出模块:

module.exports = {site}

exports = {site}

相同:导出模块

区别:module.exports 是最终使用的导出内容,exports为了语法简单

结论:当你直接赋值  module.exports  当你是挂载属性   使用谁同样的

导入模块:

require('')
复制代码

遵循:commonJS 模块化规范

  • AMD require.js 提早加上全部模块 CMD sea.js 按需加载模块

  • nodejs 实现同步加载模块 commonJS

  • ES6模块化规范

  • 实现思路: global 污染 ----》 app 没法在模版内使用 ----》 render 每一个页面须要这个数据 ----》res.locals 挂载的数据能够在模版内使用 ----》 在中间件 公用中间件

05-提取路由模块和控制器

// 定义路由规则   不去实现具体的业务 controller
const express = require('express')
const router = express.Router()

const homeController = require('./controllers/homeController')
const userController = require('./controllers/userController')

router.get('/', homeController.home)
router.get('/login',userController.login)

module.exports = router
复制代码

06-提取axios模块

// 返回  已经配置好的 axios 实例
const axios = require('axios')
const instance = axios.create({
  baseURL: 'http://localhost:8000/v1/',
  auth: {
    username: 'newshop-frontend',
    password: 'd8667837fce5a0270a35f4a8fa14be479fadc774'
  }
})

module.exports = instance
复制代码

07-首页-渲染轮播图

<!--banner轮播-->
<div id="banner" data-ride="carousel" data-interval="4000" class="sui-carousel slide">
  <ol class="carousel-indicators">
    {{each banner item i}}
    <li data-target="#banner" data-slide-to="{{i}}" class="{{i===0?'active':''}}"></li>
    {{/each}}
  </ol>
  <div class="carousel-inner">
    {{each banner item i}}
    <div class="item {{i===0?'active':''}}"><a href="{{item.link}}"><img src="{{item.image}}" title="{{item.title}}"></a></div>
    {{/each}}
  </div>
  <a href="#banner" data-slide="prev" class="carousel-control left">‹</a>
  <a href="#banner" data-slide="next" class="carousel-control right">›</a>
</div>
复制代码

08-首页-复习promise

  • 在then函数中直接返回 封装成一个promise对象 必定是成功的调用

  • 在catch函数中直接返回 封装成一个promise对象 必定是成功的调用

  • 在catch函数中返回 promise对象 失败的状况 Promise.reject(err)

    return axios.get('settings/home_slides') .then(res => res.data) .catch(err => Promise.reject(err))

  • Promise.reject() 错误回调

  • Promise.resolve() 成功回调

  • Promise.all() 同时执行多个promise对象 全部的promise操做结束后触发then()

  • Promise.race() 同时执行多个promise对象 等最快的异步操做结束触发then()

09-首页-渲染猜你喜欢

获取数据:

Promise.all([homeModel.getBanner(), homeModel.getLike()])
  .then(results => {
    // results 全部的异步操做的返回结果  且顺序和你传入promise对象的顺序一致
    res.locals.banner = results[0]
    res.locals.like = results[1]
    res.render('home.art')
  }).catch(err=> next(err))
复制代码

渲染页面:

{{each like item i}}
<li class="yui3-u-1-6">
  <a href="/item/{{item.id}}" class="pic"><img src="{{item.thumbnail}}"></a>
  <p>{{item.name}}</p><h3>¥{{item.price}}</h3>
</li>
{{/each}}
复制代码

10-首页-定义猜你喜欢接口

exports.like = (req, res, next) => {
  homeModel.getLike()
    .then(data => {
      res.send({
        status: 200,
        result: data
      })
    })
    .catch(err => {
      res.send({
        status: 500,
        msg: '获取猜你喜欢数据失败'
      })
    })
}
复制代码

11-首页-猜你喜欢换一换

// 点击换一换按钮  发生ajax请求  成功的时候  更新列表
$('#xxlChg').on('click', function () {
  $.get('/like', function (data) {
    if (data.status !== 200) return alert(data.msg)
    var html = ''
    data.result.forEach(function (item) {
      html += `
      <li class="yui3-u-1-6">
        <a href="/item/${item.id}" class="pic"><img src="${item.thumbnail}"></a>
        <p>${item.name}</p>
        <h3>¥${item.price}</h3>
      </li>
      `
    })
    $('#picLBxxl').fadeOut(function () {
      $(this).html(html).fadeIn()
    })
  })
})
复制代码

12-首页-获取分类数据

// 全局的处理
exports.global = (req, res, next) => {
  // 1. 设置网站头部
  res.locals.site = site
  // 2. 获取分类数据且设置模版使用
  // 2.1 数据获取时间太长  优化
  categoryModel.getCategory().then(data => {
    res.locals.category = data
    next()
  }).catch(err => next(err))
}
复制代码

13-首页-渲染分类模块

{{each category item i}}
<div class="item">
  <h3><a href="/list/{{item.id}}">{{item.name}}</a></h3>
  <div class="item-list clearfix">
    <div class="subitem">
      {{each item.children subItem i}}
      <dl>
        <dt><a href="/list/{{subItem.id}}">{{subItem.name}}</a></dt>
        <dd>
          {{each subItem.children lastItem i}}
          <em><a href="/list/{{lastItem.id}}">{{lastItem.name}}</a></em>
          {{/each}}
        </dd>
      </dl>
      {{/each}}
    </div>
  </div>
</div>
{{/each}}
复制代码

14-首页-分类数据缓存

  • 分类的数据获取时间好久
  • 获取一次后 缓存在node中间层
  • 在内存中存储 一个变量 存储分类信息
  • // 2. 获取分类数据且设置模版使用
    // 2.1 数据获取时间太长  优化
    // 2.2 在 app 实例存储数据  缓存分类
    // 2.3 req.locals  每次请求都是新的对象
    // 2.4 req.app.locals 挂载数据的对象
    // 2.5  判断是否缓存数据 若是缓存走缓存 若是没有走接口
    if (req.app.locals.category) {
      res.locals.category = req.app.locals.category
      next()
    } else {
      categoryModel.getCategory().then(data => {
        // 缓存
        req.app.locals.category = data
        res.locals.category = data
        next()
      }).catch(err => next(err))
    }
    复制代码

15-分类商品列表-路由规则定义

// 商品列表
router.get('/list/:id', productController.list)
复制代码

16-分类商品列表-获取路径传参

exports.list = (req, res, next) => {
  // 获取路径传参   req.params
  // 获取地址?传参  req.query
  // 获取post传参  req.body
  res.send(req.params.id)
}
复制代码

17-分类商品列表-获取列表数据

// 获取分类下的商品
exports.getProductsPager = (id, page, per_page) =>{
  return axios.get(`categories/${id}/products?page=${page}&per_page=${per_page}`)
    .then(res => {
      // 还须要分页数据  在响应头中
      // res 响应报文对象  res.headers 获取响应头
      // console.log(res.headers)
      return {
        list: res.data,
        totalPage: + res.headers['x-total-pages']
      }
    })
    .catch(err => Promise.reject(err))
}

// 获取post传参  req.body
const id = req.params.id
// 在?后提交数据  page
const page = req.query.page || 1
// 经过分类ID去获取商品列表数据且带分页
categoryModel.getProductsPager(id, page, 10)
  .then(data => {
    res.send(data)
  }).catch(err => next(err))
复制代码

18-分类商品列表-渲染列表

<ul class="yui3-g">
  {{each list item i}}
  <li class="yui3-u-1-5">
    <div class="p-img"><a href="/item/{{item.id}}"><img src="{{item.thumbnail}}"></a></div>
    <div class="price"><strong><em>¥</em><i>{{item.price}}</i></strong></div>
    <div class="attr"><em>{{item.name}}</em></div>
    <div class="commit"><i class="command">已有2000人评价</i></div>
    <div class="operate">
      <a href="/cart/add" class="sui-btn btn-bordered btn-danger">加入购物车</a>
      <a href="#" class="sui-btn btn-bordered">对比</a>
      <a href="#" class="sui-btn btn-bordered">关注</a>
    </div>
  </li>
  {{/each}}
</ul>
复制代码

19-分类商品列表-面包屑渲染

<!--bread-->
<div class="bread">
  <ul class="fl sui-breadcrumb">
    {{if bread.parent && bread.parent.parent}}
    <li><a href="/list/{{bread.parent.parent.id}}">{{bread.parent.parent.name}}</a></li>
    {{/if}}
    {{if bread.parent}}
    <li><a href="/list/{{bread.parent.id}}">{{bread.parent.name}}</a></li>
    {{/if}}
    <li class="active">{{bread.name}}</li>
  </ul>
</div>
复制代码

数据:

Promise.all([
  categoryModel.getProductsPager(id, page, 10),
  categoryModel.getCategoryAndParent(id)
]).then(results => {
  res.locals.list = results[0].list
  res.locals.bread = results[1]
  res.render('list.art')
  //res.send(res.locals)
}).catch(err => next(err))
复制代码

20-分类商品列表-排序功能实现

<a href="/list/{{bread.id}}?sort=commend">综合</a>
复制代码

获取请求的地址 不包含域名 不包含?传参

<ul class="sui-nav">
  <li class="{{sort==='commend'?'active':''}}"><a href="{{currUrl}}?sort=commend">综合</a></li>
  <li class="{{sort==='quantity'?'active':''}}"><a href="{{currUrl}}?sort=quantity">销量</a></li>
  <li class="{{sort==='market_time'?'active':''}}"><a href="{{currUrl}}?sort=market_time">新品</a></li>
  <li class="{{sort.includes('price')?'active':''}}">
    {{if sort==='-price'}}
    <a href="{{currUrl}}?sort=price">价格 <span class="sui-icon icon-tb-fold"></span></a>
    {{else if sort==='price'}}
    <a href="{{currUrl}}?sort=-price">价格 <span class="sui-icon icon-tb-unfold"></span></a>
    {{else}}
    <a href="{{currUrl}}?sort=-price">价格</a>
    {{/if}}
  </li>
</ul>

const sort = req.query.sort || 'commend'

// req.url 当前请的地址
// 解析url地址 获得pathname
const urlObject = url.parse(req.url)
res.locals.currUrl = urlObject.pathname
复制代码

07-商品列表-按关键字搜索

  • 首先:修改头部代码 点击搜索按钮 跳转到列表页面
  • 设置路由规则
  • 分析需求
    • 搜索框 保留搜索的关键字

    • 在面包屑的位置 提示文字 根据'123'的搜索结果:

    • 其余需求和分类下商品列表一致

      // 1. 搜索关键字 const q = req.query.q // 2. 排序类型 const sort = req.query.sort || 'commend' // 3. 当前页码 每页显示条数 const page = req.query.page || 1 const per_page = 5 // 4. 商品列表 根据(搜索关键字,排序方式,当前页码,每页显示条数)去获取 productModel.getProductsPager(q,page,per_page,sort) .then(data=>{ // 前端页面须要哪些数据??? res.locals.q = q res.locals.sort = sort res.locals.list = data.list res.locals.pagination = paginationUtil({ currPage: +page, totalPage: data.totalPage, req }) res.render('list.art') }).catch(err => next(err))

注意:php服务器 不支持URL传中文

// 不能传中文
// 地址栏编码  URI
// 中文 转换 URI 编码
//encodeURIComponent('电脑')
//"%E7%94%B5%E8%84%91"
//decodeURIComponent('%E7%94%B5%E8%84%91')
//"电脑"
复制代码

08-商品详情-路由规则配置

规则 处理函数 模版页面

// 商品详情
router.get('/item/:id', productController.detail)

{{extend './layout/common.art'}}
{{block 'styles'}}
<link rel="stylesheet" href="/public/assets/css/page-item.css">
<link rel="stylesheet" href="/public/assets/css/xzoom.css">
{{/block}}
{{block 'scripts'}}
<script src="/public/assets/js/sui.tab.js"></script>
<script src="/public/assets/js/xzoom.min.js"></script>
<script>
  $(function () {
    $('.xzoom, .xzoom-gallery').xzoom({ tint: '#888', Xoffset: 15 })
  })
</script>
{{/block}}
复制代码

09-商品详情-页面需求分析

  • 面包屑
  • 商品图片
  • 商品基本信息
  • 相关商品
  • 商品介绍

经过两个接口:

products/:id?include=introduce,category,pictures

products?type=like&limit=6

exports.detail = (req, res, next) => {
  // - 面包屑
  // - 商品图片
  // - 商品基本信息
  // - 相关商品
  // - 商品介绍
  const id = req.params.id
  Promise.all([
    productModel.getProduct(id),
    homeModel.getLike()
  ]).then(results => {
    //res.send(results)
    res.locals.bread = results[0].category
    res.locals.pictures = results[0].pictures
    res.locals.info = {
      name: results[0].name,
      price: results[0].price
    }
    res.locals.like = results[1]
    res.locals.introduce = results[0].introduce
    res.render('item.art')
  }).catch(err => next(err))
}
复制代码

10-商品详情-渲染-图片区域

<div class="fl preview-wrap">
  <!--放大镜效果-->
  <div class="zoom">
    <!--默认第一个预览-->
    <div id="preview" class="spec-preview">
      <img class="xzoom" xoriginal="{{pictures[0].large}}" src="{{pictures[0].middle}}" width="100%">
    </div>
    <!--下方的缩略图-->
    <div class="spec-scroll">
      {{each pictures item i}}
      <a href="{{item.large}}"><img class="xzoom-gallery" src="{{item.middle}}" width="60"></a>
      {{/each}}
    </div>
  </div>
</div>
复制代码

11-商品详情-渲染-商品基本信息

html5 的 输入类型 email number url tel search

<form action="/cart/add/{{info.id}}">
              <div class="controls">
                <input autocomplete="off" name="count" type="number" autofocus min="1" max="10" value="1" class="itxt">
              </div>
              <button class="sui-btn  btn-danger addshopcar">加入购物车</button>
            </form>
复制代码

12-商品详情-渲染-相关商品

{{each like item i}}
<li>
  <div class="p-img"><img src="{{item.thumbnail}}"></div>
  <div class="attr"><em>{{item.name}}</em></div>
  <div class="price"><strong>¥{{item.price}}</strong></div>
  <div class="operate"><a href="/cart/add/{{item.id}}?count=1" class="sui-btn btn-bordered">加入购物车</a></div>
</li>
{{/each}}
复制代码

13-商品详情-渲染-商品简介

相关文章
相关标签/搜索