一篇文带你从 0 到 1 了解建站及完成 CMS 系统编写02

329 阅读7分钟

3.5 完成登录功能编写

在 admin 模块中,index 控制器添加方法 login,内容为:

public function login(){
        return $this->view->fetch();
    }

前端代码使用 ajax 传值,前端页显示如下:

img

随后填入帐号及密码通过 ajax 传值到 admin 模块下的 Authpost 控制器中 login 方法中,内容如下:

    public function login(){
        $request_data = Request::post();
        $data['username']=$request_data['user'];
        $data['password']=md5(trim($request_data['password']));

        $res=db('admin')->where($data)->find();
        $res?session('admin', $res):$this->error('帐号或密码错误');
    }

使用 find 方法对传入值进行对比,密码正确则将值传入到 seesion 否则将提示帐号密码错误。

3.6 完成传入值的判断

在基本权限实现完成后,使用验证器对传入值进行判断,毕竟外部值都是不可靠的值。 在 controller 同级下创建一目录 validate,创建目录后在该目录下创建一 php 文件名为 BaseValidate 作为对数据进行判断类的基类,代码内容如下:

<?php
namespace app\admin\validate;

use think\Validate;
use think\Controller;
use app\admin\code\ReturnCodeInfo;

class BaseValidate extends Validate{

    public function gocheck($validata){
        if(!$this->check($validata)){
            return (new ReturnCodeInfo())->validataError($this->getError());
        }
        return (new ReturnCodeInfo())->validataSuccess();
    }
}

该类继承验证器类,具有验证器特性。验证器的使用查看 tp5.1 文档。 查看 gocheck 方法,gocheck 方法调用了验证器本身的 check 方法,其接收的参数 $validata 为需要验证的数据。check 判断错误则调用 ReturnCodeInfo 类中的报错数据返回,否则则返回正确。 假设在管理员添加时需要验证数据是否合规,那么在 validate 目录中创建一名为 AdminValidate 的 php 文件,内容为:

<?php
namespace app\admin\validate;

use app\admin\validate\BaseValidate;

class AdminValidate extends BaseValidate{
    protected $rule = [
        'password'  =>  'require|max:50',
        'username'  =>  'require|max:30',
        'realname'  =>  'require|max:30',
        'group'  =>  'require|max:30'
    ];

}

在管理员添加方法中(Authpost 控制器中的 adminadd 方法)添加:

        $valires=(new AdminValidate())->gocheck($data);
        if ($valires['code']==10002){
            return json($valires);
        }

即可完成,但一定要注意,需要引入该验证器:

use app\admin\validate\AdminValidate;

四、完成内容管理功能的编写

4.1 完成管理后台模块搭建

我们首先实现查看轮播图区域元素:

img

发现元素包含轮播图标题、简介,以及轮播图标题 1、简介 1 以及背景图。数据库设计如下:

img

我们通过 sqlyog 的可视化操作添加轮播图所需要资源的数据,可以通过邮件检查直接获取资源路径及内容:

img

首先得到轮播图第一张图片的数据:

img

复制内容填入 sqlyog 表中:

img

同理获取所有的内容填入至表:

img

所有内容填入数据库:

img

回到 index 模块下的 index 控制器中,在 index 方法中添加获取轮播图数据表中数据:

<?php
namespace app\index\controller;
use think\Controller;
use think\Db;

class Index extends Controller{
    public function index()
    {
        $banner_res=Db::table('tp_home_banner')
        ->order('id', 'desc')
        ->limit(4)
        ->select();
        print_r($banner_res);
        die;
        return $this->view->fetch();
    }

}

在以上代码中,使用 select 方法查询轮播图数据表中的数据,查询方式是 id 的降序,这样使轮播图将会以最新添加的作为显示依据,并且每次只查询前 4 条;查询结构复制给变量 banner_res,使用 print_r 对该变量进行输出,随后在输出模板前使用 die 终止,查看输出。 访问 localhost 成功获得数据:

img

在 index 方法中添加代码,像前端传递 banner_res 变量,并且删除 die 代码:

<?php
namespace app\index\controller;
use think\Controller;
use think\Db;

class Index extends Controller{
    public function index()
    {
        $banner_res=Db::table('tp_home_banner')
        ->order('id', 'desc')
        ->limit(4)
        ->select();

        $this->view->assign('banner',$banner_res);
        return $this->view->fetch();
    }

}

接下来我们将在 html 代码中使用 tp 的前端模板语法对一些 html 元素进行控制。我们通过元素查询得知轮播图元素 id 为 homev1:

img

在代码中找到 id 为 homev1 的元素,查看代码,每个轮播图标签类似,只有默认选项多了个 class 修饰:

img

但是有些小伙伴觉得很麻烦,那我们换一种方式,使用 tp 框架前端的模板语法,类似 if 判断,从而输出内容:

img

首先使用 volist 标签进行循环,在标签中设置循环变量 key,该 key 循环第一次的值为 1,当为 1 使用 eq 标签判断,是 1 则输出第一个轮播图的 html 代码:

{eq name="k" value="1"}

需要输出的 html 代码需要使用成对的 eq 标签包含,结束的 eq 标签为 {/eq}。 代码如下:

