ThinkPHP-1基础

实践学习php,thinkphp,Redis,vue,uni-app等技术,推荐开源电商系统likeshop,可以借鉴思路,可去版权免费商用,gitee下载地址:
点击进项目地址

国产 PHP web 框架

ThinkPHP5的运行环境要求PHP5.6以上,兼容PHP8.0

开发基础手册

安装

使用composer安装

composer create-project topthink/think=5.1.* tp5

启动服务

cd tp
php think run

然后就可以在浏览器中访问

http://localhost:8000

更新框架

composer update topthink/framework

采用 Composer 和 git 方式下载

github 地址

https://github.com/top-think/think/releases/tag/v5.1.41

目录结构

初始的目录结构如下:

www  WEB部署目录(或者子目录)
├─application           应用目录
│  ├─common             公共模块目录(可以更改)
│  ├─module_name        模块目录
│  │  ├─common.php      模块函数文件
│  │  ├─controller      控制器目录
│  │  ├─model           模型目录
│  │  ├─view            视图目录
│  │  └─ ...            更多类库目录
│  │
│  ├─command.php        命令行定义文件
│  ├─common.php         公共函数文件
│  └─tags.php           应用行为扩展定义文件
│
├─config                应用配置目录
│  ├─module_name        模块配置目录
│  │  ├─database.php    数据库配置
│  │  ├─cache           缓存配置
│  │  └─ ...            
│  │
│  ├─app.php            应用配置
│  ├─cache.php          缓存配置
│  ├─cookie.php         Cookie配置
│  ├─database.php       数据库配置
│  ├─log.php            日志配置
│  ├─session.php        Session配置
│  ├─template.php       模板引擎配置
│  └─trace.php          Trace配置
│
├─route                 路由定义目录
│  ├─route.php          路由定义
│  └─...                更多
│
├─public                WEB目录(对外访问目录)
│  ├─index.php          入口文件
│  ├─router.php         快速测试文件
│  └─.htaccess          用于apache的重写
│
├─thinkphp              框架系统目录
│  ├─lang               语言文件目录
│  ├─library            框架类库目录
│  │  ├─think           Think类库包目录
│  │  └─traits          系统Trait目录
│  │
│  ├─tpl                系统模板目录
│  ├─base.php           基础定义文件
│  ├─console.php        控制台入口文件
│  ├─convention.php     框架惯例配置文件
│  ├─helper.php         助手函数文件
│  ├─phpunit.xml        phpunit配置文件
│  └─start.php          框架入口文件
│
├─extend                扩展类库目录
├─runtime               应用的运行时目录(可写,可定制)
├─vendor                第三方类库目录(Composer依赖库)
├─build.php             自动生成定义文件(参考)
├─composer.json         composer 定义文件
├─LICENSE.txt           授权说明文件
├─README.md             README 文件
├─think                 命令行入口文件

可以使用php自带webserver快速测试切换到根目录后,启动命令:php think run

命名规范

ThinkPHP5 遵循PSR-2命名规范和PSR-4自动加载规范,并且注意如下规范:

目录和文件
  • 目录不强制规范,驼峰和小写+下划线模式均支持;
  • 类库、函数文件统一以.php为后缀;
  • 类的文件名均以命名空间定义,并且命名空间的路径和类库文件所在路径一致;
  • 类名和类文件名保持一致,统一采用驼峰法命名(首字母大写);
函数和类、属性命名
  • 类的命名采用驼峰法,并且首字母大写,例如 UserUserType,默认不需要添加后缀,例如UserController应该直接命名为User
  • 函数的命名使用小写字母和下划线(小写字母开头)的方式,例如 get_client_ip
  • 方法的命名使用驼峰法,并且首字母小写,例如 getUserName
  • 属性的命名使用驼峰法,并且首字母小写,例如 tableNameinstance
  • 以双下划线“__”打头的函数或方法作为魔法方法,例如 __call__autoload
常量和配置
  • 常量以大写字母和下划线命名,例如 APP_PATHTHINK_PATH
  • 配置参数以小写字母和下划线命名,例如 url_route_onurl_convert
数据表和字段
  • 数据表和字段采用小写加下划线方式命名,并注意字段名不要以下划线开头,例如 think_user 表和 user_name字段,不建议使用驼峰和中文作为数据表字段命名。

URL解析模式

http://serverName/index.php/模块/控制器/操作/参数/值

image-20210205155010787

image-20210205155033556

url 重写模式

如果没有开启伪静态,只能使用 PATH_INFO 模式

开启方式:apache

  1. httpd.conf文件,加载 mod_rewrite.so ,去掉前面的 # 号即可

    D:\phpstudy_pro\Extensions\Apache2.4.39\conf
    
  2. index.php 同级目录下 .htaccess 文件(框架已做好,重启环境即可)

设计模式

多模块,单模块

默认是多模式

单模块

// thinkphp/index.php

Container::get('app')->bind('test')->run()->send();

image-20210205160452769

config/app.php 模块设置中设置

// 默认的空模块名
'empty_module'           => ''
用途:如果发生错误可以跳转到指定页面        

空模块

通过环境变量设置空目录,将不存在的目录统一指向指定目录

config/app.php 模块设置中设置

URL 地址 public/index/one,即:控制器/操作

单一模块的命名空间也变更为:app/controller

空模块只有在多模块开启,且没有绑定模块的情况下生效

环境变量

image-20210205162531429

控制器定义
  • 控制器,即 controller,控制器文件存放在 controller 目录下

  • 类名和文件名大小写保持一致,采用驼峰法()

  • 如果类名是 双字母组合,比如 class HelloWorld,url 访问时必须用:hello_world;

    想要原样方式访问 URL,则需要关闭配置文件中的自动转换

    ‘url_convert’ => false;

    image-20210205164136011

  • 如果想要改变命名空间 app 为其他,可以在根目录下创建 .env 文件

    写上键值对即可

    app_namespace=application

渲染输出
  1. 直接 return

  2. json输出,使用 json 函数,数组可以使用此种方式

    class HelloWorld
    {
        public function eat($who='xiaoli')
        {
            $data=array('1'=>'one','2'=>'second');
            return json($data);
        }
    }
    
    # output
    {"1":"one","2":"second"}
    
  3. 使用 view 输出模板

  4. image-20210205170035017

