# CMS主题教程

# Cms主题模块开发步骤

# 第一步、准备工作

# 1.1) 准备静态HTML模板

准备需要开发的静态资源模板文件,结构可参考如下

└─ template/                       → 模板根目录
     └─ static/                    → 静态资源
          ├─ css/
          │    ├── style.css
          │    └── ......
          ├─ js/
          │    ├── script.js
          │    └── ......
          ├─ image/
          │    ├── image.jpg
          │    └── ......
          ├─ listDefault.html     → 默认列表
          ├─ listNews.html        → 新闻列表
          ├─ listProduct.html     → 产品列表
          ├─ listCase.html        → 案例列表
          ├─ detailDefault.html   → 默认详情
          ├─ detailNews.html      → 新闻详情
          ├─ detailProduct.html   → 产品详情
          ├─ detailCase.html      → 案例详情
          └─ index.html           → 首页
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 1.2) 安装模块开发助手

模块开发助手可以极大效率的提高开发效率,在 系统管理 → 模块管理 安装 模块开发助手 (opens new window)

# 第二步、模块开发

# 2.1) 创建模块

访问 系统管理 → 模块开发助手,通过常用工具创建模块

# 2.2) 安装启用主题模块

访问 系统管理 → 模块管理 → 本地模块,安装并启用模块。

# 2.3) 主题模块开发完成

以下教程以主题模块 CmsThemeMyTest 为例进行。

2.3.1) 复制静态资源

复制静态HTML模板中的所有静态资源文件 template/static/ 到主题模块静态资源 module/CmsThemeMyTest/Asset 中。

如,静态HTML模板结构为

└─ template/                        → 模板根目录
    └─ static/
        ├─ css
        │   └─ style.css
        ├─ js
        │   └─ script.js
        └─ image
            └─ image.jpg
1
2
3
4
5
6
7
8

复制到模块静态资源结构为

└─ module/CmsThemeMyTest/Asset/      → 模块静态资源结构
    └─ static/
        ├─ css
        │   └─ style.css
        ├─ js
        │   └─ script.js
        └─ image
            └─ image.jpg
1
2
3
4
5
6
7
8

2.3.2) 做静态资源软连

开发阶段为了模块开发方便,访问的静态资源使用软连链接到模块静态资源文件夹。先删除 public/vendor/CmsThemeMyTest/ 目录,然后执行以下命令完成软连创建。

php artisan modstart:module-link-asset CmsThemeMyTest

这样,访问路径 http://example.com/vendor/CmsThemeMyTest/css/style.css 路径会定向到文件 module/CmsThemeMyTest/Asset/css/style.css

2.3.3) 完成模板开发

复制以下页面到模块,并完成页面功能开发。

  • 列表页listDefault.htmlmodule/CmsThemeMyTest/View/pc/cms/list/default.blade.php
  • 列表页listNews.htmlmodule/CmsThemeMyTest/View/pc/cms/list/news.blade.php
  • 列表页listProduct.htmlmodule/CmsThemeMyTest/View/pc/cms/list/product.blade.php
  • 列表页listCase.htmlmodule/CmsThemeMyTest/View/pc/cms/list/case.blade.php
  • 详情页detailDefault.htmlmodule/CmsThemeMyTest/View/pc/cms/detail/default.blade.php
  • 详情页detailNews.htmlmodule/CmsThemeMyTest/View/pc/cms/detail/news.blade.php
  • 详情页detailProduct.htmlmodule/CmsThemeMyTest/View/pc/cms/detail/product.blade.php
  • 详情页detailCase.htmlmodule/CmsThemeMyTest/View/pc/cms/detail/case.blade.php
  • 首页index.htmlmodule/CmsThemeMyTest/View/pc/cms/index.blade.php

要面开发主要需要以下两个步骤:

① 完成页面所有静态资源的路径替换

将所有路径 path/to/static 替换为 @asset('vendor/CmsThemeMyTest/path/to/static')

script
<script src="static/js/script.js"></script>
替换为
<script src="@asset('vendor/CmsThemeMyTest/static/js/script.js')"></script>

css
<link rel="stylesheet" href="static/css/style.css">
替换为
<link rel="stylesheet" href="@asset('vendor/CmsThemeMyTest/static/css/style.css')">