<div class="carousel-inner" role="listbox">
                        
                        {volist name="banner" id="vo" key="k" }
                        {eq name="k" value="1"}
                        <div class="item active">
                            
                            <img src="{$vo.img}" alt="SeoPress Slider" />
                            <div class="bs-slider-overlay"></div>

                            <div class="container">
                                <div class="row">
                                    <div class="col-md-8 col-md-offset-2">
                                        <div class="slide-text slide_style_center">
                                            <h1 class="text-white" data-animation="animated zoomInRight">{$vo.title}</h1>
                                            <p class="text-white m-top-10" data-animation="animated fadeInLeft">{$vo.content}</p>
                                            <a class="btn btn-primary btn-round m-top-30" data-animation="animated fadeInLeft" href="" target="_blank">Read More</a>
                                            <a class="btn btn-default btn-round m-top-30" data-animation="animated fadeInRight" href="" target="_blank">Read More</a>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                        {/eq}
                        
                        {eq name="k" value="2"}
                        
                        <div class="item">
                            <img src="{$vo.img}" alt="SeoPress Slider" />
                            <div class="bs-slider-overlay"></div>
                            <div class="container">
                                <div class="row">
                                    
                                    <div class="col-md-6">
                                        <div class="slide-text slide_style_left">
                                            <h1 class="text-white" data-animation="animated fadeInRight">{$vo.title}</h1>
                                            <p class="text-white m-top-10" data-animation="animated zoomInLeft">{$vo.content}
                                            </p>

                                            <a class="btn btn-default btn-round m-top-30" data-animation="animated fadeInRight" href="" target="_blank">Read More</a>
                                            <a class="btn btn-primary btn-round m-top-30" data-animation="animated fadeInLeft" href="" target="_blank">Read More</a>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                        
                        {/eq}
                        {eq name="k" value="3"}
                        
                        <div class="item">
                            <img src="{$vo.img}" alt="SeoPress Slider" />
                            <div class="bs-slider-overlay"></div>
                            <div class="container">
                                <div class="row">
                                    
                                    <div class="col-md-6">
                                        <div class="slide-text slide_style_left">
                                            <h1 class="text-white" data-animation="animated fadeInDown">{$vo.title}</h1>
                                            <p class="text-white m-top-10" data-animation="animated fadeInLeft">{$vo.content}
                                            </p>

                                            <a class="btn btn-primary btn-round m-top-30" data-animation="animated fadeInLeft" href="" target="_blank">Read More</a>
                                            <a class="btn btn-default btn-round m-top-30" data-animation="animated fadeInRight" href="" target="_blank">Read More</a>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </div>
                        {/eq}
                        {eq name="k" value="4"}
                        
                        <div class="item">
                            <img src="{$vo.img}" alt="SeoPress Slider" />
                            <div class="bs-slider-overlay"></div>
                            <div class="container">
                                <div class="row">
                                    
                                    <div class="col-md-6">
                                        <div class="slide-text slide_style_left">
                                            <h1 class="text-white" data-animation="animated fadeInLeft">{$vo.title} <br />
                                                Online Marketing Needs</h1>
                                            <p class="text-white m-top-10" data-animation="animated fadeInRight">{$vo.content}
                                            </p>
                                            <a class="btn btn-primary btn-round m-top-30" data-animation="animated fadeInLeft" href="" target="_blank">Read More</a>
                                            <a class="btn btn-default btn-round m-top-30" data-animation="animated fadeInRight" href="" target="_blank">Read More</a>
                                        </div>
                                    </div>

                                </div>
                            </div>
                        </div>
                        {/eq}
                        {/volist}
                        
                    </div>

接着我们往下查看首页内容:

img

个人觉得该区域可以放一个 “有利于” 之类的宣传语,那么建一表存放标题、图片、内容信息:

img

在该表中填入网页中原有的数据:

img

在 index 控制器中添加查询 tp_home_advantageous 表数据的代码并将结果传至前端:

<?php
namespace app\index\controller;
use think\Controller;
use think\Db;

class Index extends Controller{
    public function index()
    {
        $banner_res=Db::table('tp_home_banner')
        ->order('id', 'desc')
        ->limit(4)
        ->select();

        $advantageous_res=Db::table('tp_home_advantageous')
        ->order('id', 'desc')
        ->limit(6)
        ->select();

        $this->view->assign('advantageous',$advantageous_res);
        $this->view->assign('banner',$banner_res);
        return $this->view->fetch();
    }

}

修改前端代码,发现该区域代码的 html 几乎一致,前 3 个的 class=“service-item sm-m-top-65”,后 3 个的 class=“service-item m-top-65”:

<div class="main-service-area text-center m-top-80">
                            <div class="col-md-4 col-sm-6">
                                <div class="service-item sm-m-top-65">
                                    <div class="service-icon">
                                        <img src="/home/assets/images/service1.png" alt="" />
                                    </div>
                                    <h5 class="text-info m-top-50">Search Engine Optimization</h5>
                                    <p class="text-black m-top-20">With our 17+ years of experience, our SEO services will get your site ranking.</p>
                                </div>
                            </div>
                            <div class="col-md-4 col-sm-6">
                                <div class="service-item sm-m-top-65">
                                    <div class="service-icon">
                                        <img src="/home/assets/images/service3.png" alt="" />
                                    </div>
                                    <h5 class="text-info m-top-50">Content Marketing</h5>
                                    <p class="text-black m-top-20">From blogs and social posts to 
                                        infographics videos we create and promote quality.</p>
                                </div>
                            </div>
                            <div class="col-md-4 col-sm-6">
                                <div class="service-item sm-m-top-65">
                                    <div class="service-icon">
                                        <img src="/home/assets/images/service2.png" alt="" />
                                    </div>
                                    <h5 class="text-info m-top-50">Social Media Marketing</h5>
                                    <p class="text-black m-top-20">Boost brand awareness and reach your 
                                        customers on a human level.</p>
                                </div>
                            </div>
                            <div class="col-md-4 col-sm-6">
                                <div class="service-item m-top-65">
                                    <div class="service-icon">
                                        <img src="/home/assets/images/service4.png" alt="" />
                                    </div>
                                    <h5 class="text-info m-top-50">Web Design & Development</h5>
                                    <p class="text-black m-top-20">Our designers and developers will create an attractive, SEO-friendly & fully functional.</p>
                                </div>
                            </div>
                            <div class="col-md-4 col-sm-6">
                                <div class="service-item m-top-65">
                                    <div class="service-icon">
                                        <img src="/home/assets/images/service5.png" alt="" />
                                    </div>
                                    <h5 class="text-info m-top-50">eCommerce Solutions</h5>
                                    <p class="text-black m-top-20">With our 17+ years of experience, 
                                        our SEO services will get your site ranking.</p>
                                </div>
                            </div>
                            <div class="col-md-4 col-sm-6">
                                <div class="service-item m-top-65">
                                    <div class="service-icon">
                                        <img src="/home/assets/images/service6.png" alt="" />
                                    </div>
                                    <h5 class="text-info m-top-50">Inbound Marketing</h5>
                                    <p class="text-black m-top-20">With our ecommerce solutions, 
                                        you'll provide an enjoyable, seamless.</p>
                                </div>
                            </div>
                        </div>

这是把其它 div 删除,留下 1 个 div,使用 volist 标签进行遍历输出值,并且设置循环变量 key,使用 tp 框架的前端判断标签,判断小于 4 时输出 class 为 col-sm-6:

{lt name="k" value="4"}col-sm-6{/eq}

当循环后 3 三位,则是 k 值大于 3,大于 3 输出 col-sm-6,使用 gt 标签:

{gt name="k" value="3"}col-sm-6{/eq}

将两个前端代码编写与 div 中,完整代码如下:

<div class="main-service-area text-center m-top-80">
    {volist name="advantageous" id="vo" key="k" }
    <div class="col-md-4 col-sm-6">
        <div class='service-item {lt name="k" value="4"}col-sm-6{/eq} {gt name="k" value="3"}col-sm-6{/eq}'>
            <div class="service-icon">
                <img src="{$vo.img}" alt="" />
            </div>
            <h5 class="text-info m-top-50">{$vo.title}</h5>
            <p class="text-black m-top-20">{$vo.content}</p>
        </div>
    </div>
    {/volist}
</div>

运行结果:

img

接着往下,查看页面区域:

img

我们将该页面编写成产品展示区域。新建一数据库表:

img

填入内容:

img

在 index 控制器 index 方法中添加 product 数据库查询代码并传至前端:

<?php
namespace app\index\controller;
use think\Controller;
use think\Db;

class Index extends Controller{
    public function index()
    {
        $banner_res=Db::table('tp_home_banner')
        ->order('id', 'desc')
        ->limit(4)
        ->select();

        $advantageous_res=Db::table('tp_home_advantageous')
        ->order('id', 'desc')
        ->limit(6)
        ->select();

        $product_res=Db::table('tp_home_product')
        ->order('id', 'desc')
        ->limit(2)
        ->select();

        $this->view->assign('product',$product_res);
        $this->view->assign('advantageous',$advantageous_res);
        $this->view->assign('banner',$banner_res);
        return $this->view->fetch();
    }

}

随后在 html 代码中输出内容即可:

<section id="leading" class="leading bg-primary sections2">
                <div class="container">
                    <div class="row">
                        <div class="main-leading">
                            <div class="col-md-6">
                                <div class="leading-content">
                                    <div class="head-title">
                                        <h2 class="text-white">{$product[0]['title']}</h2>
                                        <p class="m-top-30 text-white">{$product[0]['specs']}</p>

                                        <div class="separator2 hv2"><span></span><span></span><span></span></div>
                                    </div>

                                    <p class="m-top-40">{$product[0]['content']}</p>
                                    <a href="" class="btn btn-default btn-round m-top-20">Our Team</a>

                                </div>
                            </div>
                            <div class="col-md-5">
                                <div class="leading-img sm-m-top-50">
                                    <img src="{$product[0]['img']}" alt="" />
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </section>
            
            <section id="allies" class="allies sections">
                <div class="container">
                    <div class="row">

                        <div class="main-allies">
                            <div class="col-md-5">
                                <div class="allies-img">
                                    <img src="{$product[1]['img']}" alt="" />
                                </div>
                            </div>

                            <div class="col-md-7">
                                <div class="allies-content sm-m-top-50">
                                    <div class="head-title">
                                        <h2 class="text-black">O{$product[1]['title']}</h2>
                                        <h5 class="text-black m-top-30">{$product[1]['content']}</h5>
                                        <div class="separator2"><span></span><span></span><span></span></div>

                                    </div>
                                    <p class="m-top-40">{$product[1]['specs']}</p>

                                    <a href="" class="btn btn-primary btn-round m-top-30">Portfolio</a>

                                </div>
                            </div>
                        </div>

                    </div>
                </div>
            </section>