初始化

如果继承了基类控制器,可以定义控制器初始化方法:initialize()

initialize() 方法会在调用控制器方法之前执行:

<?php

namespace app\test\controller;

use think\Controller;

class HelloWorld extends Controller
{
    protected function initialize()
    {
        parent::initialize(); // TODO: Change the autogenerated stub
    }
}

initialize() 方法不需要返回任何值,输出用 PHP 方式,return 无效

控制器操作

前置操作

<?php
namespace app\test\controller;
use think\Controller;
class HelloWorld extends Controller
{
    protected $beforeActionList = [
        # 每次都调用first
        'first',
        # 除了调用 one 时不调用 second
        'second' => ['except' => 'one'],
        # 只有调用 one 和 two 时调用 third
        'third' => ['only' => 'one','two']
    ];
    protected function first()
    {
        echo 'first<br>';
    }
    protected function second()
    {
        echo 'second<br>';
    }
    protected function third()
    {
        echo 'third<br>';
    }
    public function index()
    {
        echo 'index';
    }
    public function one()
    {
        echo 'one';
    }
    public function two()
    {
        echo 'two';
    }
}

跳转和重定向

controller 类提供了两个跳转方法

success(msg,url)
error(msg)    

不指定 url 默认跳转 $_SERVER[‘HTTP_REFERER’]

成功或者错误有一个固定的页面模板:‘thinkphp/tpl/dispatch_jump.tpl’;

在 app.php 配置文件中,可以更改跳转页面

‘dispatch_success_tmpl’=> Env::get(‘think_path’)

<?php
namespace app\test\controller;
use think\Controller;

class HelloWorld extends Controller
{
    protected $flag = false;

    public function index()
    {
        if ($this->flag) {
            $this->success('注册成功', '../');
            # 没有url,他会死循环
        } else {
            $this->error('失败');
        }
        return 'index';
    }
}

image-20210205184939263

空方法和空控制器

空方法

当访问一个不存在的方法时,系统会报错,可以使用 _empty() 来拦截

class HelloWorld extends Controller
{
    public function _empty($name)
    {
        return '不存在当前方法:' . $name;
    }
}

# output
不存在当前方法:two

空控制器

当访问一个不存在的控制器时,系统也会报错,使用 Error 类来拦截

<?php
namespace app\test\controller;
use think\Request;

class Error
{
    public function index(Request $request)
    {
        return '当前控制器不存在:'.$request->controller();
    }
}

系统默认为 Error 类,自定义可以在 app.php 配置文件中修改:

‘empty_controller’=>‘Error’

数据库与模型

ThinkPHP 采用内置抽象层将不同的数据库操作进行封装处理

数据抽象层基于 PDO 模式,无需针对不同的数据库编写相应代码

使用

连接数据库

config/database.php ,配置连接信息

简单实例:

class HelloWorld
{
    public function show()
    {
        $data = Db::name('admin')->select();
        // 如果设置了表前缀,使用 name 不需要加前缀
        $data = Db::table('admin')->select();
        // 如果设置了表前缀,使用 table 需要加前缀
        return json($data);

    }
}

模型

image-20210206090345812

# 可以在 config/app.php,开启sql语句显示
'app_trace'              => true,
基本查询
$data1 = Db::table('admin')->find();
// 查询一条数据使用find

// return Db::getLastInsID();
// 得到最近的一条 sql 查询的原生语句

$data2 = Db::table('admin')->where('uid', '3')->find();
// var_dump($data2);
// 没有查到任何值,返回 null

$data3 = Db::table('admin')->where('uid', '3')->findOrFail();
// 查询一条数据,没有数据时抛出异常

$data4 = Db::table('admin')->where('uid', '3')->findOrEmpty();
// 查询一条数据,没有数据时抛出一个空数组

$data5 = Db::table('admin')->select();
// 查询多列数据
// selectOrEmpty,selectOrFail

$data6 = \db('admin')->select();
// 助手函数 db,更方便的查询

$data7 = Db::name('admin')->where('uid','1')->value('pass');
// 查询 admin 表下,uid=1 的 pass 字段的值,没有数据返回 null

$data8 = Db::name('admin')->column('pass');
// 查询指定列的值,没有数据返回空数组

$data9 = Db::name('admin')->column('name','uid');
// 指定 uid 作为列值的索引,即按 uid 的值进行排序

return json($data9);
链式查询

image-20210206095123478

对象实例化

public function show()
{
    $user = Db::name('admin');
    $user -> select();
    // 对象实例保存

    // 当同一个对象实例第二次查询后,会保留第一次查询的值
    $data1 = $user->order('uid')->select();
    $data2 = $user->select();
    // return json($data2);
    // SELECT * FROM `admin` ORDER BY `uid`

    // 使用 removeOption() 方法,清理掉上一次查询的保留值
    $data3 = $user->removeOption('order')->select();
    // SELECT * FROM `admin`
    return Db::getLastSql();

}
增删改查操作

image-20210206103758795

image-20210206103827470

image-20210206103859147

image-20210206103716220

image-20210206103943625

image-20210206104014241

image-20210206103645671

查询表达式

比较查询

class Search
{
    public function index()
    {
        $result = Db::name('admin')->where("uid",'<>','1')->select();
        return json($result);
    }
}

<>,>,<,=,<=,>=

区间查询

class Search
{
    public function index()
    {
        // 模糊查询
        $result = Db::name('admin')->where('name','like','ad%')->select();
        return json($result);

        // 数组传递
        $result01 = Db::name('admin')->where('name','like',['ad%,b%'])->select()

        // 快捷方式
         $result01 = Db::name('admin')->whereLike('name',['ad%,b%'])->select()
         $result01 = Db::name('admin')->whereNotLike('name',['ad%,b%'])->select()

         $result01 = Db::name('admin')->whereBetween('name',[2,3])->select()
         $result01 = Db::name('admin')->whereNotBetween('name',[2,3])->select()

         $result01 = Db::name('admin')->whereIn('name','1,2,3')->select()
         $result01 = Db::name('admin')->whereNotIn('name','1,2,3')->select()

         $result01 = Db::name('admin')->whereNull('name')->select()
         $result01 = Db::name('admin')->whereNotNull('name')->select()
    }
}