图片
<img src="static/image/image.jpg" />
替换为
<img src="@asset('vendor/CmsThemeMyTest/static/image/image.jpg')" />
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

② 完成页面变量替换和内容渲染

该部分每个页面需要参考个页面可用变量完成开发和内容替换。

更多的主题模块的开发可以参照 CmsThemeDemo (opens new window),该示例中涵盖了主题模块开发的示例。

# 第三步、模块发布分享

# 3.1) 账户信息认证

  1. 注册ModStart账号:访问 https://modstart.com (opens new window) 完成账号注册
  2. 实名认证:在用户中心完成用户实名认证

# 3.2) 在平台创建信息模块

个人中心 → 开发者 → 开发者中心 创建模块,填写基础模块信息完成创建。

创建模块

# 3.3) 模块打包上传到模块市场

进入 系统管理 → 模块开发助手 ,使用相同的 ModStart 账号登录,对于拥有的模块操作栏会出现发布按钮,点击发布一键发布到模块市场。

模块打包上传

发布成功后,需要后台审核模块,完成审核后模块即可显示在模块市场。

# 模块文件介绍

# 目录结构

module/CmsThemeXxx
├─ Admin/                             → 后台管理
│    ├─ Controller/
│    │    └─ ConfigController.php     → 后台配置开发Controller
│    └─ routes.php                    → 路由
├─ Asset/                             → 模块资源文件,安装后会复制到 public/vendor/CmsThemeXxx
│    └─ ......
├─ Core/
│    ├─ CmsThemeProvider.php          → CMS主题注册器
│    ├─ ModuleServiceProvider.php     → 模块核心注册器
│    └─ ThemeSiteTemplateProvider.php → 主题注册器,用于注册当前模块为博客主题
├─ Docs/                              → 模块文档
│    ├─ module/
│    │    ├─ content.md               → 模块介绍,发布时自动更新到模块介绍
│    │    ├─ demo.md                  → 模块演示,发布时自动更新到模块演示
│    │    ├─ mobilePreview.md         → 模块手机预览图,每行一个支持多个,发布时自动更新
│    │    └─ preview.md               → 模块电脑端预览图,每行一个支持多个,发布时自动更新
│    └─ release.md                    → 模块发布日志,发布时自动更新到模块发布日志
├─ Lang/                              → 多语言
│    ├─ en.php                        → 英文语言包
│    └─ zh.php                        → 中文语言包
├─ View/                              → 模块视图主目录
│    └─ pc/                           → 电脑端视图
│         ├─ cms/                     → CMS视图
│         │    ├─ detail/             → 详情视图
│         │    │ ├─ default.blade.php  
│         │    │ └─ ......
│         │    ├─ form/               → 表单视图
│         │    │ └─ default.blade.php
│         │    ├─ list/               → 列表视图
│         │    │ ├─ default.blade.php  
│         │    │ └─ ......
│         │    ├─ page/               → 单页视图
│         │    │ └─ default.blade.php
│         │    └─ index.blade.php     → 首页
│         ├─ footer.blade.php         → 公共视图底部
│         ├─ frame.blade.php          → 公共视图框架
│         ├─ frameTheme.blade.php     → 主题视图框架
│         └─ header.blade.php         → 公共视图顶部
└─ config.json                        → 模块配置文件
1
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
35
36
37
38
39
40

# CMS链接

  • /tag/{name} 标签列表
  • /a/{id} 内容页面
  • /search?keywords={keywords} 搜索列表

除了以上默认的地址方式外,所有页面都需要在后台栏目中自定义。

# CMS首页 cms.index

首页暂无系统变量,所有页面部分均需自定调用。

# 列表页面 cms.list.default

# 内容记录 $records

循环输入内容列表

@foreach($records as $record)
    <a href="{{$record['_url']}}">{{$record['title']}}</a>