接着往下看:

img

该区域可以更改成文章的展示,创建已数据库表:

img

添加内容:

img

查看 html 代码:

<div class="col-md-4 col-sm-6">
                                        <div class="studies-item">
                                            <div class="studies-feature border">
                                                <img class="img-rounded" src="/home/assets/images/studies-img-01.jpg" alt="" />
                                                <div class="studies-overlay img-rounded"><a href=""><span class="icon icon-arrows-2 hvr-hang"></span></a></div>
                                                <div class="custom-hover"></div>
                                            </div>
                                            <div class="studies-conten m-top-30">
                                                <h4><a href="">Acme Corporation</a></h4>
                                                <p class="m-top-10">Objective: Build a larger twitter community</p>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="col-md-4 col-sm-6">
                                        <div class="studies-item xs-m-top-35">
                                            <div class="studies-feature border">
                                                <img class="img-rounded" src="/home/assets/images/studies-img-02.jpg" alt="" />
                                                <div class="studies-overlay img-rounded"><a href=""><span class="icon icon-arrows-2 hvr-hang"></span></a></div>
                                            </div>
                                            <div class="studies-conten m-top-30">
                                                <h4><a href="">Soylent Corp </a></h4>
                                                <p class="m-top-10">Objective: Make tone & branding consistency</p>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="col-md-4 col-sm-6">
                                        <div class="studies-item sm-m-top-35">
                                            <div class="studies-feature border">
                                                <img class="img-rounded" src="/home/assets/images/studies-img-03.jpg" alt="" />
                                                <div class="studies-overlay img-rounded"><a href=""><span class="icon icon-arrows-2 hvr-hang"></span></a></div>
                                            </div>
                                            <div class="studies-conten m-top-30">
                                                <h4><a href="">Umbrella Corporation</a></h4>
                                                <p class="m-top-10">Objective: Eliminate the residue of black-hat methods</p>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="col-md-4 col-sm-6">
                                        <div class="studies-item m-top-35">
                                            <div class="studies-feature border">
                                                <img class="img-rounded" src="/home/assets/images/studies-img-04.jpg" alt="" />
                                                <div class="studies-overlay img-rounded"><a href=""><span class="icon icon-arrows-2 hvr-hang"></span></a></div>
                                            </div>
                                            <div class="studies-conten m-top-30">
                                                <h4><a href="">Initech</a></h4>
                                                <p class="m-top-10">Objective: Improve site load speed & functionality</p>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="col-md-4 col-sm-6">
                                        <div class="studies-item m-top-35">
                                            <div class="studies-feature border">
                                                <img class="img-rounded" src="/home/assets/images/studies-img-05.jpg" alt="" />
                                                <div class="studies-overlay img-rounded">
                                                    <a href="">
                                                        <span class="icon icon-arrows-2 hvr-hang"></span>
                                                    </a>
                                                </div>
                                            </div>
                                            <div class="studies-conten m-top-30">
                                                <h4><a href="">Vehement Capital Partners </a></h4>
                                                <p class="m-top-10">Objective: Increase nationwide sales</p>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="col-md-4 col-sm-6">
                                        <div class="studies-item m-top-35">

                                            <div class="studies-feature border">
                                                <img class="img-rounded" src="/home/assets/images/studies-img-06.jpg" alt="" />
                                                <div class="studies-overlay img-rounded">
                                                    <a href=""><span class="icon icon-arrows-2 hvr-hang"></span></a>
                                                </div>
                                            </div>
                                            <div class="studies-conten m-top-30">
                                                <h4><a href="">Massive Dynamic</a></h4>
                                                <p class="m-top-10">Objective: Increase qualified traffic</p>
                                            </div>
                                        </div>
                                    </div>

发现该 html 代码中前 3 个 div 的 class 有所变化,后 3 个 div 布局内容则无变化。我们使用 eq 标签使前 3 个 div 照原样输出,后 3 个 div 遍历输出:

{volist name="article" id="vo" key="k" }
{eq name="k" value="1"}
 <div class="col-md-4 col-sm-6">
     <div class="studies-item">
         <div class="studies-feature border">
             <img class="img-rounded" src="{$vo.img}" alt="" />
             <div class="studies-overlay img-rounded"><a href=""><span class="icon icon-arrows-2 hvr-hang"></span></a></div>
             <div class="custom-hover"></div>
         </div>
         <div class="studies-conten m-top-30">
             <h4><a href="">{$vo.title}</a></h4>
             <p class="m-top-10">{$vo.content}</p>
         </div>
     </div>
 </div>
 {/eq}
 {eq name="k" value="2"}
 <div class="col-md-4 col-sm-6">
     <div class="studies-item xs-m-top-35">
         <div class="studies-feature border">
             <img class="img-rounded" src="{$vo.img}" alt="" />
             <div class="studies-overlay img-rounded"><a href=""><span class="icon icon-arrows-2 hvr-hang"></span></a></div>
         </div>
         <div class="studies-conten m-top-30">
             <h4><a href="">{$vo.title}</a></h4>
             <p class="m-top-10">{$vo.content}</p>
         </div>
     </div>
 </div>
 {/eq}
 {eq name="k" value="3"}
 <div class="col-md-4 col-sm-6">
     <div class="studies-item sm-m-top-35">
         <div class="studies-feature border">
             <img class="img-rounded" src="{$vo.img}" alt="" />
             <div class="studies-overlay img-rounded"><a href=""><span class="icon icon-arrows-2 hvr-hang"></span></a></div>
         </div>
         <div class="studies-conten m-top-30">
             <h4><a href="">{$vo.title}</a></h4>
             <p class="m-top-10">{$vo.content}</p>
         </div>
     </div>
 </div>
 {/eq}
 {gt name="k" value="3"}
 <div class="col-md-4 col-sm-6">
     <div class="studies-item m-top-35">
         <div class="studies-feature border">
             <img class="img-rounded" src="{$vo.img}" alt="" />
             <div class="studies-overlay img-rounded"><a href=""><span class="icon icon-arrows-2 hvr-hang"></span></a></div>
         </div>
         <div class="studies-conten m-top-30">
             <h4><a href="">{$vo.title}</a></h4>
             <p class="m-top-10">{$vo.content}</p>
         </div>
     </div>
 </div>
 {/gt}
 {/volist}

在 index 控制器的首页方法 index 中添加对 article 表数据的查询:

<?php
namespace app\index\controller;
use think\Controller;
use think\Db;

class Index extends Controller{
    public function index()
    {
        $banner_res=Db::table('tp_home_banner')
        ->order('id', 'desc')
        ->limit(4)
        ->select();

        $advantageous_res=Db::table('tp_home_advantageous')
        ->order('id', 'desc')
        ->limit(6)
        ->select();

        $product_res=Db::table('tp_home_product')
        ->order('id', 'desc')
        ->limit(2)
        ->select();

        $article_res=Db::table('tp_home_article')
        ->order('id', 'desc')
        ->limit(6)
        ->select();

        $this->view->assign('article',$article_res);
        $this->view->assign('product',$product_res);
        $this->view->assign('advantageous',$advantageous_res);
        $this->view->assign('banner',$banner_res);
        return $this->view->fetch();
    }

}

其它的前端内容通过数据库更改不再赘述。

4.2 完成通过后台设置更改与添加前端内容

创建控制器 Contentmanger,添加方法 bannerManger,bannerManger 方法跳转到一页面用于显示 banner 数据,点击每条数据可进行编辑:

img

由于有数据的查询,在控制器中需要查询 banner 表数据,代码为:

<?php

namespace app\admin\controller;
use think\Controller;
use think\Db;
use think\facade\Request;

class Contentmanger extends Base{

    
    public function bannerManger(){

        $list=Db::table('tp_home_banner')
        ->order('id')
        ->select();
        
        $this->view->assign('list',$list);
        return $this->view->fetch();
    }
}

此处可添加验证器检测传入值是否正确,为了节省篇幅接下来的代码中不再过多的添加其它内容。 html 代码前端的编辑修改按钮,使用了 url 方法传参,传参后获取该 id 的内容,方便进行修改:

img

点击编辑后将会可以随意修改 banner 的值:

img

点击 choosefile 可选择 img 文件,修改 banner 图片。

创建一控制器用来管理内容修改操作的逻辑,创建一 php 文件名为 Contentmangerpost ,添加 bannerEdit 方法:

<?php

namespace app\admin\controller;
use think\Controller;
use think\Db;
use think\facade\Request;
use \think\File;

use app\admin\model\Goods;
use app\admin\validate\IdValidate;
use app\admin\code\ReturnCodeInfo;

class Contentmangerpost extends Base{
    
    public function bannerEdit(){
        $save_path='/public';
        $save_path_='/uploads/imgs/';
        $request_data = Request::post();
        $con['id']=$request_data['id'];
        $data['title']=$request_data['title'];
        $data['title_2']=$request_data['title_2'];
        $data['content']=$request_data['content'];
        $data['content_2']=$request_data['content_2'];


        
        $file = request()->file('file');
        if($file){
            
            $info = $file->move('..'.$save_path.$save_path_);
            if($info){
                
                $data['img']=$save_path_.str_replace('\\','/',$info->getSaveName());
            }else{
                
                echo $file->getError();
            }  
        }else{
            $data['img']='/home/assets/images/slide-bg-01.jpg';
        }


        $res=Db::name('home_banner')
        ->where($con)
        ->update($data);

        if($res){
            return json((new ReturnCodeInfo())->actionSuccess());
        }else{
            return json((new ReturnCodeInfo())->actionError());
        }
    }
}

以上代码使用 request()->file(‘file’); 判断是否接收到 file 值,如接收到说明用户选择了新图片,那么使用 move 方法保存图片,通过 getSaveName 方法获取保存图片名。最终更新至数据库中。其它数据的更新方法与该步骤类似,不再赘述。接下来通过拖拽实现 web 并且绑定数据。

五、完成页面拖拽生成并绑定数据功能的编写

