# Blog主题教程
# Blog主题模块开发步骤
# 第一步、准备工作
# 1.1) 准备静态HTML模板
准备需要开发的静态资源模板文件,结构可参考如下
└─ template/ → 模板根目录
├─ static/ → 静态资源
│ ├─ css/
│ │ ├─ style.css
│ │ └─ ......
│ ├─ js/
│ │ ├─ script.js
│ │ └─ ......
│ └─ image/
│ ├─ image.jpg
│ └─ ......
├─ show.html → 详情
├─ list.html → 列表
├─ tags.html → 标签
├─ about.html → 关于
├─ message.html → 留言
└─ index.html → 首页
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 1.2) 安装模块开发助手
模块开发助手可以极大效率的提高开发效率,在 系统管理 → 模块管理
安装 模块开发助手 (opens new window) 。
# 第二步、模块开发
# 2.1) 创建模块
访问 系统管理 → 模块开发助手
,通过常用工具创建模块
# 2.2) 安装启用主题模块
访问 系统管理 → 模块管理 → 本地模块
,安装并启用模块。
# 2.3) 主题模块开发完成
以下教程以主题模块 BlogThemeMyTest
为例进行。
2.3.1) 复制静态资源
复制静态HTML模板中的所有静态资源文件 template/static/
到主题模块静态资源 module/BlogThemeMyTest/Asset
中。
如,静态HTML模板结构为
└─ template/ → 模板根目录
└─ static/
├─ css
│ └─ style.css
├─ js
│ └─ script.js
└─ image
└─ image.jpg
2
3
4
5
6
7
8
复制到模块静态资源结构为
└─ module/BlogThemeMyTest/Asset/ → 模块静态资源结构
└─ static/
├─ css
│ └─ style.css
├─ js
│ └─ script.js
└─ image
└─ image.jpg
2
3
4
5
6
7
8
2.3.2) 做静态资源软连
开发阶段为了模块开发方便,访问的静态资源使用软连链接到模块静态资源文件夹。先删除 public/vendor/BlogThemeMyTest/ 目录,然后执行以下命令完成软连创建。
php artisan modstart:module-link-asset BlogThemeMyTest
这样,访问路径 http://example.com/vendor/BlogThemeMyTest/css/style.css
路径会定向到文件 module/BlogThemeMyTest/Asset/css/style.css
。
2.3.3) 完成模板开发
复制以下页面到模块,并完成页面功能开发。
- 列表:
list.html
→module/BlogThemeMyTest/View/pc/blog/list.blade.php
- 详情:
show.html
→module/BlogThemeMyTest/View/pc/blog/show.blade.php
- 表填:
tags.html
→module/BlogThemeMyTest/View/pc/blog/tags.blade.php
- 关于:
about.html
→module/BlogThemeMyTest/View/pc/blog/about.blade.php
- 留言:
message.html
→module/BlogThemeMyTest/View/pc/blog/message.blade.php
- 首页:
index.html
→module/BlogThemeMyTest/View/pc/blog/index.blade.php
要面开发主要需要以下两个步骤:
① 完成页面所有静态资源的路径替换
将所有路径 path/to/static 替换为 @asset('vendor/BlogThemeMyTest/path/to/static')
script
<script src="static/js/script.js"></script>
替换为
<script src="@asset('vendor/BlogThemeMyTest/static/js/script.js')"></script>
css
<link rel="stylesheet" href="static/css/style.css">
替换为
<link rel="stylesheet" href="@asset('vendor/BlogThemeMyTest/static/css/style.css')">
图片
<img src="static/image/image.jpg" />
替换为
<img src="@asset('vendor/BlogThemeMyTest/static/image/image.jpg')" />
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
② 完成页面变量替换和内容渲染
该部分每个页面需要参考个页面可用变量完成开发和内容替换。
# 第三步、模块发布分享
# 3.1) 账户信息认证
- 注册ModStart账号:访问 https://modstart.com (opens new window) 完成账号注册
- 实名认证:在用户中心完成用户实名认证
# 3.2) 在平台创建信息模块
在 个人中心 → 开发者 → 开发者中心
创建模块,填写基础模块信息完成创建。
# 3.3) 模块打包上传到模块市场
进入 系统管理 → 模块开发助手
,使用相同的 ModStart 账号登录,对于拥有的模块操作栏会出现发布按钮,点击发布一键发布到模块市场。
发布成功后,需要后台审核模块,完成审核后模块即可显示在模块市场。
# 模块文件介绍
# 目录结构
module/BlogThemeXxx
├─ Admin/ → 后台管理
│ ├─ Controller/
│ │ └─ ConfigController.php → 后台配置开发Controller
│ └─ routes.php → 路由
├─ Asset/ → 模块资源文件,安装后会复制到 public/vendor/BlogThemeXxx
│ └─ ......
├─ Core/
│ ├─ ModuleServiceProvider.php → 模块核心注册器
│ └─ ThemeSiteTemplateProvider.php → 主题注册器,用于注册当前模块为博客主题
├─ Docs/ → 模块文档
│ ├─ module/
│ │ ├─ content.md → 模块介绍,发布时自动更新到模块介绍
│ │ ├─ demo.md → 模块演示,发布时自动更新到模块演示
│ │ ├─ mobilePreview.md → 模块手机预览图,每行一个支持多个,发布时自动更新
│ │ └─ preview.md → 模块电脑端预览图,每行一个支持多个,发布时自动更新
│ └─ release.md → 模块发布日志,发布时自动更新到模块发布日志
├─ Lang/ → 多语言
│ ├─ en.php → 英文语言包
│ └─ zh.php → 中文语言包
├─ View/ → 模块视图主目录
│ └─ pc/ → 电脑端视图
│ ├─ blog/ → 博客视图
│ │ ├─ about.blade.php → 关于
│ │ ├─ index.blade.php → 首页
│ │ ├─ list.blade.php → 列表
│ │ ├─ message.blade.php → 留言
│ │ ├─ show.blade.php → 详情
│ │ └─ tags.blade.php → 标签
│ ├─ footer.blade.php → 公共视图底部
│ ├─ frame.blade.php → 公共视图框架
│ ├─ frameTheme.blade.php → 主题视图框架
│ └─ header.blade.php → 公共视图顶部
└─ config.json → 模块配置文件
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 博客链接
/blogs
:博客列表/blogs?keywords=xxx
:博客关键词搜索/blogs?keywords=xxx
:博客标签搜索/blog/{id}
:博客详情/blog/message
:留言/blog/archive
:博客归档/blog/about
:关于
# 博客首页 blog.index
# 博客列表 $records
@foreach($records as $record)
ID:{{ $record['id'] }}
标题:{{ $record['title'] }}
时间:{{ $record['postTime'] }}
摘要:{{ $record['summary'] }}
图片:{{ join(',',$record['images']) }}
标签:{{ join(',',$record['tag']) }}
分类ID:{{ $record['categoryId'] }}
分类标题:{{ $record['_category']['title'] }}
分类封面:{{ $record['_category']['cover'] }}
点击数:{{ $record['clickCount'] }}
评论数:{{ $record['commentCount'] }}
喜欢数:{{ $record['likeCount'] }}
收藏数:{{ $record['favCount'] }}
置顶:{{ $record['isTop'] }}
热门:{{ $record['isHot'] }}
推荐:{{ $record['isRecommend'] }}
日期:{{ $record['_date'] }}
封面:{{ $record['_cover'] }}
链接:{{ $record['_url'] }}
@endforeach
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
变量 | 说明 |
---|---|
$records | 博客记录数组 |
├ $record['id'] | 博客ID |
├ $record['title'] | 博客标题 |
├ $record['postTime'] | 博客创建时间 |
├ $record['summary'] | 博客摘要 |
├ $record['images'] | 博客图片数组 |
├ $record['tag'] | 博客标签数组 |
├ $record['categoryId'] | 博客分类ID |
├ $record['_category']['title'] | 博客分类标题 |
├ $record['_category']['cover'] | 博客分类封面 |
├ $record['clickCount'] | 博客点击数 |
├ $record['commentCount'] | 博客评论数 |
├ $record['likeCount'] | 博客喜欢数 |
├ $record['favCount'] | 博客收藏数 |
├ $record['isTop'] | 博客置顶 |
├ $record['isHot'] | 博客热门 |
├ $record['isRecommend'] | 博客推荐 |
├ $record['_date'] | 日期 |
├ $record['_cover'] | 博客封面(单张),会自动从内容中抽取 |
└ $record['_url'] | 博客链接 |
# 博客分页 $page
# 当前页数 $page
{{$page}}
# 分页大小 $pageSize
{{$pageSize}}
# 分页HTML
$pageHtml
{!! $pageHtml !!}
当前列表分页HTML数据
<div class="pages">
<a href="?page=1">1</a>
<span>2</span>
<a href="?page=1">3</a>
</div>
2
3
4
5
6
如果使用系统完整分页条,则以上样式名称在输出的HTML代码中都带,可以直接使用对应名称在自己的css中定义具体样式即可。
# 自定义分页
{!! \ModStart\Core\Util\PageHtmlUtil::render($total, $pageSize, $page,
'?' . \ModStart\Core\Input\Request::mergeQueries(['page' => ['{page}']]), [
'warp' => '<div>%s%</div>',
'more' => '<span>...</span>',
'prev' => '<a href="%s%">上一页</a>',
'prevDisabled' => '<span>上一页</span>',
'next' => '<a href="%s%">下一页</a>',
'nextDisabled' => '<span>下一页</span>',
'first' => '<a href="%s%">首页</a>',
'last' => '<a href="%s%">尾页</a>',
'current' => '<span>%p%</span>',
'item' => '<a href="%s%">%p%</a>',
]) !!}
2
3
4
5
6
7
8
9
10
11
12
13
# 博客列表 blog.list
# 博客列表 $records
@foreach($records as $record)
ID:{{ $record['id'] }}
标题:{{ $record['title'] }}
时间:{{ $record['postTime'] }}
摘要:{{ $record['summary'] }}
图片:{{ join(',',$record['images']) }}
标签:{{ join(',',$record['tag']) }}
分类ID:{{ $record['categoryId'] }}
分类标题:{{ $record['_category']['title'] }}
分类封面:{{ $record['_category']['cover'] }}
点击数:{{ $record['clickCount'] }}
评论数:{{ $record['commentCount'] }}
喜欢数:{{ $record['likeCount'] }}
收藏数:{{ $record['favCount'] }}
置顶:{{ $record['isTop'] }}
热门:{{ $record['isHot'] }}
推荐:{{ $record['isRecommend'] }}
日期:{{ $record['_date'] }}
封面:{{ $record['_cover'] }}
链接:{{ $record['_url'] }}
@endforeach
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
变量 | 说明 |
---|---|
$records | 博客记录数组 |
├ $record['id'] | 博客ID |
├ $record['title'] | 博客标题 |
├ $record['postTime'] | 博客创建时间 |
├ $record['summary'] | 博客摘要 |
├ $record['images'] | 博客图片数组 |
├ $record['tag'] | 博客标签数组 |
├ $record['categoryId'] | 博客分类ID |
├ $record['_category']['title'] | 博客分类标题 |
├ $record['_category']['cover'] | 博客分类封面 |
├ $record['clickCount'] | 博客点击数 |
├ $record['commentCount'] | 博客评论数 |
├ $record['likeCount'] | 博客喜欢数 |
├ $record['favCount'] | 博客收藏数 |
├ $record['isTop'] | 博客置顶 |
├ $record['isHot'] | 博客热门 |
├ $record['isRecommend'] | 博客推荐 |
├ $record['_date'] | 日期 |
├ $record['_cover'] | 博客封面(单张),会自动从内容中抽取 |
└ $record['_url'] | 博客链接 |
# 博客分页
# 当前页数 $page
{{$page}}
# 分页大小 $pageSize
{{$pageSize}}
# 分页HTML
$pageHtml
{!! $pageHtml !!}
当前列表分页HTML数据
<div class="pages">
<a href="?page=1">1</a>
<span>2</span>
<a href="?page=1">3</a>
</div>
2
3
4
5
6
如果使用系统完整分页条,则以上样式名称在输出的HTML代码中都带,可以直接使用对应名称在自己的css中定义具体样式即可。
# 自定义分页
{!! \ModStart\Core\Util\PageHtmlUtil::render($total, $pageSize, $page,
'?' . \ModStart\Core\Input\Request::mergeQueries(['page' => ['{page}']]), [
'warp' => '<div>%s%</div>',
'more' => '<span>...</span>',
'prev' => '<a href="%s%">上一页</a>',
'prevDisabled' => '<span>上一页</span>',
'next' => '<a href="%s%">下一页</a>',
'nextDisabled' => '<span>下一页</span>',
'first' => '<a href="%s%">首页</a>',
'last' => '<a href="%s%">尾页</a>',
'current' => '<span>%p%</span>',
'item' => '<a href="%s%">%p%</a>',
]) !!}
2
3
4
5
6
7
8
9
10
11
12
13
# 博客详情 blog.show
# 博客 $record
ID:{{ $record['id'] }}
标题:{{ $record['title'] }}
时间:{{ $record['postTime'] }}
摘要:{{ $record['summary'] }}
图片:{{ join(',',$record['images']) }}
标签:{{ join(',',$record['tag']) }}
分类ID:{{ $record['categoryId'] }}
分类标题:{{ $record['_category']['title'] }}
分类封面:{{ $record['_category']['cover'] }}
点击数:{{ $record['clickCount'] }}
评论数:{{ $record['commentCount'] }}
喜欢数:{{ $record['likeCount'] }}
收藏数:{{ $record['favCount'] }}
置顶:{{ $record['isTop'] }}
热门:{{ $record['isHot'] }}
推荐:{{ $record['isRecommend'] }}
日期:{{ $record['_date'] }}
封面:{{ $record['_cover'] }}
链接:{{ $record['_url'] }}
内容:{{ $record['content'] }}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
变量 | 说明 |
---|---|
$record['id'] | 博客ID |
$record['title'] | 博客标题 |
$record['postTime'] | 博客创建时间 |
$record['summary'] | 博客摘要 |
$record['images'] | 博客图片数组 |
$record['tag'] | 博客标签数组 |
$record['categoryId'] | 博客分类ID |
$record['_category']['title'] | 博客分类标题 |
$record['_category']['cover'] | 博客分类封面 |
$record['clickCount'] | 博客点击数 |
$record['commentCount'] | 博客评论数 |
$record['likeCount'] | 博客喜欢数 |
$record['favCount'] | 博客收藏数 |
$record['isTop'] | 博客置顶 |
$record['isHot'] | 博客热门 |
$record['isRecommend'] | 博客推荐 |
$record['_date'] | 日期 |
$record['_cover'] | 博客封面(单张),会自动从内容中抽取 |
$record['_url'] | 博客链接 |
$record['content'] | 博客内容 |
# 博客上/下篇
# 上篇博客 $recordPrev
变量 | 说明 |
---|---|
$recordPrev['id'] | 博客ID |
$recordPrev['title'] | 博客标题 |
$recordPrev['_url'] | 博客地址 |
# 下篇博客 $recordNext
变量 | 说明 |
---|---|
$recordNext['id'] | 博客ID |
$recordNext['title'] | 博客标题 |
$recordNext['_url'] | 博客地址 |
# 评论列表 $comments
@foreach($comments as $comment)
留言ID:{{ $comment['id'] }}
留言用户名:{{ $comment['username'] }}
留言邮箱:{{ $comment['email'] }}
留言网址:{{ $comment['url'] }}
留言时间:{{ $comment['created_at'] }}
留言头像:{{ $comment['_avatar'] }}
留言内容:{{ $comment['content'] }}
@endforeach
2
3
4
5
6
7
8
9
变量 | 说明 |
---|---|
$comments | 评论记录数组 |
├ $comment['id'] | ID |
├ $comment['username'] | 称呼 |
├ $comment['email'] | 邮箱 |
├ $comment['url'] | 网址 |
├ $comment['content'] | 内容(富文本) |
├ $comment['created_at'] | 创建时间 |
└ $comment['_avatar'] | 头像 |
# 评论分页
可用变量 $commentPage
$commentPageSize
$commentTotal
使用方法同博客分页。
# 评论表单
评论表单提交到接口 blog/comment/add
<form method="post" data-ajax-form action="{{modstart_api_url('blog/comment/add')}}">
<input type="hidden" name="blogId" value="{{$record['id']}}"/>
<input type="text" name="username" placeholder="访客" />
<input type="text" name="email" placeholder="邮箱" />
<input type="text" name="url" placeholder="主页" />
<textarea name="content" placeholder="内容"></textarea>
<div>
验证:
{!! \Module\Vendor\Provider\Captcha\CaptchaProvider::get(modstart_config('Blog_BlogCaptchaProvider','default'))->render() !!}
</div>
<button type="submit">发表评论</button>
</form>
需要注意,表单提交需要引入这两个JS来处理 data-ajax-form 的表单提交
<script src="@asset('asset/vendor/jquery.js')"></script>
<script src="@asset('asset/common/base.js')"></script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 留言页面 blog.message
# 留言 $records
@foreach($records as $record)
留言ID:{{ $record['id'] }}
留言内容:{{ $record['content'] }}
@endforeach
2
3
4
变量 | 说明 |
---|---|
$records | 留言记录数组 |
└ $record['id'] | ID |
└ $record['username'] | 称呼 |
└ $record['email'] | 邮箱 |
└ $record['url'] | 网址 |
└ $record['content'] | 内容 |
└ $record['created_at] | 时间 |
└ $record['_avatar'] | 头像 |
# 留言分页
# 当前页数 $page
{{$page}}
# 分页大小 $pageSize
{{$pageSize}}
# 分页HTML
$pageHtml
{!! $pageHtml !!}
当前列表分页HTML数据
<div class="pages">
<a href="?page=1">1</a>
<span>2</span>
<a href="?page=1">3</a>
</div>
2
3
4
5
6
如果使用系统完整分页条,则以上样式名称在输出的HTML代码中都带,可以直接使用对应名称在自己的css中定义具体样式即可。
# 自定义分页
{!! \ModStart\Core\Util\PageHtmlUtil::render($total, $pageSize, $page,
'?' . \ModStart\Core\Input\Request::mergeQueries(['page' => ['{page}']]), [
'warp' => '<div>%s%</div>',
'more' => '<span>...</span>',
'prev' => '<a href="%s%">上一页</a>',
'prevDisabled' => '<span>上一页</span>',
'next' => '<a href="%s%">下一页</a>',
'nextDisabled' => '<span>下一页</span>',
'first' => '<a href="%s%">首页</a>',
'last' => '<a href="%s%">尾页</a>',
'current' => '<span>%p%</span>',
'item' => '<a href="%s%">%p%</a>',
]) !!}
2
3
4
5
6
7
8
9
10
11
12
13
# 留言表单
留言表单提交到 blog/message/add
<form method="post" data-ajax-form action="{{modstart_api_url('blog/message/add')}}">
<input type="text" name="username" placeholder="名称" />
<input type="text" name="email" placeholder="输入邮箱" />
<input type="text" name="url" placeholder="输入网站" />
<textarea name="content" placeholder="内容"></textarea>
<div>
验证
{!! \Module\Vendor\Provider\Captcha\CaptchaProvider::get(modstart_config('Blog_MessageCaptchaProvider','default'))->render() !!}
</div>
<button type="submit">
提交
</button>
</form>
需要注意,表单提交需要引入这两个JS来处理 data-ajax-form 的表单提交
<script src="@asset('asset/vendor/jquery.js')"></script>
<script src="@asset('asset/common/base.js')"></script>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 通用页面
# 公共变量
$pageTitle
页面标题$pageKeywords
页面关键词$pageDescription
页面描述
# 配置
// 网站名称
{{ modstart_config('siteName') }}
// 网站Logo
{{ modstart_config_asset_url('siteLogo') }}
// 网站副标题
{{ modstart_config('siteSlogan') }}
// 网站域名
{{ modstart_config('siteDomain') }}
// 网站关键词
{{ modstart_config('siteKeywords') }}
// 网站描述
{{ modstart_config('siteDescription') }}
// 备案编号
{{ modstart_config('siteBeian') }}
// 网站ICO
{{ modstart_config_asset_url('siteFavIco') }}
// 网站主色调
{{ modstart_config('sitePrimaryColor') }}
// 网站主题
{{ modstart_config('siteTemplate') }}
// 联系方式-邮箱
{{ modstart_config('Site_ContactEmail') }}
// 联系方式-电话
{{ modstart_config('Site_ContactPhone') }}
// 联系方式-地址
{{ modstart_config('Site_ContactAddress') }}
// 联系方式-二维码
{{ modstart_config_asset_url('Site_ContactQrcode') }}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 博客名称
{{ modstart_config('Blog_Name') }}
// 博客标语
{{ modstart_config('Blog_Slogan') }}
// 博客头像
{{ modstart_config_asset_url('Blog_Avatar') }}
// 联系方式-QQ
{{ modstart_config('Blog_ContactQQ') }}
// 联系方式-微博
{{ modstart_config('Blog_ContactWeibo') }}
// 联系方式-微信
{{ modstart_config('Blog_ContactWechat') }}
2
3
4
5
6
7
8
9
10
11
12
# 导航
# 循环显示导航
@foreach(MNav::all('head') as $nav)
<a href="{{ $nav['link'] }}">{{ $nav['name'] }}</a>
@endforeach
2
3
变量 | 说明 |
---|---|
$nav['name'] | 导航名称 |
$nav['link'] | 导航链接 |
$nav['_child'] | 子导航(空表示只有一级导航,不为空表示为二级导航) |
$nav['openType'] | 打开方式(2=新窗口 其他值=当前窗口) |
# 不同的位置
MNav::all('head'); // 头部导航
MNav::all('foot'); // 底部导航
2
# 多级嵌套(最多支持三级菜单)
@foreach(MNav::all('head') as $nav)
@if(empty($nav['_child']))
<!-- 无二级导航 -->
<a href="{{ $nav['link'] }}">{{ $nav['name'] }}</a>
@else
<!-- 有二级导航 -->
<div class="title">
<a href="{{$nav['link']}}">{{$nav['name']}}</a>
</div>
<div class="child">
@foreach($nav['_child'] as $nav2)
@if(empty($nav2['_child']))
<!-- 无三级导航 -->
<a href="{{$nav2['link']}}">{{$nav2['name']}}</a>
@else
<!-- 有三级导航 -->
<div class="title">
<a href="{{$nav2['link']}}">{{$nav2['name']}}</a>
</div>
<div class="child">
@foreach($nav2['_child'] as $nav3)
<a href="{{$nav3['link']}}">{{$nav3['name']}}</a>
@endforeach
</div>
@endif
@endforeach
</div>
@endif
@endforeach
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 高亮菜单
当前URL匹配链接时输出 CSS 类 active
@foreach(MNav::all('head') as $nav)
<a href="{{ $nav['link'] }}"
class="{{modstart_baseurl_active($nav['link'],'active')}}">
{{ $nav['name'] }}
</a>
@endforeach
2
3
4
5
6
更多参考 Nav (opens new window) 模块
# 轮播
# 循环显示轮播
// 循环特定位置轮播
@foreach(MBanner::all('Xxx') as $banner)
@if($banner['type']===\Module\Banner\Type\BannerType::IMAGE)
图片
<a href="{{ $banner['link'] }}">{{ $banner['image'] }}</a>
@elseif($banner['type']===\Module\Banner\Type\BannerType::IMAGE_TITLE_SLOGAN_LINK)
图片+标题+描述+链接
<a href="{{ $banner['link'] }}">{{ $banner['image'] }}</a>
<span>{{ $banner['title'] }}</span>
<span>{{ $banner['slogan'] }}</span>
<a href="{{ $banner['link'] }}">{{ $banner['linkText'] }}</span>
@elseif($banner['type']===\Module\Banner\Type\BannerType::VIDEO)
视频
<a href="{{ $banner['link'] }}">{{ $banner['video'] }}</a>
@endif
@endforeach
// 循环特定位置轮播(仅包含图片)
@foreach(MBanner::allImage('Xxx') as $banner)
<a href="{{ $banner['link'] }}">{{ $banner['image'] }}</a>
@endforeach
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 支持多个位置
// 位置 Blog
\MBanner::all('Blog')
// 位置 Cms
\MBanner::all('Cms')
2
3
4
更多使用可参考 Banner (opens new window) 模块
# 友情链接
# 循环显示友情链接
// 循环特定位置友情链接
@foreach(\MPartner::all('Xxx') as $partner)
<a href="{{ $partner['link'] }}">{{ $partner['title'] }}</a>
@endforeach
2
3
4
# 不同位置友情链接
// 位置 Blog
\MPartner::all('Blog')
// 位置 Cms
\MPartner::all('Cms')
2
3
4
更多使用可参考 Partner (opens new window) 模块
# 站点地图
启用网站需要安装 SiteMapManager (opens new window) 模块获得支持,设置后访问路径如下:
- `http://www.example.com/sitemap.xml`
系统使用动态站点地图,不需要手动生成,访问地址即为实时地图,输出格式为xml格式。具体使用方式可参考 SiteMapManager (opens new window) 模块的使用方法。
# 用户
需要安装模块获得支持 Member (opens new window)
@if(\Module\Member\Auth\MemberUser::isLogin())
用户ID:{{$_memberUser['id']}}
用户名:{{$_memberUser['username']}}
昵称:{{$_memberUser['nickname']}}
@else
请登录
@endif
2
3
4
5
6
7
变量 | 说明 |
---|---|
$_memberUserId | 用户ID,可以判断该变量是否为空来判断用户是否登录 |
$_memberUser['id'] | 用户ID |
$_memberUser['username'] | 用户名 |
$_memberUser['avatar'] | 头像 |
$_memberUser['nickname'] | 昵称 |
# 视图开发
# 网站主色调
可以通过 CSS 的变量 var(--color-primary)
获取,该变量会根据用户后台设置的主色调来动态改变。
# 页面框架与继承
通常情况下一个主题结构如图所示
├── 视图根目录 → 模块视图主目录
│ └── pc → 自适应默认为PC
│ ├── xxx → 模块视图子目录
│ │ ├── list.blade.php → 详情页
│ │ ├── show.blade.php → 列表页
│ │ ├── index.blade.php → 首页
│ ├── footer.blade.php
│ ├── frame.blade.php → 框架视图
│ └── header.blade.php
2
3
4
5
6
7
8
9
# 框架视图 frame.blade.php
通过会在模板文件中可以通过 @extends($_viewFrame)
来确定当前模板的框架视图,该文件通常包含公共的头部、尾部、侧边栏等内容。
$_viewFrame
会根据当前模板查找最先匹配到的文件,通常情况下,该变量会按照如下顺序查找:
resources/views/theme/<主题>/pc/frame.blade.php
module/<主题模块>/View/pc/frame.blade.php
resources/views/theme/default/pc/frame.blade.php
请保证 frame.blade.php
文件为以下结构,完整结构可参考 vendor/modstart/modstart/views/layout/frame.blade.php
<!doctype html>
<html>
<head>
...
<title>@section('pageTitle')@yield('pageTitleMain','') | {{modstart_config('siteName')}}@endsection</title>
<meta name="keywords" content="@yield('pageKeywords','')">
<meta name="description" content="@yield('pageDescription','')">
@section('headAppend')@show
</head>
<body>
@section('body')
@section('bodyContent')@show
@show
@section('bodyAppend')@show
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 页面视图
@extends($_viewFrame)
@section('pageTitleMain')我的视图标题@endsection
@section('bodyContent')
<div class="ub-container">
我的视图文件
</div>
@endsection
2
3
4
5
6
7
8
9
其中:
$_viewFrame
变量表示当前系统使用的框架视图@section('pageTitleMain')
为系统标题@section('bodyContent')
为系统正文内容部分
# 自适应的设备视图
根据访问设备的不同,会启用不同的视图文件,具体逻辑可参照 \ModStart\Core\View\ResponsiveViewTrait
中的逻辑。
- PC端使用
pc/
中的视图 - 手机端使用
m/
中的视图 - 当手机端视图不存在时,会自动降级使用
pc/
中的视图
# 系统路径
// 系统路径
{{ modstart_web_url('foo/bar') }}
// 系统路径,带域名
{{ modstart_web_full_url('foo/bar') }}
2
3
4
# 页面 section 修改
<!--为页面设置标题 -->
@section('pageTitle')页面标题@endsection
<!--设置页面主标题(会自动补全网站名称)-->
@section('pageTitleMain')页面主标题@endsection
<!--设置页面关键词-->
@section('pageKeywords')页面关键词@endsection
<!--设置页面描述-->
@section('pageDescription')页面描述@endsection
<!--在页面head上追加内容-->
@section('headAppend')
@parent
<script src="head.js"></script>
@endsection
<!--在页面body上追加内容-->
@section('bodyAppend')
@parent
<script src="body.js"></script>
@endsection
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 使用 @asset 引入路径
使用 @asset 指令可以引入静态资源,同时会自动添加版本号,以便于浏览器缓存。
<script src="@asset('foo/bar.js')"></script>
<link rel="stylesheet" href="@asset('vendor/Xxx/style/test.css')" />
<img src="@asset('vendor/Xxx/image/test.jpg')" />
2
3
最终显示在浏览器端的HTML代码为
<script src="/foo/bar.js?4015423772"></script>
<link rel="stylesheet" href="/vendor/Xxx/style/test.css?4015427772" />
<img src="/vendor/Xxx/image/test.jpg?4015423772" />
2
3
其中文件后加的 Hash 值在文件内容变动时会变化,避免了浏览器缓存。
# 页面 JS 和 CSS
页面 JavaScript
会自动放在页面尾部(</body>
之前)
// 引入行内 js
\ModStart\ModStart::script('console.log("Hello ModStart");');
// 引入一个 JavaScript 文件内容到页面
\ModStart\ModStart::js('文件路径.js');
// 引入一个 js 文件路径到页面
\ModStart\ModStart::js('文件路径.js');
2
3
4
5
6
页面 CSS
会自动放在头部(</head>
之前)
// 引入行内 css
\ModStart\ModStart::style('.test{ color:red; }');
// 引入一个 CSS 文件内容到页面
\ModStart\ModStart::styleFile('文件路径.css');
// 引入一个 CSS 文件路径到页面
\ModStart\ModStart::css('文件路径.css');
2
3
4
5
6
# 时间格式化
// $t = '2021-01-01 00:00:00'
date('Y-m-d', strtotime($t) )
2
时间格式化标签和PHP时间格式化语法一致,分别用不同字母代替,中间可以穿插任意字符,如:Y-m-d
、Y/m/d
、Y年m月d日
等
注意:Y代表完整年份,y代表简化年份,m代表月份,d代表日,H代表小时,i代表分,s代表秒,更多请参考PHP时间格式化语法 ,参考链接 :http://php.net/manual/zh/function.date.php (opens new window)
# HTML去除标签
// 去除HTML并限制输出 100 个字符
\ModStart\Core\Util\HtmlUtil::text($html,100)
2
一般在首页等特殊位置需要调取正文一段纯文本时使用,这时一般会配合下面的内容截取标签一起使用
# 内容截取
// HTML
\ModStart\Core\Util\HtmlUtil::text($html,100)
// 非HTML
\ModStart\Core\Util\StrUtil::limit($text,100,'...')
2
3
4
限制输出 100 个字符
# 其它格式
// 限定浮点格式,更多参考 https://www.php.net/manual/en/function.sprintf.php
sprintf('%0.2f', 3.14159)
2
# 当前网址
以访问 http://example.com/test/path?a=b
为例
// /test/path
\ModStart\Core\Input\Request::path()
// http://example.com/test/path?a=b
\ModStart\Core\Input\Request::currentPageUrl()
// http://example.com/test/path
\ModStart\Core\Input\Request::currentPageUrlWithOutQueries()
2
3
4
5
6
# 当前页面URL
获取当前访问页面完整地址,通常用于生成二维码等
\ModStart\Core\Input\Request::currentPageUrl()
# 二维码生成
生成二维码数据
// 返回base64图片字符串
\ModStart\Core\Util\QrcodeUtil::pngBase64String('ModStart')
2
可直接用于显示,如
<img src="{!! \ModStart\Core\Util\QrcodeUtil::pngBase64String('ModStart') !!}" />
# 获取系统配置
网站配置全部位于 config
数据表中,查找 key
值,通过如下如下函数可以直接获取值,该函数已内置添加了缓存可在视图中多次调用。
modstart_config('xxx','默认值')
# 模板语法
# 显示数据
你可以使用「中括号」包住变量以显示传递至 Blade 视图的数据。就如以下的路由设置一样:
return view('welcome', ['name' => 'Samantha']);
你可以像这样显示 name 变量的内容:
Hello, {{ $name }}.
显示数据或默认值
此写法兼容Laravel5和Laravel9+
{{ empty($name) ? '默认值' : $name }}
当然也不是说一定只能显示传递至视图的变量内容。你也可以显示 PHP 函数的结果。实际上,你可以放置任何你想要的 PHP 代码到 Blade 显示的语法里面:
目前的 UNIX 时间戳为 {{ time() }}。
注意:Blade 的 语法会自动调用 PHP htmlentites 函数来防御 XSS 攻击。
# 条件判断 if
你可以使用 @if、@elseif、@else 及 @endif 命令建构 if 表达式。这些命令的功能等同于在 PHP 中的语法:
@if (count($records) === 1)
我有一条记录!
@elseif (count($records) > 1)
我有多条记录!
@else
我没有任何记录!
@endif
2
3
4
5
6
7
# 循环 for foreach
除了条件表达式外,Blade 也支持 PHP 的循环结构:
@for ($i = 0; $i < 10; $i++)
目前的值为 {{ $i }}
@endfor
@foreach ($users as $user)
<p>此用户为 {{ $user->id }}</p>
@endforeach
@forelse ($users as $user)
<li>{{ $user->name }}</li>
@empty
<p>没有用户</p>
@endforelse
@while (true)
<p>我永远都在跑循环。</p>
@endwhile
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 定义页面布局
使用 Blade 模板的两个主要优点为 模板继承 与 区块。
让我们先通过一个简单的例子来上手。首先,我们需要确认一下「主要的」页面布局。大多数的网页应用程序在不同页面都保持着相同的布局方式,这种布局在这单个 Blade 视图中可以很方便的定义:
<html>
<head>
<title>应用程序名称 - @yield('title')</title>
</head>
<body>
@section('sidebar')
这是主要的侧边栏。
@show
<div class="container">
@yield('content')
</div>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
如你所见,这个文件包含了传统的 HTML 语法。不过,请注意 @section 与 @yield 命令。正如其名,@section 命令定义一个内容区块,而 @yield 命令被用来 “显示指定区块” 的内容。
现在,我们已经定义好了这个应用程序的布局,让我们接着来定义一个继承此布局的子页面。
# 继承页面布局
当正在定义子页面时,你可以使用 Blade 的 @extends 命令指定子页面应该「继承」哪一个布局。当视图 @extends Blade 的布局之后,即可使用 @section 命令将内容注入于布局的区块中。切记,如上述例子所见,这些区块的内容都会使用 @yield 显示在布局中:
@extends('theme.pc.default.frame')
@section('title', '页面标题')
@section('sidebar')
@parent
<p>这边会附加在主要的侧边栏。</p>
@endsection
@section('content')
<p>这是我的主要内容。</p>
@endsection
2
3
4
5
6
7
8
9
10
11
12
在这个例子中,sidebar 区块利用了 @parent 命令增加(而不是覆盖)内容至布局的侧边栏。@parent 命令会在视图输出时被置换成布局的内容。
# 大括号不转义输出
由于许多 JavaScript 框架也使用「大括号」在浏览器中显示指定的表达式,因此可以使用 @ 符号来告知 Blade 渲染引擎该表达式应该维持原样。举个例子:
Hello, @{{ name }}.
在这个例子中,@ 符号会被 Blade 移除。而且,Blade 引擎会保留 表达式,如此一来便可跟其它 JavaScript 框架一起应用。
# 显示未转义过的数据
在默认情况下,Blade 模板中的 表达式将会自动调用 PHP 的 htmlentities 函数,以避免 XSS 攻击。如果你不希望你的数据被转义,可以使用下列的语法:
Hello, {!! $name !!}.
注意:要非常小心处理用户提供的字符串,请总是使用双大括号语法来转义内容中的 HTML 元素,以避免 XSS 攻击。
# 引入子视图
Blade 的 @include 命令用来引入已存在的视图,所有在父视图的可用变量在被引入的视图中都是可用的。
@include('share.header')
尽管被引入的视图会继承父视图中的所有数据,你也可以通过传递额外的数组数据至被引入的页面:
@include('view.name', ['some' => 'data'])
使用说明:
@include('module::Xxx.View.pc.a.b')
表示包含路径module/Xxx/View/pc/a/b.blade.php
视图文件
@include('theme.default.pc.a.b')
表示包含路径resources/views/theme/default/pc/a/b.blade.php
视图文件如果视图文件以
module::
开头,表示是目录module/
中的视图,否则为resources/views/theme/
中的视图
# 当数据存在时输出
有时候你想要输出一个变量,但你并不确定这个变量是否已被设置。我们可以用像这样的冗长 PHP 代码表达:
{{ isset($name) ? $name : '默认值' }}
在这个例子中,如果 $name 变量存在,它的值将会被显示出来。但是,如果这个变量不存在,便会显示 默认值
。
# 注释
Blade 也允许在页面中定义注释,然而,跟 HTML 的注释不同的是,Blade 注释不会被包含在应用程序返回的 HTML 内:
{{-- 此注释将不会出现在渲染后的 HTML --}}