@endforeach
1
2
3
变量 说明
$records 记录数组
├ $record['id'] 内容ID
├ $record['created_at'] 创建时间
├ $record['updated_at'] 更新时间
├ $record['catId'] 栏目ID
├ $record['modelId'] 模型ID
├ $record['title'] 标题
├ $record['summary'] 摘要
├ $record['cover'] 封面
├ $record['postTime'] 发布时间
├ $record['wordCount'] 字数
├ $record['viewCount'] 浏览次数
├ $record['commentCount'] 评论数
├ $record['likeCount'] 喜欢数
├ $record['isRecommend'] 是否推荐
├ $record['isTop'] 是否置顶
├ $record['tags'] 标签
├ $record['_tags'] 标签数组 ['标签1', ...]
├ $record['_tagList] 标签数组 [ {'name':'标签1','url':'标签2'}, ...]
├ $record['author'] 作者
├ $record['source'] 来源
├ $record['seoTitle'] SEO标题
├ $record['seoDescription'] SEO描述
├ $record['seoKeywords'] SEO关键词
├ $record['_url'] 内容URL
├ $record['_day'] 内容发布日期
└ $record['_data']['xxx'] 自定义字段

# 当前栏目 $cat


变量 说明
$cat['id'] 栏目ID
$cat['pid'] 父级栏目ID
$cat['title'] 栏目标题
$cat['url'] 栏目URL
$cat['modelId'] 栏目模型ID
$cat['seoTitle'] SEO标题
$cat['seoDescription'] SEO描述
$cat['seoKeywords'] SEO关键词
$cat['icon'] 栏目图标
$cat['cover'] 栏目封面
$cat['subTitle'] 栏目子标题
$cat['bannerBg'] 栏目Banner背景
$cat['_model'] 栏目模型
$cat['_model']['title'] 栏目模型名称
$cat['_model']['name'] 栏目模型标识

# 顶级栏目 $catRoot

如果当前栏目为顶级栏目,则该变量与 $cat 相同。


变量 说明
$cat['id'] 栏目ID
$cat['pid'] 父级栏目ID
$cat['title'] 栏目标题
$cat['url'] 栏目URL
$cat['modelId'] 栏目模型ID
$cat['seoTitle'] SEO标题
$cat['seoDescription'] SEO描述
$cat['seoKeywords'] SEO关键词
$cat['icon'] 栏目图标
$cat['cover'] 栏目封面
$cat['subTitle'] 栏目子标题
$cat['bannerBg'] 栏目Banner背景
$cat['_model'] 栏目模型
$cat['_model']['title'] 栏目模型名称
$cat['_model']['name'] 栏目模型标识

# 子栏目 $catChildren

@foreach ($catChildren as $cat)
    <a href="{{$cat['_url']}}">{{$cat['title']}}</a>
@endforeach
1
2
3

变量 说明
$cats 记录数组
├ $cat['id'] 栏目ID
├ $cat['pid'] 父级栏目ID
├ $cat['title'] 栏目标题
├ $cat['url'] 栏目URL
├ $cat['modelId'] 栏目模型ID
├ $cat['seoTitle'] SEO标题
├ $cat['seoDescription'] SEO描述
├ $cat['seoKeywords'] SEO关键词
├ $cat['icon'] 栏目图标
├ $cat['cover'] 栏目封面
├ $cat['subTitle'] 栏目子标题
├ $cat['bannerBg'] 栏目Banner背景
├ $cat['_model'] 栏目模型
├ $cat['_model']['title'] 栏目模型名称
└ $cat['_model']['name'] 栏目模型标识

# 顶级栏目子栏目 $catRootChildren

@foreach ($catRootChildren as $cat)
    <a href="{{$cat['_url']}}">{{$cat['title']}}</a>
@endforeach
1
2
3

变量 说明
$cats 记录数组
├ $cat['id'] 栏目ID
├ $cat['pid'] 父级栏目ID
├ $cat['title'] 栏目标题
├ $cat['url'] 栏目URL
├ $cat['modelId'] 栏目模型ID
├ $cat['seoTitle'] SEO标题
├ $cat['seoDescription'] SEO描述
├ $cat['seoKeywords'] SEO关键词
├ $cat['icon'] 栏目图标
├ $cat['cover'] 栏目封面
├ $cat['subTitle'] 栏目子标题
├ $cat['bannerBg'] 栏目Banner背景
├ $cat['_model'] 栏目模型
├ $cat['_model']['title'] 栏目模型名称
└ $cat['_model']['name'] 栏目模型标识

# 栏目面包屑 $catChain

@foreach ($catChain as $cat)
    <a href="{{$cat['_url']}}">{{$cat['title']}}</a>
@endforeach
1
2
3

变量 说明
$cats 记录数组
├ $cat['id'] 栏目ID
├ $cat['pid'] 父级栏目ID
├ $cat['title'] 栏目标题
├ $cat['url'] 栏目URL
├ $cat['modelId'] 栏目模型ID
├ $cat['seoTitle'] SEO标题
├ $cat['seoDescription'] SEO描述
├ $cat['seoKeywords'] SEO关键词
├ $cat['icon'] 栏目图标
├ $cat['cover'] 栏目封面
├ $cat['subTitle'] 栏目子标题
├ $cat['bannerBg'] 栏目Banner背景
├ $cat['_model'] 栏目模型
├ $cat['_model']['title'] 栏目模型名称
└ $cat['_model']['name'] 栏目模型标识

# 分页 $page $pageSize $pageHtml


# 当前页数 $page

{{$page}}
1

# 分页大小 $pageSize

{{$pageSize}}
1

# 分页HTML

$pageHtml

{!! $pageHtml !!}
1

当前列表分页HTML数据


<div class="pages">
    <a href="?page=1">1</a>
    <span>2</span>
    <a href="?page=1">3</a>
</div>
1
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>',
]) !!}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 下一页链接 $pageNextUrl