拖拽页面在此提供一个思想,通过 bootstrap 的 layoutit 可视化布局可以完成简单页面拖拽生成,需要完成更多复杂的界面需要对 layoutit 进行二次开发。本篇内容为一个 demo,通过可视化 layoutit 生成界面且进行代码替换完成对于 thinkphp 模板的制作,最后通过可视化数据绑定生成 php 代码。

5.1 完成拖拽界面的前端搭建

首先为 layoutit 添加一个控制器并更改资源路径,此操作不再赘述。部署完成后打开界面:

img

可拖拽布局实现界面编辑:

img

拖拽成如下界面:

img

点击下载可查看生成的 html 代码:

img

在点击下载时,我通过 js 保存了生成的代码:

	  var template=''; 
	  $("[data-target=#downloadModal]").click(function(e) {
	    e.preventDefault();
	    downloadLayoutSrc();
	  });
	
	  function downloadLayoutSrc() {
	    var e = "";
	    $("#download-layout").children().html($(".demo").html());
	    var t = $("#download-layout").children();
	    t.find(".preview, .configuration, .drag, .remove").remove();
	    t.find(".lyrow").addClass("removeClean");
	    t.find(".box-element").addClass("removeClean");
	    t.find(".lyrow .lyrow .lyrow .lyrow .lyrow .removeClean").each(function() {
	      cleanHtml(this)
	    });
	    t.find(".lyrow .lyrow .lyrow .lyrow .removeClean").each(function() {
	      cleanHtml(this)
	    });
	    t.find(".lyrow .lyrow .lyrow .removeClean").each(function() {
	      cleanHtml(this)
	    });
	    t.find(".lyrow .lyrow .removeClean").each(function() {
	      cleanHtml(this)
	    });
	    t.find(".lyrow .removeClean").each(function() {
	      cleanHtml(this)
	    });
	    t.find(".removeClean").each(function() {
	      cleanHtml(this)
	    });
	    t.find(".removeClean").remove();
	    $("#download-layout .column").removeClass("ui-sortable");
	    $("#download-layout .row-fluid").removeClass("clearfix").children().removeClass("column");
	    if ($("#download-layout .container").length > 0) {
	      changeStructure("row-fluid", "row")
	    }
	    formatSrc = $.htmlClean($("#download-layout").html(), {
	      format: true,
	      allowedAttributes: [
	        ["id"],
	        ["class"],
	        ["data-toggle"],
	        ["data-target"],
	        ["data-parent"],
	        ["role"],
	        ["data-dismiss"],
	        ["aria-labelledby"],
	        ["aria-hidden"],
	        ["data-slide-to"],
	        ["data-slide"]
	      ]
	    });
	    $("#download-layout").html(formatSrc);
	    $("#downloadModal textarea").empty();
	    $("#downloadModal textarea").val(formatSrc)
	    console.log(formatSrc);
	    template=formatSrc;
	  }

此代码为 layoutit 的 js 代码,在此基础上我新建了已 js 全局变量保存数据,变量为 template,在 js 代码清洗完成后把清洗后的值赋值给全局变量 template。 随后点击保存:

<button class="btn btn-primary" onclick="bc()">保存</button>

保存按钮点击后对应的 js 代码为:

function bc(){
                {literal} 
                template='{$head|raw}'+'<body style="min-height: 816px; cursor: auto;" class="devpreview sourcepreview">'+template+'</body>';
                {/literal} 
                $.ajax({
                    type:'post',
                    url:'/index.php?s=/admin/Autoviewpost/test/',
                    data:{"template":template},
                    dataType:"json", 
                    success:function(data){
    
                    },error:function(jqXHR){
    
                    }
                })  
              }

在因为生成的代码需要一定的 js 文件引入,在此我添加了 {$head|raw} 为前端的模板代码,使用了{literal} 标签对 thinkphp 的模板代码进行修饰,表示不解析其中内容。head 变量的内容为:

$head='<link href="/autoview/css/bootstrap-combined.min.css" rel="stylesheet">
        <link href="/autoview/css/layoutit.css" rel="stylesheet">
        <!-- Le styles -->
        <link href="/autoview/css/bootstrap-combined.min.css" rel="stylesheet">
        <link href="/autoview/css/layoutit.css" rel="stylesheet">
        
        <!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
        <!--[if lt IE 9]>
                <script src="/autoview/js/html5shiv.js"></script>
            <![endif]-->
        
            <!-- Fav and touch icons -->
            <link rel="shortcut icon" href="/autoview/img/favicon.png">
            
            <script type="text/javascript" src="/autoview/js/jquery-2.0.0.min.js"></script>
            <!--[if lt IE 9]>
            <script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
            <![endif]-->
            <script type="text/javascript" src="/autoview/js/bootstrap.min.js"></script>
            <script type="text/javascript" src="/autoview/js/jquery-ui.js"></script>
            <script type="text/javascript" src="/autoview/js/jquery.ui.touch-punch.min.js"></script>
        <script type="text/javascript" src="/autoview/js/jquery.htmlClean.js"></script>
        <script type="text/javascript" src="/autoview/ckeditor/ckeditor.js"></script>
        <script type="text/javascript" src="/autoview/ckeditor/config.js"></script>
        <script type="text/javascript" src="/autoview/js/scripts.js"></script>';

