/ 思路:给当前的运行环境加上标识 系统环境变量 (内存) // 怎么设置环境变量在内存 // 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
复制代码
02-回顾ios
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-首页-分类数据缓存
// 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
复制代码
02-回顾
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-首页-分类数据缓存
// 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-商品详情-渲染-商品简介