{{$pageNextUrl}}
1

# 上一页链接 $pagePrevUrl

{{$pagePrevUrl}}
1

# 列表条件过滤

如果需要进行自定义字段的筛选,需要设置字段以下属性

  • 字段开启「列表搜索」
  • 字段开启「访客列表页面可见」

随后在URL中传递该参数即可实现列表页面的条件过滤。

# 详情页面 cms.detail.default

# 内容详情 $record

标题:{{ $record['title'] }}
内容:{{ $record['content'] }}
1
2
变量 说明
$record['id'] 内容ID
$record['created_at'] 创建时间
$record['updated_at'] 更新时间
$record['catId'] 栏目ID
$record['modelId'] 模型ID
$record['title'] 标题
$record['summary'] 摘要
$record['cover'] 封面
$record['postTime'] 发布时间
$record['wordCount'] 字数
$record['viewCount'] 浏览次数
$record['commentCount'] 评论数
$record['likeCount'] 喜欢数
$record['isRecommend'] 是否推荐
$record['isTop'] 是否置顶
$record['tags'] 标签数组
$record['_tags'] 标签数组 ['标签1', ...]
$record['_tagList] 标签数组 [ {'name':'标签1','url':'标签2'}, ...]
$record['author'] 作者
$record['source'] 来源
$record['seoTitle'] SEO标题
$record['seoDescription'] SEO描述
$record['seoKeywords'] SEO关键词
$record['_data']['content'] 内容
$record['_data']['xxx'] 自定义字段

# 当前栏目 $cat

变量 说明
$cat['id'] 栏目ID
$cat['pid'] 父级栏目ID
$cat['title'] 栏目标题
$cat['url'] 栏目URL
$cat['modelId'] 栏目模型ID
$cat['seoTitle'] SEO标题
$cat['seoDescription'] SEO描述
$cat['seoKeywords'] SEO关键词
$cat['icon'] 栏目图标
$cat['cover'] 栏目封面
$cat['subTitle'] 栏目子标题
$cat['bannerBg'] 栏目Banner背景
$cat['_model'] 栏目模型
$cat['_model']['title'] 栏目模型名称
$cat['_model']['name'] 栏目模型标识

# 表单页面 cms.form.default

# 通用表单

提交到 modstart_api_url('cms/form/submit',['cat'=>7]) ,其中 cat 为栏目ID。

需要提交的字段,提交则字段不能全部为空。

  • content 内容
  • xxx 其他自定义字段

# 留言本

<form action="{{ modstart_web_url('cms/form/submit',['cat'=>7]) }}" 
    method="post" data-ajax-form>
    手机:<input type="text" name="phone" >
    姓名:<input type="text" name="name" >
    内容:<input type="text" name="content" >
    <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>
1
2
3
4
5
6
7
8
9
10

# 标签页 cms.tag.index

# 搜索页 cms.search.index

# 通用页面

# 公共变量

  • $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') }}
1
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('Cms_CompanyName') }}
// 企业传真
{{ modstart_config('Cms_ContactFax') }}
// 联系人
{{ modstart_config('Cms_ContactContactPerson') }}
// 企业联系QQ
{{ modstart_config('Cms_ContactQQ') }}
// 企业介绍标题
{{ modstart_config('Cms_HomeInfoTitle') }}
// 企业介绍图片
{{ modstart_config_asset_url('Cms_HomeInfoImage') }}
// 企业介绍说明,富文本
{!! modstart_config('Cms_HomeInfoContent') !!}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 导航