点击保存后,生成的 html 代码文本将会传到 Autoviewpost 控制器下的 test 方法中,test 方法代码如下:

public function test(){
        $request_data = Request::post();
        $template=$request_data['template'];

        
        $template=preg_replace(getMediaReStr(),getMediaHtmlStr(),$template);
        $template=preg_replace(getCarouselReStr(),getCarouselHtmlStr(),$template);
        $template=preg_replace(getThumbnailsReStr(),getThumbnailsHtmlStr(),$template);
        $template=preg_replace(getUnitReStr(),getUnitHtmlStr(),$template);

        $template=str_replace("{eq name="key" value="1"}active{/eq}",'{eq name="key" value="1"}active{/eq}',$template);
        
        file_put_contents(dirname(dirname(__FILE__)).'\view\templates\t1.html',$template);
        
    }

该方法在接收值后对一部分进行替换。使用 preg_replace 对文本进行替换,在该对比中我使用了正则对数据进行匹配,该方法我编写在 common 公共函数的 php 文件中,地址为 application\common.php,内容为:

<?php











function arrunset(&$arr){
    array_splice($arr,0,1);
}


function getMediaHtmlStr(){
    $str='{volist name="media" id="data" }'.
    '<div class="media">'.
    '<a href="{$data.src}" class="pull-left"><img src="{$data.img}" class="media-object" alt=\'\' /></a>'.
    '<div class="media-body">'.
    '<h4 class="media-heading">'.
    '{$data.title}'.
    '</h4> {$data.content}'.
    '</div>'.
    '</div>'.
    '{:arrunset($media)}'.
    '{/volist}';
    return $str;
}

function getMediaReStr(){
    $re="/<div class=\"media\".*?>.*?<\/div>.*?<\/div>/ism"; 
    return $re;
}


function getCarouselHtmlStr(){
    $str='<div class="carousel slide" id="carousel-998124"><div class="carousel-inner"> '.
    '{volist name="banner" id="data"}'.
    '<div class=\'item {eq name="key" value="1"}active{/eq} \'>'.
    '<img alt="" src="{$data.img}" />'.
    '<div class="carousel-caption">'.
    '<h4>'.
    '{$data.title}'.
    '</h4>'.
    '<p>'.
    '{$data.content}'.
    '</p>'.
    '</div>'.
    '</div>'.
    '{/volist} '.
    '</div> '.
    '<a data-slide="prev" href="#carousel-998124" class="left carousel-control">‹</a><a data-slide="next" href="#carousel-998124" class="right carousel-control">›</a></div>';
    return $str;
}

function getCarouselReStr(){
    $re="/<div class=\"carousel slide\".*?>.*?class=\"right carousel-control\">.*?<\/div>/ism"; 
    return $re;
}



function getThumbnailsHtmlStr(){
    $str='<ul class="thumbnails">'.
    '{volist name="article" id="data"}'.
    '<li class="span4">'.
    '<div class="thumbnail"> <img alt="300x200" src="{$data.faceimg}">'.
    '<div class="caption" contenteditable="true">'.
    '<h3>{$data.title}</h3>'.
    '<p>{$data.content}</p>'.
    '<p><a class="btn btn-primary" href="#">浏览</a> <a class="btn" href="#">分享</a></p>'.
    '</div>'.
    '</div>'.
    '</li>'.
    '{/volist}'.
    '</ul>';
    return $str;
}

function getThumbnailsReStr(){
    $re="/<ul class=\"thumbnails\".*?>.*?<\/ul>/ism"; 
    return $re;
}


function getUnitHtmlStr(){
    $str='{volist name="ad" id="data" offset="0" length=\'1\'}'.
    '<div class="hero-unit" contenteditable="true">'.
    '<h1>{$data.title}</h1>'.
    '<p>{$data.content} </p>'.
    '<p><a class="btn btn-primary btn-large" href="#">参看更多 »</a></p>'.
    '</div>'.
    '{:arrunset($ad)}'.
    '{/volist}' ;
    return $str;
}

function getUnitReStr(){
    $re="/<div class=\"hero-unit\".*?>.*?<\/div>/ism"; 
    return $re;
}

使用不同的方法返回不同组件、html 代码的正则匹配,替换成所需的带有 thinkphp 框架语法的 html 代码,这些代码同样在 common 文件中。完成替换后由于发现某些字符需要进行替换,编写代码:

$template=str_replace("{eq name="key" value="1"}active{/eq}",'{eq name="key" value="1"}active{/eq}',$template);

完成清洗替换后生成 html 模板生成危机:

file_put_contents(dirname(dirname(__FILE__)).'\view\templates\t1.html',$template);

由于是 demo,所以位置写死了。 随后访问 Autoview 控制器下的 createcontrol 方法(页面没写):

img

输入你想要生成的控制器名、方法名,该方法需要绑定数据表中哪些元素,以及绑定的页面路径:

img