image-20210218143154541

时间查询

image-20210218145153360

image-20210218145135999

image-20210218145238769

image-20210218145247799

image-20210218145349049

聚合、原生、子查询

image-20210218145634920

image-20210218150628856

image-20210218150645415

设置主键

<?php

namespace app\test\model;

use think\Model;

class Admin extends Model
{
    protected $pk='uid';
}

初始化

    protected static function init()
    {
//        parent::init(); // TODO: Change the autogenerated stub
        echo '初始化';
    }

模型操作数据和数据库操作一样,只不过不需要指定表了

查询
    UserModel::select();
删除
    UserModel::destory

数据库操作返回列表是一个二维数组 [[ ]] ,模型返回结果集 [{ }]

<?php

namespace app\test\controller;

use \app\test\model\Admin as AdminModel;
// 避免重名

class Search
{
    public function index()
    {
        $result = AdminModel::select();
        return json($result);
    }
}
添加和删除
    public function insert()
    {
        // 实例化
        $user = new AdminModel();

        $user->name='xiaoming';
        $user->pass='12333333';

        $user->save();

    }

    public function delete()
    {
        $user = new AdminModel();

        // 数据删除
        // 通过主键id查询
        $user =AdminModel::get(1);
        // 再通过delete方法,将数据删除,返回布尔值
        $user->delete();

        // 直接使用静态方法调用 destory()
        AdminModel::destroy(1);
        
        // 也可以使用条件查询
    }
}

。。。。。

。。。。。

模板视图

模板引擎

模板引擎分为两种,一种是内置的,一种作为插件引入,一般使用内置即可

内置的模板引擎的配置文件是 config/template.php

    // 模板路径
    'view_path'    => '',
默认就是 view 目录    
视图渲染

See.php

<?php

namespace app\test\controller;
use think\Controller;

class See extends Controller
{
    public function index()
    {
        // 自动定位
        return $this->fetch();

        // 指定模板
        return  $this->fetch('edit');
        // D:\phpstudy_pro\WWW\thinkphp\tp5\application\test\view\see\edit.html

        //指定目录下的模板
        return $this->fetch('public/edit');
        // D:\phpstudy_pro\WWW\thinkphp\tp5\application\test\view\public\edit.html

        // 指定模块下的模板,适用于多模块
        return $this->fetch('admin@public/edit');
        // D:\phpstudy_pro\WWW\thinkphp\tp5\application\admin\view\public\edit.html


        // view_path 下的模块
        return $this->fetch('/edit');
        // D:\phpstudy_pro\WWW\thinkphp\tp5\application\test\view\edit.html


        // 如果没有继承 Controller 模块的话,可以使用助手函数 view() 方法,具体使用方法同上
        return view();
        
    }
}

image-20210222104954007

视图赋值
  1. 在继承控制器基类的情况下,可以使用 assign() 方法进行赋值

    // See.php 
    class See extends Controller
    {
        public function index()
        {
            $this->assign('name','hello');
            return $this->fetch('index');
        }
    }
    
    // view/see/index.html
    {$name}
    

    image-20210222105857402

  2. 通过数组的方式,进行多个变量的赋值

    // See.php 
    $this->assign(['name' => 'hello', 'sex' => 'male', 'mail' => '2333@qq.com']);
    return $this->fetch('index');
    
    // view/see/index.html
    {$name}.{$sex}.{$mail}
    
  3. assign() 和 fetch() 方法合二为一

    return $this->fetch('index',['name'=>'xiaoli','sex'=>'male','mail'=>'wwww@qq.com']);
    
  4. 使用 display() 方法,可以不通过模板直接解析变量

    $content='{$name}.{$sex}.{$mail}';
    
    return $this->display($content,['name'=>'xiaoli','sex'=>'male','mail'=>'wwww@qq.com']);
    
  5. 使用 view() 助手函数实现渲染并赋值操作

    1.
    $this->assign(['name' => 'hello', 'sex' => 'male', 'mail' => '2333@qq.com']);
    return view('index');
    
    2.
    return view('index',['name' => 'hello', 'sex' => 'male', 'mail' => '2333@qq.com']);
    
    3.
    return view('index')->assign(['name' => 'hello', 'sex' => 'male', 'mail' => '2333@qq.com']); 
    
  6. 使用 View::share() 静态方法,可以在系统任意位置做全局变量赋值

    // public/static/index.php
    \think\facade\View::share('key','value');
    
    // view/see/index.html
    {$name}.{$sex}.{$mail}.{$key}
    

    image-20210222112144407

视图过滤
  1. 可以使用 filter() 方法,对模板页面输出的变量进行过滤

    class See extends Controller
    {
        public function index()
        {
            $this->assign(['name' => 'hello1', 'sex' => 'male1', 'mail' => '2333@qq.com']);
            return $this->filter(function ($content) {
                return str_replace('1', '<br>', $content);
            })->fetch();
            // $content 表示所有的模板变量
        }
    }
    
  2. 如果控制器有N个方法,都需要过滤,可以在初始化中全局过滤

    class See extends Controller
    {
        public function initialize()
        {
            return $this->filter(function ($content) {
                return str_replace('1', '<br>', $content);
            });
        }
    
        public function index()
        {
            $this->assign(['name' => 'hello1', 'sex' => 'male1', 'mail' => '2333@qq.com']);
            return $this->fetch();
        }
    }
    
  3. 也可以使用助手函数实现模板变量的过滤

    class See extends Controller
    {
        public function index()
        {
            $this->assign(['name' => 'hello1', 'sex' => 'male1', 'mail' => '2333@qq.com']);
            return view('index')->filter(
                function ($content) {
                    return str_replace('1', '<br>', $content);
                }
            );
        }
    }
    
模板变量输出

模板变量的输出方式,控制器实现赋值

$this->assign('name','ThinkPHP');

当模板位置创建好后,输出控制器的赋值变量时用花括号和$符号

{$name}

当程序在运行的时候,会在 runtime/temp 目录下生成一个编译文件

<?php echo htmlentities($name); ?>
  • 如果传递的是数组,也会对应
// controller/See.php
$data=['name' => 'hello1', 'sex' => 'male1', 'mail' => '2333@qq.com'];
$this->assign('user',$data);  // user是名字
return $this->fetch();