# 循环显示导航

@foreach(MNav::all('head') as $nav)
    <a href="{{ $nav['link'] }}">{{ $nav['name'] }}</a>
@endforeach
1
2
3
变量 说明
$nav['name'] 导航名称
$nav['link'] 导航链接
$nav['_child'] 子导航(空表示只有一级导航,不为空表示为二级导航)
$nav['openType'] 打开方式(2=新窗口 其他值=当前窗口)

# 不同的位置

MNav::all('head'); // 头部导航
MNav::all('foot'); // 底部导航
1
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
1
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
1
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
1
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')
1
2
3
4

更多使用可参考 Banner (opens new window) 模块

# 友情链接


# 循环显示友情链接

// 循环特定位置友情链接
@foreach(\MPartner::all('Xxx') as $partner)
  <a href="{{ $partner['link'] }}">{{ $partner['title'] }}</a>
@endforeach
1
2
3
4

# 不同位置友情链接

// 位置 Blog
\MPartner::all('Blog')
// 位置 Cms
\MPartner::all('Cms')
1
2
3
4

更多使用可参考 Partner (opens new window) 模块

# 站点地图


启用网站需要安装 SiteMapManager (opens new window) 模块获得支持,设置后访问路径如下:

  • `http://www.example.com/sitemap.xml`

系统使用动态站点地图,不需要手动生成,访问地址即为实时地图,输出格式为xml格式。具体使用方式可参考 SiteMapManager (opens new window) 模块的使用方法。

image-20220621084218094

# 用户


@if(\Module\Member\Auth\MemberUser::isLogin())
    用户ID{{$_memberUser['id']}}
    用户名:{{$_memberUser['username']}}
    昵称:{{$_memberUser['nickname']}}
@else
    请登录
@endif
1
2
3
4
5
6
7
变量 说明
$_memberUserId 用户ID,可以判断该变量是否为空来判断用户是否登录
$_memberUser['id'] 用户ID
$_memberUser['username'] 用户名
$_memberUser['avatar'] 头像
$_memberUser['nickname'] 昵称

更多参考 Member (opens new window)

# 内容区块


# 获取一个区块内容

@foreach([MContentBlock::getCached('标识')] as $cb)
    @if(!empty($cb))
        <p>类型:{{$cb['type']}}</p>
        <p>名称:{{$cb['name']}}</p>
        <p>备注:{{$cb['remark']}}</p>
        <p>通用</p>
        <p>图片:{{join(',',$cb['texts'])}}</p>
        <p>图片:{{join(',',$cb['basicImages'])}}</p>
        <p>图片</p>
        <p>图片:{{$cb['image']}}</p>
        <p>富文本</p>
        <p>HTML{{$cb['content']}}</p>
    @endif
@endforeach
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 获取多个区块内容

@foreach(MContentBlock::allCached('标识',5) as $cb)
    <p>类型:{{$cb['type']}}</p>
    <p>名称:{{$cb['name']}}</p>
    <p>备注:{{$cb['remark']}}</p>
    <p>通用</p>
    <p>图片:{{join(',',$cb['texts'])}}</p>
    <p>图片:{{join(',',$cb['basicImages'])}}</p>
    <p>图片</p>
    <p>图片:{{$cb['image']}}</p>
    <p>富文本</p>
    <p>HTML{{$cb['content']}}</p>
@endforeach
1
2
3
4
5
6
7
8
9
10
11
12

# 指定内容

