[golang gin框架] 26.Gin 商城项目-前台自定义商品列表模板, 商品详情数据渲染,Markdown语法使用
一.前台自定义商品列表模板
当在首页分类点击进入分类商品列表页面时,可以根据后台分类中的分类模板跳转到对应的模板商品列表页面
1.管理后台商品分类模板设置如下图所示
2.代码展示
(1).商品控制器方法Category()完善
修改controllers/frontend/productController.go中的方法Category(), 判断分类模板,如果后台没有设置,则使用默认模板
-
// 根据商品分类获取分类下面的所有商品数据
-
func (con ProductController) Category(c *gin.Context) {
-
//获取分类id
-
cateId, _ := models.Int(c.Param("id"))
-
//当前页
-
page, _ := models.Int(c.Query("page"))
-
if page == 0 {
-
page = 1
-
}
-
//每一页显示的数量
-
pageSize := 2
-
-
//获取当前分类
-
curCate := models.GoodsCate{}
-
models.DB.Where("id = ? ", cateId).Find(&curCate)
-
-
//判断当前分类是否顶级分类,如果是,则获取对应的二级分类,如果不是,则获取对应的兄弟分类
-
subCate := []models.GoodsCate{}
-
var tempSlice []int
-
if curCate.Pid == 0 { // 当前分类是顶级分类,获取对应的二级分类
-
models.DB.Where("pid = ?", cateId).Find(&subCate)
-
//把二级分类id放到切片中
-
for i := 0; i < len(subCate); i {
-
tempSlice = append(tempSlice, subCate[i].Id)
-
}
-
} else { // 当前分类是二级分类,获取对应的兄弟分类
-
models.DB.Where("pid = ?", curCate.Pid).Find(&subCate)
-
}
-
//把请求的分类id放入切片
-
tempSlice = append(tempSlice, cateId)
-
//通过上面的分类id,获取商品相关数据
-
goodsList := []models.Goods{}
-
where := "cate_id in ?"
-
models.DB.Where(where, tempSlice).Where("status = ?", 1).Offset((page - 1) * pageSize).Limit(pageSize).Find(&goodsList)
-
-
//获取总数量
-
var count int64
-
models.DB.Where(where, tempSlice).Table("goods").Count(&count)
-
-
//定义请求的模板
-
tpl := "frontend/product/list.html"
-
//判断分类模板,如果后台没有设置,则使用默认模板
-
if curCate.Template != "" {
-
tpl = curCate.Template
-
}
-
-
con.Render(c, tpl, gin.H{
-
"goodsList": goodsList,
-
"subCate": subCate,
-
"currentCate": curCate,
-
"page": page,
-
"totalPages": math.Ceil(float64(count) / float64(pageSize)),
-
})
-
}
(2).模板页面案例
-
{{ define "frontend/product/catetest.html" }}
-
-
-
<html lang="en">
-
<head>
-
<meta charset="UTF-8">
-
<meta http-equiv="X-UA-Compatible" content="IE=edge">
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
-
<title>Document</title>
-
</head>
-
<body>
-
自定义模板
-
</body>
-
</html>
-
{{end}}
二.商品详情数据渲染,Markdown语法使用
1.后台商品相关页面
先来回顾一下后台商品相关属性功能页面
2.前端相关界面展示
3.路由代码
完善routers/frontendRouters.go前端路由
-
package routers
-
-
import (
-
"goshop/controllers/frontend"
-
"github.com/gin-gonic/gin"
-
)
-
-
//设置前端路由
-
func FrontendRoutersInit(r *gin.Engine) {
-
defaultRouters := r.Group("/")
-
{
-
//首页
-
defaultRouters.GET("/", frontend.IndexController{}.Index)
-
//商品分类对应的商品列表页面
-
defaultRouters.GET("/category:id", frontend.ProductController{}.Category)
-
//商品详情页
-
defaultRouters.GET("/detail", frontend.ProductController{}.Detail)
-
//获取商品图库信息:获取当前商品对应颜色的图片信息
-
defaultRouters.GET("/getImgList", frontend.ProductController{}.GetImgList)
-
}
-
}
3.控制器,模型代码
在controllers/frontend/productController.go中增加商品详情等方法
-
-
//商品详情
-
func (con ProductController) Detail(c *gin.Context) {
-
//获取商品id
-
id, err := models.Int(c.Query("id"))
-
//判断商品id是否符合要求
-
if err != nil {
-
c.Redirect(302, "/")
-
c.Abort()
-
}
-
//1、获取商品信息
-
goods := models.Goods{Id: id}
-
models.DB.Find(&goods)
-
-
//2、获取关联商品 RelationGoods
-
relationGoods := []models.Goods{}
-
//把数据库中保存的关联商品id转换成切片类型
-
goods.RelationGoods = strings.ReplaceAll(goods.RelationGoods, ",", ",")
-
relationIds := strings.Split(goods.RelationGoods, ",")
-
//查询关联商品
-
models.DB.Where("id in ?", relationIds).Select("id,title,price,goods_version").Find(&relationGoods)
-
-
//3、获取关联赠品 GoodsGift
-
goodsGift := []models.Goods{}
-
goods.GoodsGift = strings.ReplaceAll(goods.GoodsGift, ",", ",")
-
giftIds := strings.Split(goods.GoodsGift, ",")
-
models.DB.Where("id in ?", giftIds).Select("id,title,price,goods_version").Find(&goodsGift)
-
-
//4、获取关联颜色 GoodsColor
-
goodsColor := []models.GoodsColor{}
-
goods.GoodsColor = strings.ReplaceAll(goods.GoodsColor, ",", ",")
-
colorIds := strings.Split(goods.GoodsColor, ",")
-
models.DB.Where("id in ?", colorIds).Find(&goodsColor)
-
-
//5、获取关联配件 GoodsFitting
-
goodsFitting := []models.Goods{}
-
goods.GoodsFitting = strings.ReplaceAll(goods.GoodsFitting, ",", ",")
-
fittingIds := strings.Split(goods.GoodsFitting, ",")
-
models.DB.Where("id in ?", fittingIds).Select("id,title,price,goods_version").Find(&goodsFitting)
-
-
//6、获取商品关联的图片 GoodsImage
-
goodsImage := []models.GoodsImage{}
-
models.DB.Where("goods_id = ?", goods.Id).Limit(6).Find(&goodsImage)
-
-
//7、获取规格参数信息 GoodsAttr
-
goodsAttr := []models.GoodsAttr{}
-
models.DB.Where("goods_id = ?", goods.Id).Find(&goodsAttr)
-
-
//8、获取更多属性
-
/*
-
颜色:红色,白色,黄色 | 尺寸:41,42,43
-
切片
-
[
-
{
-
Cate:"颜色",
-
List:[红色,白色,黄色]
-
},
-
{
-
Cate:"尺寸",
-
List:[41,42,43]
-
}
-
]
-
-
goodsAttrStrSlice[0] 尺寸:41,42,43
-
tempSlice[0] 尺寸
-
tempSlice[1] 41,42,43
-
-
goodsAttrStrSlice[1] 套餐:套餐1,套餐2
-
-
*/
-
-
// 更多属性: goodsAttrStr := "尺寸:41,42,43|套餐:套餐1,套餐2"
-
goodsAttrStr := goods.GoodsAttr
-
//字符串替换操作
-
goodsAttrStr = strings.ReplaceAll(goodsAttrStr, ",", ",")
-
goodsAttrStr = strings.ReplaceAll(goodsAttrStr, ":", ":")
-
//实例化商品更多属性结构体
-
var goodsItemAttrList []models.GoodsItemAttr
-
//strings.Contains 判断字符串中有没有冒号(:)
-
if strings.Contains(goodsAttrStr, ":") {
-
//字符串替换操作:获取属性切片
-
goodsAttrStrSlice := strings.Split(goodsAttrStr, "|")
-
//创建切片的存储空间
-
goodsItemAttrList = make([]models.GoodsItemAttr, len(goodsAttrStrSlice))
-
for i := 0; i < len(goodsAttrStrSlice); i {
-
//strings.Split(s, sep string) 把字符串s按照sep转换成切片
-
//拆分 "尺寸:41,42,43
-
tempSlice := strings.Split(goodsAttrStrSlice[i], ":")
-
goodsItemAttrList[i].Cate = tempSlice[0]
-
//拆分 41,42,43
-
listSlice := strings.Split(tempSlice[1], ",")
-
goodsItemAttrList[i].List = listSlice
-
}
-
}
-
-
//定义请求的模板
-
tpl := "frontend/product/detail.html"
-
con.Render(c, tpl, gin.H{
-
"goods": goods,
-
"relationGoods": relationGoods,
-
"goodsGift": goodsGift,
-
"goodsColor": goodsColor,
-
"goodsFitting": goodsFitting,
-
"goodsImage": goodsImage,
-
"goodsAttr": goodsAttr,
-
"goodsItemAttrList": goodsItemAttrList,
-
})
-
}
-
-
//获取商品对应颜色的图库信息
-
func (con ProductController) GetImgList(c *gin.Context) {
-
//获取商品id
-
goodsId, err1 := models.Int(c.Query("goods_id"))
-
//获取商品对应的颜色id
-
colorId, err2 := models.Int(c.Query("color_id"))
-
-
//查询商品图库信息
-
goodsImageList := []models.GoodsImage{}
-
err3 := models.DB.Where("goods_id = ? AND color_id = ?", goodsId, colorId).Find(&goodsImageList).Error
-
if err1 != nil || err2 != nil || err3 != nil {
-
c.JSON(http.StatusOK, gin.H{
-
"success": false,
-
"result": "",
-
"message": "参数错误",
-
})
-
return
-
}
-
-
//判断 goodsImageList的长度 如果goodsImageList没有数据,那么我们需要返回当前商品所有的图库信息
-
if len(goodsImageList) == 0 {
-
models.DB.Where("goods_id = ?", goodsId).Find(&goodsImageList)
-
}
-
c.JSON(http.StatusOK, gin.H{
-
"success": true,
-
"result": goodsImageList,
-
"message": "获取数据成功",
-
})
-
}
在models/goodsItemAttr.go中定义一个商品更多属性的结构体
-
package models
-
-
//商品更多属性结构体
-
-
type GoodsItemAttr struct {
-
// 尺寸:41,42,43
-
Cate string //属性类型: 尺寸
-
List []string // 对应的值 [41,42,43]
-
}
4.main.go,tools.go
在前端渲染数据的时候,需要解析后台Markdown语法数据,这是就需要在models/tools.go中增加调用 Markdown语法的方法,这样就可以解析后台商品 规格与包装属性中的Markdown语法格式:
Markdown 是一种 轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档
当前许多网站都广泛使用 Markdown 来撰写帮助文档或是用于论坛上发表消息
更多语法参考: https://www.runoob.com/markdown/md-lists.html
在解析Markdown语法之前,需要 引入gomarkdown包,操作如下:
在tools.go中import github.com/gomarkdown/markdown,然后在main.go目录下 go mod tidy 更新就可以使用啦
models/tools.go中增加FormatAttr()方法
-
import (
-
"github.com/gomarkdown/markdown"
-
)
-
-
/*
-
转换markdown格式
-
str就是markdown语法
-
例如:
-
**我是一个三级标题** <=> <h3>我是一个三级标题</h3>
-
**我是一个加粗** <=> <strong>我是一个加粗</strong>
-
*/
-
func FormatAttr(str string) string {
-
tempSlice := strings.Split(str, "\n")
-
var tempStr string
-
for _, v := range tempSlice {
-
md := []byte(v)
-
output := markdown.ToHTML(md, nil, nil)
-
tempStr = string(output)
-
}
-
return tempStr
-
}
增加main.go中的自定义模板函数FormatAttr
-
//自定义模板函数,必须在r.LoadHTMLGlob前面(只调用,不执行, 可以在html 中使用)
-
r.SetFuncMap(template.FuncMap{
-
"UnixToTime": models.UnixToTime, //注册模板函数
-
"Str2Html": models.Str2Html,
-
"FormatImg": models.FormatImg,
-
"Sub": models.Sub,
-
"SubStr": models.SubStr,
-
"FormatAttr": models.FormatAttr,
-
})
5.html代码
渲染商品详情相关数据frontend/product/detail.html
-
{{ define "frontend/product/detail.html" }}
-
-
{{ template "frontend/public/page_header.html" .}}
-
-
{{ template "frontend/public/middle_nav.html" .}}
-
-
<link rel="stylesheet" href="/static/frontend/css/product.css">
-
-
<div class="jieshao mt20 w">
-
<div class="left fl">
-
<div class="swiper-container">
-
<div class="swiper-wrapper item_focus" id="item_focus">
-
{{range $key,$value := .goodsImage}}
-
<div class="swiper-slide">
-
<img src="{{$value.ImgUrl | FormatImg}}"/>
-
</div>
-
{{end}}
-
</div>
-
-
<div class="swiper-pagination"></div>
-
<div class="swiper-button-next"></div>
-
<div class="swiper-button-prev"></div>
-
</div>
-
</div>
-
<div class="right fr">
-
<div class="h3 ml20 mt20">{{.goods.Title}}</div>
-
<div class="jianjie mr40 ml20 mt10">{{.goods.SubTitle}}</div>
-
<div class="jiage ml20 mt10">{{.goods.Price}}元 <span class="old_price">{{.goods.MarketPrice}}元</span></div>
-
{{$goodsId := .goods.Id}}
-
{{$relationGoodsLen := len .relationGoods}}
-
{{if gt $relationGoodsLen 0}}
-
<div class="ft20 ml20 mt20">选择版本</div>
-
<div class="xzbb ml20 mt10 clearfix">
-
-
{{range $key,$value := .relationGoods}}
-
<div class="banben fl {{if eq $value.Id $goodsId}}active{{end}}">
-
<a href="detail?id={{$value.Id}}">
-
<span>{{$value.GoodsVersion}}</span>
-
<span>{{$value.Price}}元</span>
-
</a>
-
</div>
-
{{end}}
-
</div>
-
{{end}}
-
-
{{$goodsColorLen := len .goodsColor}}
-
{{if gt $relationGoodsLen 0}}
-
<div class="ft20 ml20 mt10">选择颜色</div>
-
<div class="xzbb ml20 mt10 clearfix" id="color_list">
-
{{range $key,$value:=.goodsColor}}
-
<div class="banben fl" goods_id="{{$goodsId}}" color_id="{{$value.Id}}">
-
<span class="yuandian" style="background:{{$value.ColorValue}}"></span>
-
<span class="yanse">{{$value.ColorName}}</span>
-
</div>
-
{{end}}
-
</div>
-
{{end}}
-
-
{{$goodsItemAttrListLen := len .goodsItemAttrList}}
-
{{if gt $goodsItemAttrListLen 0}}
-
{{range $key,$value := .goodsItemAttrList}}
-
<div class="ft20 ml20 mt20">{{$value.Cate}}</div>
-
<div class="xzbb ml20 mt10 clearfix">
-
{{range $k,$v := $value.List}}
-
<div class="banben fl">
-
<span>{{$v}}</span>
-
</div>
-
{{end}}
-
-
</div>
-
{{end}}
-
{{end}}
-
<div class="xqxq mt10 ml20">
-
<div class="top1 mt10">
-
<div class="left1 fl">{{.goods.GoodsVersion}} <span id="color_name"></span></div>
-
<div class="right1 fr">{{.goods.Price}}元</div>
-
<div class="clear"></div>
-
</div>
-
<div class="bot mt20 ft20 ftbc">总计:{{.goods.Price}}元</div>
-
</div>
-
<div class="xiadan ml20 mt10">
-
<input class="jrgwc" type="button" name="jrgwc" value="加入购物车"/>
-
</div>
-
</div>
-
<div class="clear"></div>
-
</div>
-
-
<div class="container clearfix">
-
<div class="c_left">
-
<h2>看了又看</h2>
-
<div class="item">
-
<a target="_blank" href="#">
-
<img src="/static/upload/20211117/1637139107685884400.jpg"/>
-
<p class="price recommendLookPrice4183081">¥31.90</p>
-
<p>三利 纯棉A类标准简约素雅大浴巾 70×140cm 男女同款 柔软舒适吸水裹身巾 豆绿</p>
-
</a>
-
</div>
-
<div class="item">
-
<a target="_blank" href="#">
-
<img src="/static/upload/20211117/1637139107685884400.jpg"/>
-
<p class="price recommendLookPrice4183081">¥31.90</p>
-
<p>三利 纯棉A类标准简约素雅大浴巾 70×140cm 男女同款 柔软舒适吸水裹身巾 豆绿</p>
-
</a>
-
</div>
-
<div class="item">
-
<a target="_blank" href="#">
-
<img src="/static/upload/20211117/1637139107685884400.jpg"/>
-
<p class="price recommendLookPrice4183081">¥31.90</p>
-
<p>三利 纯棉A类标准简约素雅大浴巾 70×140cm 男女同款 柔软舒适吸水裹身巾 豆绿</p>
-
</a>
-
</div>
-
</div>
-
-
<div class="c_right">
-
<ul class="detail_list clearfix">
-
-
<li class="">详情描述</li>
-
-
<li class="">规格参数</li>
-
-
<li class="">用户评价</li>
-
</ul>
-
-
<div class="detail_info">
-
-
<div class="detail_info_item">
-
{{Str2Html .goods.GoodsContent}}
-
</div>
-
<div class="detail_info_item">
-
<ul>
-
{{range $key,$value:=.goodsAttr}}
-
-
{{if ne $value.AttributeValue ""}}
-
<li class="row clearfix">
-
-
<div class="span5">
-
-
<h2>{{$value.AttributeTitle}}</h2>
-
</div>
-
<div class="span15">
-
{{$value.AttributeValue | FormatAttr | Str2Html}}
-
</div>
-
</li>
-
{{end}}
-
{{end}}
-
</ul>
-
</div>
-
-
<div class="detail_info_item">
-
<ul class="comment_list">
-
<li>
-
<div>
-
<img src="https://www.itying.com/themes/itying/images/stars5.gif">
-
</div>
-
<p>这已经是第六部了,一如既往地好用。美中不足得是,尾插和数据线的链接口,用过一段时间,就会有充电接触不良的问题,希望厂家将来有改进。</p>
-
-
<p class="eval-order-info"> <span class="eval-time">2018-11-18
-
14:00:35</span><span>月岩白</span><span>6GB 64GB</span><span></span></p>
-
-
</li>
-
<li>
-
<div>
-
<img src="https://www.itying.com/themes/itying/images/stars5.gif">
-
</div>
-
<p>这已经是第六部了,一如既往地好用。美中不足得是,尾插和数据线的链接口,用过一段时间,就会有充电接触不良的问题,希望厂家将来有改进。</p>
-
-
<p class="eval-order-info"> <span class="eval-time">2018-11-18
-
14:00:35</span><span>月岩白</span><span>6GB 64GB</span><span></span></p>
-
-
</li>
-
<li>
-
<div>
-
<img src="https://www.itying.com/themes/itying/images/stars5.gif">
-
</div>
-
<p>这已经是第六部了,一如既往地好用。美中不足得是,尾插和数据线的链接口,用过一段时间,就会有充电接触不良的问题,希望厂家将来有改进。</p>
-
-
<p class="eval-order-info"> <span class="eval-time">2018-11-18
-
14:00:35</span><span>月岩白</span><span>6GB 64GB</span><span></span></p>
-
-
</li>
-
<li>
-
<div>
-
<img src="https://www.itying.com/themes/itying/images/stars5.gif">
-
</div>
-
<p>这已经是第六部了,一如既往地好用。美中不足得是,尾插和数据线的链接口,用过一段时间,就会有充电接触不良的问题,希望厂家将来有改进。</p>
-
-
<p class="eval-order-info"> <span class="eval-time">2018-11-18
-
14:00:35</span><span>月岩白</span><span>6GB 64GB</span><span></span></p>
-
-
</li>
-
</ul>
-
</div>
-
</div>
-
-
</div>
-
</div>
-
-
{{ template "frontend/public/page_footer.html" .}}
-
</body>
-
</html>
-
{{end}}
6.js代码
在static/frontend/js/base.js中增加 initProductContentTab()方法-商品详情页面 tab切换(内容,规格参数等; initProductContentColor()方法- 商品详情 颜色选中功能,如果有关联的商品图片,则展示对应的商品图片信息
-
(function ($) {
-
-
var app = {
-
init: function () {
-
-
this.initSwiper();
-
-
this.initNavSlide();
-
-
this.initProductContentTab();
-
-
this.initProductContentColor();
-
-
},
-
initSwiper: function () { // 轮播图切换操作
-
new Swiper('.swiper-container', {
-
loop: true,
-
navigation: {
-
nextEl: '.swiper-button-next',
-
prevEl: '.swiper-button-prev'
-
},
-
pagination: {
-
el: '.swiper-pagination',
-
clickable: true
-
}
-
-
});
-
},
-
initNavSlide: function () { // 导航鼠标移上去效果
-
$("#nav_list>li").hover(function () {
-
-
$(this).find('.children-list').show();
-
}, function () {
-
$(this).find('.children-list').hide();
-
})
-
-
},
-
initProductContentTab: function () { // 商品详情页面tab切换(内容,规格参数等tab切换)
-
$(function () {
-
$('.detail_info .detail_info_item:first').addClass('active');
-
$('.detail_list li:first').addClass('active');
-
$('.detail_list li').click(function () {
-
var index = $(this).index();
-
$(this).addClass('active').siblings().removeClass('active');
-
$('.detail_info .detail_info_item').removeClass('active').eq(index).addClass('active');
-
-
})
-
})
-
},
-
initProductContentColor: function () { // 商品详情颜色选中功能,如果有关联的商品图片,则展示对应的商品图片信息
-
var _that = this;
-
$("#color_list .banben").first().addClass("active");
-
$("#color_name").html($("#color_list .active .yanse").html())
-
$("#color_list .banben").click(function () {
-
$(this).addClass("active").siblings().removeClass("active");
-
$("#color_name").html($("#color_list .active .yanse").html())
-
var goods_id = $(this).attr("goods_id")
-
var color_id = $(this).attr("color_id")
-
//获取当前商品对应颜色的图片信息
-
$.get("/product/getImgList", {"goods_id": goods_id, "color_id": color_id}, function (response) {
-
if (response.success == true) {
-
var swiperStr = ""
-
for (var i = 0; i < response.result.length; i ) {
-
swiperStr = '<div class="swiper-slide"><img src="https://blog.csdn.net/zhoupenghui168/article/details/130356348' response.result[i].img_url '"> </div>';
-
}
-
$("#item_focus").html(swiperStr)
-
_that.initSwiper()
-
}
-
})
-
})
-
}
-
}
-
-
$(function () {
-
app.init();
-
})
-
-
})($)
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhgfaabg
同类精品
更多
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
怎样阻止微信小程序自动打开
PHP中文网 06-13 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01