// view/see/index.php
{$user.name}.{$user.sex}.{$user['mail']}

// runtime/temp/
<?php echo htmlentities($user['name']); ?>.<?php echo htmlentities($user['sex']); ?>.<?php echo htmlentities($user['mail']); ?>
  • 对象
// controller/See.php
$obj=new \stdClass();
$obj->username='xiaoli';
$obj->mail='oooo@qq.com';
$this->assign('obj',$obj);
return $this->fetch('index');

// view/see/index.php
{$obj->username}.{$obj->mail}  // 只能用指向符号

// runtime/temp/
<?php echo htmlentities($obj->username); ?>.<?php echo htmlentities($obj->mail); ?>
  • 其他输出

1.如果输出的变量没有值可以直接设置默认值代替

// controller/See.php
$obj=new \stdClass();
$obj->username='';
$obj->mail='oooo@qq.com';
$this->assign('obj',$obj);
return $this->fetch('index');

// view/see/index.php
{$obj->username|default='nodata'}.{$obj->mail}

2.使用 $Think.xxx.yyy 方式,可以输出系统的变量及常量

// 变量
系统的变量有:$_SERVER  $_ENV  $_GET  $_POST  $_REQUEST  $_SESSION$_COOKIE

{$Think.get.name} # 下图

// 常量
{$Think.const.PHP_VERSION}{$Think.PHP_VERSION}

image-20210222145411904

3.系统配置也可以在模板输出,配置参数可以在 config 文件下

{$Think.config.default_return_type}
函数

1.模板 md5 加密

// controller/See.php
$this->assign('password','123456');
return $this->fetch();

// view/see/index.php
{$password|md5}

2.系统默认在编译时会采用 htmlentities (HTML实体化转义)过滤函数防止 XSS 跨站脚本攻击

<?php echo htmlentities(md5($password)); ?>

更换过滤函数,可以在配置文件中设置

// config/template.php
'default_filter' => 'htmlspecialchars'

如果不需要转义,可以使用 raw 过滤方法

ThinkPHP 提供的其他过滤方法

image-20210222152340808

3.可以使用 substr 进行切片

4.在模板中支持多个函数进行操作,用 | 号隔开即可,函数从左到右依次执行

// view/see/index.php
{$password|md5|upper|substr=0,3}

#### 运算符

在模板中的运算符有 + - * / % ++ –

如果模板中有运算符,则函数方法则不再支持

# 错误 {$password1 + $password2|upper|substr=0,3}

模板中可以实现三元运算,包括其他写法

// view/see/index.php
{$password ? 'true':'false'}
<!-- password 为 true 返回 字符串true,否则返回false-->
{$password ?= 'true'}
<!-- password 为 true 返回 字符串true-->
{$Think.get.name ?? 'not exist'}
<!-- 用于系统变量,没有值时输出 -->
{$password ?: 'not exist'}
<!-- 用于普通变量,没有值时输出 -->


<!-- runtime/temp -->
<?php echo !empty($password) ? 'true' : 'false'; ?>
<!-- password 为 true 返回 字符串true,否则返回false-->
<?php if(!empty($password)) echo 'true'; ?>
<!-- password 为 true 返回 字符串true-->
<?php echo (htmlentities(app('request')->get('name'))) ? htmlentities(app('request')->get('name')) :  'not exist'; ?>
<!-- 用于系统变量,没有值时输出 -->
<?php echo !empty($password) ? htmlentities($password) : 'not exist'; ?>
<!-- 用于普通变量,没有值时输出 -->
模板循环标签
foreach

1.控制前端先通过模型把对应的数据列表给筛选出来

$data=AdminModel::all();
$this->assign('list',$data);
return $this->fetch();

2.前端使用 foreach 进行循环

{foreach $list as $key=>$value}
{$key}{$value.name}{$value.pass}</br>
{/foreach}
// list 是数据集,key是索引,value是对象,key和value的名字不是绝对的

3.可以在模板中直接执行模型数据调用,而不需要在控制器中设置

{foreach :model('admin')->all() as $key=>$value}
{$key}{$value.name}{$value.pass}</br>
{/foreach}
volist
{volist name='list' id='obj'}  // 不用加 $
{$key}{$obj.name}{$obj.pass}</br>
{/volist}
// name 属性表示数据总集,id 属性表示当前循环的数据单条集
  • offset 和 length 属性表示从第 offset 条开始显示 length 条数据,下标从 0 开始
{volist name='list' id='obj' offset='2' length='3'}
{$key}{$obj.name}{$obj.pass}</br>
{/volist}

//
3user11233333
4user11233333
5user11233333
  • eq 标签

mod

// 实现奇偶判断
{volist name='list' id='obj' mod='2'}
    {eq name='mod' value='0'}
        {$key}{$obj.name}{$obj.pass}</br>
    {/eq}
{/volist}

// config/template.php
foreach($__LIST__ as $key=>$obj): $mod = ($i % 2 );++$i;if($mod == '0'):

//
0user11233333
2user11233333
4user11233333
6user11233333
8xiaoming12333333

empty

// 如果为空就返回 nodata
{volist name=':model("admin")->where("uid","100")->all()' id='obj' empty='nodata'}
{$key}{$value.name}{$value.pass}</br>
{/volist}

key

// $key 默认从0开始计数,$i 默认从1开始计数
{volist name='list' id='obj' }
{$i}-{$key}-{$value.name}-{$value.pass}</br>
{/volist}
//
1-0-xiaoming-12333333
2-1-xiaoming-12333333
3-2-xiaoming-12333333

key='k' 则不需要指定 {$i},$i失效
{volist name='list' id='obj' key='k'}
{$k}-{$key}-{$value.name}-{$value.pass}</br>
{/volist} 
for
{for start='1' end='10' comparison='<' name='i'} //i可以换
    {$i}
{/for}

1 2 3 4 5 6 7 8 9
比较标签
  • eq
{eq name='$name' value='siri1'} // name后加可以加$,也可以不加,value如果是字符串不加$,如果是变量则需要加$
equal
{else/}
not equal
{/eq}

其他比较标签

{gt}(>)
{egt}(>=)
{lt}(<)
{elt}(<=)
{heq}(===)
{nheq}(!==)
  • compare