// 根据ID获取内容
<?php $record = MCms::getContent(1); ?>
1
2
标题:{{ $record['title'] }}
内容:{{ $record['content'] }}
1
2
变量 说明
$record['id'] 内容ID
$record['created_at'] 创建时间
$record['updated_at'] 更新时间
$record['catId'] 栏目ID
$record['modelId'] 模型ID
$record['title'] 标题
$record['summary'] 摘要
$record['cover'] 封面
$record['postTime'] 发布时间
$record['wordCount'] 字数
$record['viewCount'] 浏览次数
$record['commentCount'] 评论数
$record['likeCount'] 喜欢数
$record['isRecommend'] 是否推荐
$record['isTop'] 是否置顶
$record['tags'] 标签数组
$record['_tags'] 标签数组 ['标签1', ...]
$record['_tagList] 标签数组 [ {'name':'标签1','url':'标签2'}, ...]
$record['author'] 作者
$record['source'] 来源
$record['seoTitle'] SEO标题
$record['seoDescription'] SEO描述
$record['seoKeywords'] SEO关键词
$record['_data']['content'] 内容
$record['_data']['xxx'] 自定义字段

# 指定栏目

// 根据栏目ID获取栏目信息
<?php $cat = MCms::getCat(1); ?>
// 根据栏目URL获取栏目信息
<?php $cat = MCms::getCatByUrl('news'); ?>
1
2
3
4
变量 说明
$cat['id'] 栏目ID
$cat['pid'] 父级栏目ID
$cat['title'] 栏目标题
$cat['url'] 栏目URL
$cat['modelId'] 栏目模型ID
$cat['seoTitle'] SEO标题
$cat['seoDescription'] SEO描述
$cat['seoKeywords'] SEO关键词
$cat['icon'] 栏目图标
$cat['cover'] 栏目封面
$cat['subTitle'] 栏目子标题
$cat['bannerBg'] 栏目Banner背景
$cat['_model'] 栏目模型
$cat['_model']['title'] 栏目模型名称
$cat['_model']['name'] 栏目模型标识

留言本使用了通用模型 id = 7 的内容模型,如过手动调整过内容模型,请自行修改代码。

# 表单详情

@foreach($cat['_model']['_customFields'] as $customField)
    @if($customField['fieldType']=='text')
        <!-- 文本字段 -->
        <div>
            {{$customField['title']}}
            :
            <input class="form" type="text" name="{{$customField['name']}}" />
        </div>
    @else
        <!-- 其他字段 -->
    @endif
@endforeach
1
2
3
4
5
6
7
8
9
10
11
12

具体可参照 通用表单模板 (opens new window)

# 可用变量

变量 说明
$customField['modelId'] 模型ID
$customField['title'] 字段名
$customField['name'] 字段
$customField['fieldType'] 字段类型
$customField['fieldData'] 字段数据
$customField['isRequired'] 必填
$customField['placeholder'] 输入提示

# 适配模块-标签云

需要安装 TagManager (opens new window) 模块。

@foreach (\Module\TagManager\Util\TagManagerUtil::allVisible('cms') as $tag)
    <a href="{{ modstart_web_url('tag/'.urlencode($tag['tag'])) }}">{{ $tag['tag'] }}</a>
@endforeach
1
2
3

更多使用方式参考 模块使用 (opens new window)

# 视图开发


# 网站主色调

可以通过 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
1
2
3
4
5
6
7
8
9

# 框架视图 frame.blade.php

通过会在模板文件中可以通过 @extends($_viewFrame) 来确定当前模板的框架视图,该文件通常包含公共的头部、尾部、侧边栏等内容。

$_viewFrame 会根据当前模板查找最先匹配到的文件,通常情况下,该变量会按照如下顺序查找:

  1. resources/views/theme/<主题>/pc/frame.blade.php
  2. module/<主题模块>/View/pc/frame.blade.php
  3. 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>
1
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
1
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') }}
1
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
1
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')" />
1
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" />
1
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');
1
2
3
4
5
6

页面 CSS 会自动放在头部(</head> 之前)

// 引入行内 css
\ModStart\ModStart::style('.test{ color:red; }');
// 引入一个 CSS 文件内容到页面
\ModStart\ModStart::styleFile('文件路径.css');
// 引入一个 CSS 文件路径到页面
\ModStart\ModStart::css('文件路径.css');
1
2
3
4
5
6

# 时间格式化

// $t = '2021-01-01 00:00:00'
date('Y-m-d', strtotime($t) )
1
2

时间格式化标签和PHP时间格式化语法一致,分别用不同字母代替,中间可以穿插任意字符,如:Y-m-dY/m/dY年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)
1
2

一般在首页等特殊位置需要调取正文一段纯文本时使用,这时一般会配合下面的内容截取标签一起使用