输入完成后点击提交,数据将会传到 Autoview 控制器中的 buildcontrol 方法中,方法代码如下:

    public function buildcontrol(){
        $request_data = Request::post();
        $data['controll'] = $request_data['controll'];
        $data['function']=$request_data['function'];
        $data['datas']=$request_data['datas'];
        $data['templatepath']=$request_data['templatepath'];

        $controlcode='<?php

        namespace app\admin\controller;
        use think\Controller;
        use think\Db;
        
        class '.$data['controll'].' extends AutoviewBase{
        
            public function '.$data['function'].'(){
        
                return $this->view->fetch(dirname(dirname(__FILE__)).'.$data['templatepath'].');
            }
        }';

        file_put_contents(dirname(dirname(__FILE__)).'\controller\\'.$data['controll'].'.php',$controlcode);

        $res = Url_datas::create($data);

        if($res){
            return json((new ReturnCodeInfo())->actionSuccess());
        }else{
            return json((new ReturnCodeInfo())->actionError());
        }
    }

该方法 controlcode 变量为控制器模板变量,该模板文本可以得知该控制器名称为自定义名称,继承于 AutoviewBase 基类,方法名也是自定义,模板位置根据指定路径进行输出渲染。最后使用 file_put_contents 进行控制器生成。最后将数据存入到 Url_datas 模型中,也是 Url_datas 表中,数据表结构数据如下:

img

img

我们从控制器生成路径中可以得知,是 admin 内的控制器,我们访问生成的控制器方法查看效果:

img

数据页面得到显示,这些数据都是数据库中的数据。在创建控制器时,我们在指定数据表及字段时使用的格式内容为如下:

{             
"banner":"id,title,img,content",            
 "article":"id,title,content,faceimg",             
 "media":"id,src,img,title,content",             
 "ad":"id,title,content,img"        
  }

数据指定格式为 “数据表”:“字段 1, 字段 2…”,通过在 AutoviewBase 的前置方法中对该 json 数据进行解析,AutoviewBase 基类如下:

<?php

namespace app\admin\controller;
use think\Controller;
use think\Db;

class AutoviewBase extends Controller{
    protected $beforeActionList = [
        'toview'
    ];

    public function toview(){
        $head='<link href="/autoview/css/bootstrap-combined.min.css" rel="stylesheet">
        <link href="/autoview/css/layoutit.css" rel="stylesheet">
        <!-- Le styles -->
        <link href="/autoview/css/bootstrap-combined.min.css" rel="stylesheet">
        <link href="/autoview/css/layoutit.css" rel="stylesheet">
        
        <!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
        <!--[if lt IE 9]>
                <script src="/autoview/js/html5shiv.js"></script>
            <![endif]-->
        
            <!-- Fav and touch icons -->
            <link rel="shortcut icon" href="/autoview/img/favicon.png">
            
            <script type="text/javascript" src="/autoview/js/jquery-2.0.0.min.js"></script>
            <!--[if lt IE 9]>
            <script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
            <![endif]-->
            <script type="text/javascript" src="/autoview/js/bootstrap.min.js"></script>
            <script type="text/javascript" src="/autoview/js/jquery-ui.js"></script>
            <script type="text/javascript" src="/autoview/js/jquery.ui.touch-punch.min.js"></script>
        <script type="text/javascript" src="/autoview/js/jquery.htmlClean.js"></script>
        <script type="text/javascript" src="/autoview/ckeditor/ckeditor.js"></script>
        <script type="text/javascript" src="/autoview/ckeditor/config.js"></script>
        <script type="text/javascript" src="/autoview/js/scripts.js"></script>';
        
        $con['controll']=strtolower(request()->controller());
        $con['function']=strtolower(request()->action());

        
        $data_rules=Db::name('url_datas')
        ->where($con)
        ->order('id', 'desc')
        ->field('datas')
        ->find();
        
        
        $datas=[];
        $tables = json_decode($data_rules['datas'], true);
        foreach($tables as $key => $value){
            $datas[$key]=Db::name($key)
                        ->column($value);
        }

        
        foreach($datas as $key => $value){
            $this->view->assign($key,$value);
        }


        $this->view->assign('head',$head);

        return $this->view->fetch(dirname(dirname(__FILE__)).'\view\templates\t1.html');
    }

}

以上代码中定义了前置操作 toview 方法,在 toview 方法中定义了 head 为头部资源文件,之后使用如下代码获取当前控制器及方法名:

$con['controll']=strtolower(request()->controller());
$con['function']=strtolower(request()->action());

把控制器及方法名当作条件至 url_datas 数据表中查询所需的数据要求及格式:

        $data_rules=Db::name('url_datas')
        ->where($con)
        ->order('id', 'desc')
        ->field('datas')
        ->find();

得到了所需数据后,对该数据进行 json 解析,解析后遍历该数据作为对指定表与数据的查询:

		$datas=[];
        $tables = json_decode($data_rules['datas'], true);
        foreach($tables as $key => $value){
            $datas[$key]=Db::name($key)
                        ->column($value);
        }

之后使用遍历把得到的数据结果输出到前端:

    foreach($datas as $key => $value){
        $this->view->assign($key,$value);
    }

最后把 head 传递值前端代码,渲染输出:

 $this->view->assign('head',$head);
return $this->view->fetch(dirname(dirname(__FILE__)).'\view\templates\t1.html');

以上内容准备过于匆忙,只讲解了实现中较为重要的地方,很多优化及细节没有说明,希望下次将会编写一份完全的教程给大家!如有错误欢迎指出,想要深入学习可以关注博主, 点赞博主、收藏博文,谢谢~