所有的标签都可以使用 compare 来代替

{compare type='eq' name='name' value='siri'}
	equal
{/compare}
定义标签

1.定义变量:使用 {assign} 标签

{assign name='var' value='123'}
{$var}

2.定义常量:使用 {define} 标签

{define name='PI' value='3.14'}
{$Think.const.PI}

3.PHP原生编码:使用 {php} 标签

{php}
echo '原生防止脱发'
{/php}

原生编码就是 PHP 编码,不能再使用模板引擎的特殊编码方式,不支持 eq 等标签语法

4.标签嵌套

{foreach $list as $key=>$value}
    {eq name='value.name' value='xiaoming'}
        {$key}{$value.name}{$value.pass}
    {/eq}
{/foreach}
条件判断标签
  • switch
<?php
namespace app\test\controller;
use think\Controller;

class See extends Controller
{
    public function index()
    {
        $this->assign(['number'=>'10','cond'=>'10']);
        return $this->fetch('index');
    }
}
{switch $number}
    {case 1}1{/case}
    {case 10|20|30}10/20/30{/case}
    <!--支持多个条件判断,使用 | 分隔-->
    {case $cond}equal{/case}
	<!--case 后面也可以是变量,设置变量后不可以使用|线-->
	{default/}default
{/switch}
  • if
1.
{if $number>10}
	>10
{/if}

2.
{if ($number>10) OR ($cond<5) }
	<!--最好加括号-->
	true
{/if}

3.
{if $number>10 }
	number>10 true
{else/}
	number>10 False
{/if}

4.
{if $number>100 }
	number>100 true
{elseif $number>50}
	number>50 true
{else/}
	number>0 true
{/if}

5.{if 标签里的条件判断支持 PHP 写法,不支持 TP 函数}
// See.php
class See extends Controller
{
    public function index()
    {
        $man=new \stdClass();
        $man->name='Lee';
        $this->assign('man',$man);
        return $this->fetch('index');
    }
}

// index.html
{if strtoupper($man->name)=='LEE'}
	Lee
{/if}
范围标签
  • in
1.in
{in name='$number' value='10,20,30'}
    {$number} in array
{/in}
//10 in array

2.notin
{notin name='$number' value='10,20,30'}
    {$number} not in array
{/notin}
//11 not in array

3.in else
{in name='$number' value='10,20,30'}
    {$number} in array
    {else/}
    {$number} not in array
{/in}
//11 not in array

4.notin else
  • between
1. between
{between name='$number' value='10,20'}
    {$number} in this area
{/between}
//11 in this area

2.notbetween
{notbetween name='$number' value='15,20'}
    {$number} not in this area
{/notbetween}
//11 not in this area

value 只能有两个值,表示一个区间,第三个值无效,区间也可以用字母,比如 a-z
    
3.
{between name='$number' value='a,z'}
    {$number} in this area
{/between}  
//b in this area
  • present

    判断变量是否已经定义,是否存在

1.present
// See.php
$this->assign('number','');

// index.html
{present name='$number'}
    $number is exist
{else/}
	$number is not exist
{/present}
// $number is exist

2.notpresent
{notpresent name='$num'}
    $num is not exist
{/notpresent}
// num is not exist
  • empty
1.empty
// See.php
$this->assign('number','');

// index.html
{empty name='$number'}
    $number is empty
{else/}
	$number is not empty        
{/empty}
//$number is empty

2.notempty
  • defined

    判断常量是否定义(是否存在)

模板的加载包含输出

image-20210305200300382

{include fil e='public/header,public/nav'}
<!--如果写header.php则需要完整绝对路径-->
<!--{include file='../application/view/public/header.html'}-->
index
{include file='public/footer'}

调用数据

<!--block/index.html-->
{include file='public/header,public/nav' title='template' keyword='this is a temp!'}
index
{include file='public/footer'}

<!--public/header.html-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>[title]</title>
</head>
<body>
header
[keyword]
<br>   

image-20210305201713622

替换文件

有事需要调用静态文件

可以将静态文件存放在根目录 public/static/css

如果直接写完整目录,比较繁长,可以将路径整理打包

在目前二级目录下,template.php 中,配置新增一个参数

'tpl_replace_string'=>[
    '__JS__'=>'static/js',
    '__CSS__'=>'static/css',
]
// 配置文件修改后,需要删除缓存编译文件,重新创建    

如果在顶级域名下,直接改成 /static/css 即可,加一个反斜杠

html 文件调用端,直接通过 __CSS__(__JS)__配置的魔术方法调用即可

image-20210305203938271

文件加载

  1. 传统方式调用 CSS 或者 JS 文件时,采用 link 和 script 标签实现

  2. 系统提供了更加智能的加载方式,方便加载 CSS 和 JS 等文件

  3. 使用 {load} 标签和 href 属性来链接,不需要设置任何其他参数

    {load href='__CSS__/basic.css' /}
    {load href='__JS__/basic.js' /}
    
    {load href='__CSS__/basic.css,__JS__/basic.js' /}
    
  4. 还提供了两个别名 {js}、{css} 来更好地实现可读性

    {js href='__JS__/basic.js'}
    {css href='__CSS__/basic.css'}
    

    {js} 和 {css} 只是别名而已,php 是更具后缀来识别的

模板的布局和继承

模板布局

  • 第一种方法

默认情况下,不支持模板布局功能,需要在配置文件中开启

在配置文件 template.php 中,配置开始模板布局功能

'layout_on' => true,
# 配置 layout 的位置,文件名
'layout_name' => 'public/layout',

使用{__CONTENT__}类似魔法方法的标签来引入 index.html '主体’内容

如果需要更改 {__CONTENT__},可以在配置文件中配置

'layout_item'=>'{__REPLACE__}'

注意:如果更改了配置文件,需要删除 temp 下的编译文件再刷新

  • 第二种方法

只要在 index.html 的最上面加上如下代码,可实现模板布局

{layout name='public/layout' replace='[__CONTENT__]'}
#标签注释