# 内容截取

// HTML
\ModStart\Core\Util\HtmlUtil::text($html,100)
// 非HTML
\ModStart\Core\Util\StrUtil::limit($text,100,'...')
1
2
3
4

限制输出 100 个字符

# 其它格式

// 限定浮点格式,更多参考 https://www.php.net/manual/en/function.sprintf.php
sprintf('%0.2f', 3.14159)
1
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()
1
2
3
4
5
6

# 当前页面URL

获取当前访问页面完整地址,通常用于生成二维码等

\ModStart\Core\Input\Request::currentPageUrl()
1

# 二维码生成

生成二维码数据

// 返回base64图片字符串
\ModStart\Core\Util\QrcodeUtil::pngBase64String('ModStart')
1
2

可直接用于显示,如

<img src="{!! \ModStart\Core\Util\QrcodeUtil::pngBase64String('ModStart') !!}" />
1

# 获取系统配置

网站配置全部位于 config 数据表中,查找 key 值,通过如下如下函数可以直接获取值,该函数已内置添加了缓存可在视图中多次调用。

modstart_config('xxx','默认值')
1

image-20220620171930360

# 模板语法


# 显示数据

你可以使用「中括号」包住变量以显示传递至 Blade 视图的数据。就如以下的路由设置一样:

return view('welcome', ['name' => 'Samantha']);
1

你可以像这样显示 name 变量的内容:

Hello, {{ $name }}.
1

显示数据或默认值

此写法兼容Laravel5和Laravel9+

{{ empty($name) ? '默认值' : $name }}
1

当然也不是说一定只能显示传递至视图的变量内容。你也可以显示 PHP 函数的结果。实际上,你可以放置任何你想要的 PHP 代码到 Blade 显示的语法里面:

目前的 UNIX 时间戳为 {{ time() }}
1

注意:Blade 的 语法会自动调用 PHP htmlentites 函数来防御 XSS 攻击。

# 条件判断 if

你可以使用 @if、@elseif、@else 及 @endif 命令建构 if 表达式。这些命令的功能等同于在 PHP 中的语法:

@if (count($records) === 1)
    我有一条记录!
@elseif (count($records) > 1)
    我有多条记录!
@else
    我没有任何记录!
@endif
1
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
1
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>
1
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
1
2
3
4
5
6
7
8
9
10
11
12

在这个例子中,sidebar 区块利用了 @parent 命令增加(而不是覆盖)内容至布局的侧边栏。@parent 命令会在视图输出时被置换成布局的内容。

# 大括号不转义输出

由于许多 JavaScript 框架也使用「大括号」在浏览器中显示指定的表达式,因此可以使用 @ 符号来告知 Blade 渲染引擎该表达式应该维持原样。举个例子:

Hello, @{{ name }}.
1

在这个例子中,@ 符号会被 Blade 移除。而且,Blade 引擎会保留 表达式,如此一来便可跟其它 JavaScript 框架一起应用。

# 显示未转义过的数据

在默认情况下,Blade 模板中的 表达式将会自动调用 PHP 的 htmlentities 函数,以避免 XSS 攻击。如果你不希望你的数据被转义,可以使用下列的语法:

Hello, {!! $name !!}.
1

注意:要非常小心处理用户提供的字符串,请总是使用双大括号语法来转义内容中的 HTML 元素,以避免 XSS 攻击。

# 引入子视图

Blade 的 @include 命令用来引入已存在的视图,所有在父视图的可用变量在被引入的视图中都是可用的。

@include('share.header')
1

尽管被引入的视图会继承父视图中的所有数据,你也可以通过传递额外的数组数据至被引入的页面:

@include('view.name', ['some' => 'data'])
1

使用说明:

@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 : '默认值' }}
1

在这个例子中,如果 $name 变量存在,它的值将会被显示出来。但是,如果这个变量不存在,便会显示 默认值

# 注释

Blade 也允许在页面中定义注释,然而,跟 HTML 的注释不同的是,Blade 注释不会被包含在应用程序返回的 HTML 内:

{{-- 此注释将不会出现在渲染后的 HTML --}}
1

# API接口


新窗口查看接口文档 (opens new window)

# 模块方法


新窗口查看CMS操作方法 (opens new window)

Last Updated: a year ago