{/*layout name='public/layout' replace='[__CONTENT__]'*/}
​```{/*layout name='public/layout' replace='[__CONTENT__]'*/}
  • 第三种方法

直接在控制器端执行 layout(true) 方法即可,false 表示临时关闭

$this->view->engine->layout(true);

这种方法不过不用默认的路径,还是要配置路径

template.php
'layout_name' => 'public/layout',

模板继承

类似于 flask 继承

image-20210306134703148

首先创建基文件 public/base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>base</title>
</head>
<body>
<h1>base</h1>
{$name}
<!--传递变量-->    

{block name='nav'}
    {include file='public/nav'}
{/block}
<!--挖坑-->    
</body>
</html>

block/extend.html

{extend name='public/base'}
or
{extend name='public:base'}

{block name='nav'}
{/block}
# 默认继承过来没有内容,如果需要原来的内容要加 {__block__}
{block name='nav'}
{__block__}
{/block}
模板中的一些杂项
  • 模板标签原样输出
{literal}
	{$name}
{/literal}

image-20210306141652036

  • 模板注释

html 注释只是不显示,还是会解析

# controller/see.php
$this->assign('name','lihua');

# view/see/other.html
<!--{$name}-->

image-20210306142254502

正确注释

# 单行注释
{//name}

# 多行注释
{/* 
*/}

注意:注释和 { 符号之间不能有空格,否则无法实现注释隐藏

生成编译文件后,注释的内容会被自动删除,不会显示

  • 标签扩展

image-20210306142700513

路由

image-20210306144127100

内置服务器:php think run

test/controller/Address.php
class Address extends Controller
{
    public function detail($id)
    {
        return 'detail'.$id;
    }
}

image-20210306144852953

5.html 会被解析成变量 5,其余后缀名不可以

添加路由

# route/route.php
think\facade\Route::get('details/:id','test/Address/detail');
# 注意:被替换的 url 开头不需要加 /
test 是模块名
Address 是控制器名
detail 是操作名    

url 写法变为

image-20210306150309430

选择 HTTP methods

think\facade\Route::get('details/:id','test/Address/detail',['GET']);

think\facade\Route::get('details/:id','test/Address/detail',['POST']);

think\facade\Route::get('details/:id','test/Address/detail',['GET|POST']);

路由分类

// 静态
think\facade\Route::get('static','test/Address/staticfunc');

// 动态
think\facade\Route::get('details/:id','test/Address/detail');

// 多参数动静态结合,url 可以输多个变量
think\facade\Route::get('double/:id/:uid','test/Address/double',['GET']);

// 规则完全匹配,只能有两个变量 也可以开启完全匹配,在 app.php 中配置
think\facade\Route::get('double/:id/:uid$','test/Address/double',['GET']);

// 多参数动静态结合,uid可选
think\facade\Route::get('choose/:id/[:uid]','test/Address/double',['GET']);

// 全动态地址,不限制 search 是否固定
think\facade\Route::get(':search/:id/:uid','test/Address/double',['GET']);


class Address extends Controller
{
    public function staticfunc()
    {
        return 'staticfunc';
    }

    public function detail($id)
    {
        return 'detail'.$id;
    }

    public function double($id,$uid='')
    {
        return 'detail'.$id.'uid'.$uid;
    }
}

控制使用路由地址

类似于 flask endpoint

  1. 通过 url() 方法来实现
# Address.php
class Address extends Controller
public function index()
    {
        return url('test/Address/index',['id'=>10]);
    }
}

# route/route.php
think\facade\Route::get('index','test/Address/index',['GET']);

image-20210306155604821

  1. 定义标识,起别名
# Address.php
class Address extends Controller
    public function index()
    {
        return url('index',['id'=>10]);
    }
}

# route/route.php
think\facade\Route::get('index','test/Address/index',['GET'])->name('index');
路由的变量规则

系统的默认路由规则为:\W+ 字母、数字、下划线

单个限制

# route/route.php
think\facade\Route::get('details/:id','test/Address/detail')->pattern('id','\d+');

pattern rule 为正则表达式

全部限制

# route/route.php
\think\facade\Route::pattern([
    'id'=>'\d+',
    'uid'=>'\w+',
]);

think\facade\Route::get('details/:id','test/Address/detail');

think\facade\Route::get('double/:id/:uid','test/Address/double');

组合变量规则

# route/route.php
think\facade\Route::get('double-:id-:uid','test/Address/double');
之间的分隔符可以换成 - _ 等

image-20210307092948901

动态组合拼装

如果地址和参数都是模糊动态的,可以使用如下方法

# route/route.php
think\facade\Route::get('dynmic-:name-:id','test/Hello_:name/index');
think\facade\Route::get('dynmic-:name-:id','test/Hello_<name>/index');

# test/controller/HelloWorld.php
    public function index($id)
    {
        return 'index'.$id;
    }

image-20210307093815968

image-20210307094234543

闭包

路由直接返回函数

Route::get('think', function () {
    return 'hello,ThinkPHP5!';
});

Route::get('bibao/:name', function ($name) {
    return 'hello!'.$name;
});
路由地址
  1. 路由地址一般为:控制器/方法,如果多模块则是:模块/控制器/方法
  2. 支持多级控制器
# test/controller/group/Address.php
<?php
namespace app\test\controller\group;
use think\Controller;

class Address extends Controller
{
    public function detail($id)
    {
        return 'detail'.$id;
    }
}

# route/route.php
think\facade\Route::get('gdetails/:id','test/group.Address/detail');

image-20210307104552028

  1. 支持动态路由地址以及额外参数地址
# test/controller/Address.php
class Address extends Controller
{
    public function param()
    {
        echo $this->request->param('flag');
    }
}

# route/route.php
think\facade\Route::get('param/:id','test/Address/param?flag=aaaa');
  1. 静态方法
# test/controller/Address.php
class Address extends Controller
{
    public static function stat($id){
        return 'static function'.$id;
    }
}

# route/route.php
think\facade\Route::get('stat/:id','app\test\controller\Address::stat');
使用 命名空间

image-20210307111457447

  1. 路由对模板传值
# test/view/see/other.html
<body>
{$name}
<br>
{$email}
</body>

# route/route.php
//\think\facade\Route::view('see/:name','test@See/other');
\think\facade\Route::view('see/:name','test@See/other',['email'=>'2222@qq.com']);

image-20210307125725052

重定向
think\facade\Route::get('details/:id','http://www.ocean888.cn')->status(302);

think\facade\Route::redirect('details/:id','http://www.ocean888.cn',302);
路由缓存

解析之后保存,提高效率,需要在部署环境下生效,在 app.php 开启

'route_check_cache'      => true,

# 关闭调试模式
'app_debug'              => true,

删除缓存

php think clear
路由参数

设置路由的时候,可以设置点三个数组参数,主要实施匹配检测和行为执行

  1. ext 参数作用是检测 URL 后缀,比如,强制所有 URL 后缀为 .html
\think\facade\Route::get('yyds/:id','test/Address/detail',['ext'=>'html']);

# 第三组参数也可以作为对象的方法存在
\think\facade\Route::get('yyds/:id','test/Address/detail')->ext('html');
  1. https 参数作用是检测是否为 https 请求
  2. 全局统一配置
app.php
'url_html_suffix'='html'
  1. 禁止某些后缀
denyExt('')
['denyExt'=>'']
  1. filter对额外参数进行检测
filter('id',10)
  1. model 绑定到模型,第三方参数设置 false 避免异常,也可以多参数
# test/controller/Address.php
class Address extends Controller
{   # 数据注入
    public function search(\app\test\model\Admin $user)
    {
        return json($user);
    }
}

# route/route.php
# 默认参数是id
\think\facade\Route::get('model/:uid','test/Address/search')->model('app\test\model\Admin');

\think\facade\Route::get('model/:uid','test/Address/search')->model('uid','app\test\model\Admin');

# 加第三个参数 false 忽略报错
\think\facade\Route::get('model/:uid','test/Address/search')->model('uid','app\test\model\Admin',false);
  1. option 参数作用是全局的路由进行配置,且可以多次调用
\think\facade\Route::option('ext','html')->option('https','true');
快捷路由

快捷路由可以快速给控制器注册路由,还可以以不同的请求类型设置前缀

快捷路由控制器和方法编写规则:给方法前面加上 get 或 post 等代表对应请求类型

就是更具不同的请求类型,返回对应的函数

# test/controller/Short.php

class Short extends Controller
{
    public function index()
    {
        return 'index';
    }
    public function getInfo()
    {
        echo 'getinfo';
    }

    public function postInfo()
    {
        echo 'postinfo';
    }
}

# route/route.php
\think\facade\Route::controller('short','test/Short');

image-20210307145043200

路由分组

将前缀相同的路由进行合并分组,以简化路由定义,提高匹配效率

  1. 使用 group() 方法,来进行分组路由的注册
# test/controller/collect.php
class Collect extends Controller
{
    public function index()
    {
        return 'index';
    }

    public function read($id)
    {
        return 'read is' . $id;
    }

    public function who($name)
    {
        return 'name is'.$name;
    }
}

# route/route.php
\think\facade\Route::group('col',[
    'index'=>'test/Collect/index',
    ':id'=>'test/Collect/read',
    ':name'=>'test/Collect/who'
])->ext('html')->pattern(['id'=>'\d+$','name'=>'\w+$']);

image-20210308195359535

image-20210308195409585

由于限制了 ext 后缀名,所以必须加 .html

  1. 使用 group() 方法,并采用闭包的形式进行注册
\think\facade\Route::group('col', function () {
    \think\facade\Route::get(':id','test/Collect/read');
    \think\facade\Route::get(':name','test/Collect/who');
})->ext('html')->pattern(['id'=>'\d+$','name'=>'\w+$']);
  1. prefix 简化路由
# route/route.php
\think\facade\Route::group('col',[
    'index'=>'index',
    ':id'=>'read',
    ':name'=>'who'
])->prefix('test/Collect/')->ext('html')->pattern(['id'=>'\d+$','name'=>'\w+$']);

image-20210308202715830

  1. append() 方法,可以传入额外参数,用 request 获取
# test/controller/collect.php
public function read($id)
{
    echo $this->request->param('flag');
    return 'read is' . $id;
}

# route/route.php
\think\facade\Route::group('col',[
    'index'=>'index',
    ':id'=>'read',
    ':name'=>'who'
])->prefix('test/Collect/')->ext('html')->pattern(['id'=>'\d+$','name'=>'\w+$'])->append(['flag'=>1]);

image-20210308203255080

  1. 路由规则(主要是分组和域名路由)定义的文件,加载时会解析消耗较多的资源,尤其是规则特别庞大的时候,开启延迟解析只有在匹配的时候才会注册解析
# config/app.php    
// 是否开启路由延迟解析
'url_lazy_route' => true,
注解路由

可以在注释中直接创建路由,默认为关闭

开启路由注解

// config/app.php
// 使用注解路由
'route_annotation'       => false,

使用

在要加入注解的位置右击,选择 generate

image-20210308210021803

image-20210308210101930

image-20210308210133681

image-20210308205851122

image-20210308205826270

MISS

1.全局 MISS 类似开启强制路由功能,匹配不到相应规则时会自动跳转到 MISS

# route/route.php
\think\facade\Route::miss('test/See/miss');

# test/controller/See.php
    public function miss()
    {
        return '404 not found!';
    }

image-20210309142514011

2.分组 MISS 可以在路由分组中使用 miss 方法,当不满足匹配规则时跳转到这里

# route/route.php
\think\facade\Route::group('col', function () {
    \think\facade\Route::get(':id','test/Collect/read');
    \think\facade\Route::miss('test/See/miss');
})->ext('html')->pattern(['id'=>'\d+$','name'=>'\w+$']);

image-20210309142952793

跨域请求
# route/route.php
\think\facade\Route::miss('test/See/miss')->header('Access-Control-Allow-Origin','www.ocean888.cn')->allowCrossDomain();

allowCrossDomain()  允许跨域请求
header('Access-Control-Allow-Origin','www.ocean888.cn') 限制只能来自 www.ocean888.cn 的跨域请求
绑定

路由绑定可以简化 URL 和路由规则的定义,可以绑定到模块/控制器/操作

由于本身不是规则,需要关闭强制路由后测试,本身绑定并不是定义路由

未绑定(默认绑定 index )

image-20210309151423547

绑定后

\think\facade\Route::bind('test');

image-20210309151455570

可以绑定到模块、控制器、操作

别名

给一个控制器起一个别名,可以通过别名自动生成一系列规则

例:

\think\facade\Route::alias('index','test/See/index');

image-20210309194445464

也支持别名设置限定条件

\think\facade\Route::alias('index','test/See/index',['ext'=>'html']);

别名路由和快捷路由在 PHP6 已经废弃

资源路由

1.资源路由,采用固定的常用方法来实现简化 URL 的功能

2.系统提供了一个命令,方便开发者快速生成一个资源控制器

php think make:controller index/Blog # index 模块下生成 Blog

# 单模块不需要加模块名,根据    
php think make:controller Blog
Controller created successfully.    

image-20210309200846611

3.从生成的多个方法,包含了显示、增删改查等多个操作方法

4.在路由 route.php 文件下创建一个资源路由,资源名称可自定义

\think\facade\Route::resource('blog','Blog');
# ('资源名','资源路径')

5.资源路由注册成功后,会自动提供以下方法(不能自己添加),无须手动注册

# GET 访问模式下: 
index(blog),create(blog/create),read(blog/:id),edit(blog:id/edit)
# POST 访问模式下:
save(blog)
# PUT 访问模式下:
update(blog/:id)
# DELETE 访问模式下
delete(blog/:id)

post 一般是表单提交,put 和 delete 用 ajax 访问

# public/test/test.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>test</title>
</head>
<body>
<div>
    <input type="submit" id="button" value="confirm">
</div>
</body>
<script>
    $('#button').click(function (){
        $.ajax({
            type:'DELETE',
            url:'http://localhost:8000/blog/10',
            success:function(res){
                console.log(res);
            }
        })
    })
</script>
</html>

image-20210309205812469

image-20210309205746069

6.默认的参数采用 id 名称,如果需要更换使用 var() 方法

\think\facade\Route::resource('blog','Blog')->vars(['blog'=>'blog_id']);

7.only() 方法限定访问方法

\think\facade\Route::resource('blog','Blog')->only(['index','read','edit']);

image-20210309210717621

image-20210309210815331

8.except() 方法排除系统提供的资源方法

\think\facade\Route::resource('blog','Blog')->except(['update']);

9.使用 reset() 方法,更改系统给予的默认方法,1.请求地址;2.地址;3.操作

\think\facade\Route::rest([
    'save'=>['POST','','store']
]);
\think\facade\Route::resource('blog','Blog')->except(['update']);

10.使用嵌套资源路由,让上级资源对下级资源进行操作

image-20210309212519509

# comment.php
<?php
namespace app\controller;
use think\Controller;

class Comment extends Controller
{
    public function read($id, $blog_id)
    {
        return 'read comment id is :'.$id.' and blog id is:'.$blog_id;
    }
}

# route/route.php
\think\facade\Route::resource('blog','Blog')->except(['update']);
\think\facade\Route::resource('blog.comment','Comment');

使用嵌套路由

image-20210309212622276

image-20210309212707351

域名路由

如果使用需要域名路由,首先在本地 hosts 文件来映射

127.0.0.1 ocean.com
# route/route.php
# 闭包方法
\think\facade\Route::domain('ocean.com',function (){
    \think\facade\Route::get('edit/:id','test/Collect/read');
});

# 普通方法
\think\facade\Route::domain('ocean.com',
    ['edit/:id' => 'test/Collect/read',]
);

image-20210310191438996

绑定多个三级域名

\think\facade\Route::domain(['open','live'],
    ['edit/:id' => 'test/Collect/read',]
);

使用通配符

image-20210310194115939

URL 生成

之前所有的 URL,都是手动键入的,路由提供了一套生成方式

Url:build('地址表达式'.['参数'],['URL 后缀'],['域名'])
url('地址表达式',['参数'],['URL 后缀'],['域名'])    

可以使用助手函数

iv>

```

[外链图片转存中…(img-T5c7ZZit-1615809818891)]

[外链图片转存中…(img-kbr45H5G-1615809818892)]

6.默认的参数采用 id 名称,如果需要更换使用 var() 方法

\think\facade\Route::resource('blog','Blog')->vars(['blog'=>'blog_id']);

7.only() 方法限定访问方法

\think\facade\Route::resource('blog','Blog')->only(['index','read','edit']);

[外链图片转存中…(img-1mbLYl9x-1615809818893)]

[外链图片转存中…(img-AkXLsto2-1615809818894)]

8.except() 方法排除系统提供的资源方法

\think\facade\Route::resource('blog','Blog')->except(['update']);

9.使用 reset() 方法,更改系统给予的默认方法,1.请求地址;2.地址;3.操作

\think\facade\Route::rest([
    'save'=>['POST','','store']
]);
\think\facade\Route::resource('blog','Blog')->except(['update']);

10.使用嵌套资源路由,让上级资源对下级资源进行操作

[外链图片转存中…(img-Me0yw3Zm-1615809818895)]

# comment.php
<?php
namespace app\controller;
use think\Controller;

class Comment extends Controller
{
    public function read($id, $blog_id)
    {
        return 'read comment id is :'.$id.' and blog id is:'.$blog_id;
    }
}

# route/route.php
\think\facade\Route::resource('blog','Blog')->except(['update']);
\think\facade\Route::resource('blog.comment','Comment');

使用嵌套路由

[外链图片转存中…(img-kNJymzC4-1615809818895)]

[外链图片转存中…(img-zXpKEmR4-1615809818896)]

域名路由

如果使用需要域名路由,首先在本地 hosts 文件来映射

127.0.0.1 ocean.com
# route/route.php
# 闭包方法
\think\facade\Route::domain('ocean.com',function (){
    \think\facade\Route::get('edit/:id','test/Collect/read');
});

# 普通方法
\think\facade\Route::domain('ocean.com',
    ['edit/:id' => 'test/Collect/read',]
);

[外链图片转存中…(img-xKbgSjGQ-1615809818897)]

绑定多个三级域名

\think\facade\Route::domain(['open','live'],
    ['edit/:id' => 'test/Collect/read',]
);

使用通配符

[外链图片转存中…(img-ZnqSe804-1615809818898)]

URL 生成

之前所有的 URL,都是手动键入的,路由提供了一套生成方式

Url:build('地址表达式'.['参数'],['URL 后缀'],['域名'])
url('地址表达式',['参数'],['URL 后缀'],['域名'])    

可以使用助手函数

方法很多…

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

OceanSec

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值