Yii2 自定义省市区三级联动挂件

废话不多说直接上车

  1. 创建地区表结构
DROP TABLE IF EXISTS `region`;
CREATE TABLE `region`  (
  `region_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '地区ID号',
  `parent_id` int(10) UNSIGNED NOT NULL DEFAULT 0 COMMENT '地区父级ID',
  `region_name` varchar(120) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '地区名称',
  `region_type` tinyint(1) NOT NULL DEFAULT 2 COMMENT '地区级别',
  PRIMARY KEY (`region_id`) USING BTREE,
  INDEX `parent_id`(`parent_id`) USING BTREE,
  INDEX `region_name`(`region_name`) USING BTREE,
  INDEX `region_type`(`region_type`) USING BTREE,
  INDEX `agency_id`(`agency_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 659009509 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '地区' ROW_FORMAT = Dynamic;
  1. 创建 Region Model 文件

/common/models/Region.php

<?php

namespace common\models;

use yii\db\ActiveRecord;
use yii\helpers\ArrayHelper;

class Region extends ActiveRecord
{
    /**
     * {@inheritdoc}
     */
    public static function tableName()
    {
        return '{{%region}}';
    }

    /**
     * {@inheritdoc}
     */
    public function rules()
    {
        return [
            [['region_name'], 'required'],
        ];
    }

    /**
     * {@inheritdoc}
     */
    public function attributeLabels()
    {
        return [
            'region_id' => '地区ID',
            'parent_id' => '地区父级ID',
            'region_name' => '地区名称',
            'region_type' => '地区级别'
        ];
    }

    /**
     * 获取
     * @param int $parent_id
     * @return array
     */
    public static function getRegion($parent_id=1)
    {
        $regions = static::find()->where(['parent_id'=>$parent_id])->asArray()->all();
        return ArrayHelper::map($regions, 'region_id', 'region_name');
    }
}
  1. 创建ajax异步获取地区数据链接方法

/backend/controllers/common/AjaxController.php,这个自行定义,只要可以调用就行

<?php
namespace backend\controllers\common;

use backend\controllers\BaseController;
use common\models\Region as RegionModel;
use Yii;
use yii\helpers\Html;
use yii\web\Response;

//ajax联动接口
class AjaxController extends BaseController
{
    //免认证方法
    public function allowAction()
    {
        return [];
    }

    /**
     * 地区联动查询
     * @return string
     */
    public function actionGetRegion()
    {
        $parent_id = Yii::$app->request->get('parent_id', 0);
        $regions = RegionModel::getRegion($parent_id);

        $result = '';
        foreach($regions as $key => $val){
            $result .= Html::tag('option', $val, ['value' => $key]);
        }

        return $result;
    }
}
  1. 创建地区三级联动挂件

/common/widgets/Region.php

<?php
namespace common\widgets;

use yii\base\InvalidParamException;
use yii\base\Widget;
use yii\helpers\ArrayHelper;
use yii\helpers\Html;

class Region extends Widget
{
    public $model = null;

    /**
     * @var string 此属性不用处理
     */
    public $attribute;

    /**
     * @var array 外层属性配置
     */
    public $options = [];

    /**
     * @var array 省份配置
     */
    public $province = [];

    /**
     * @var array 城市配置
     */
    public $city = [];

    /**
     * @var array 县/区配置
     */
    public $district = [];

    /**
     * @var mixed 数据源
     */
    public $url;

    public function init()
    {
        if (!$this->model) {
            throw new InvalidParamException('model不能为null!');
        }

        if (empty($this->province) || empty($this->city)) {
            throw new InvalidParamException('province和city不能为空!');
        }

        $cityId = Html::getInputId($this->model, $this->city['attribute']);
        if (empty($this->city['options']['prompt'])) {
            $this->city['options']['prompt'] = '选择城市';
        }
        $cityDefault = Html::renderSelectOptions('city', ['' => $this->city['options']['prompt']]);

        $joinChar = strripos($this->url, '?') ? '&' : '?';
        $url = $this->url . $joinChar;

        if (!empty($this->district)) {
            if (empty($this->district['options']['prompt'])) {
                $this->district['options']['prompt'] = '选择县/区';
            }
            $districtId = Html::getInputId($this->model, $this->district['attribute']);
            $districtDefault = Html::renderSelectOptions('district', ['' => $this->district['options']['prompt']]);
            $this->city['options'] = ArrayHelper::merge($this->city['options'], [
                'onchange' => "
                    if($(this).val() != ''){
                        $.get('{$url}parent_id='+$(this).val(), function(data) {
                            $('#{$districtId}').html('{$districtDefault}'+data);
                        })
                    }else{
                        $('#{$districtId}').html('{$districtDefault}');
                    }
                "
            ]);
        }

        $provinceOnchangeHtml = "
                if($(this).val()!=''){
                    $.get('{$url}parent_id='+$(this).val(), function(data) {
                        $('#{$cityId}').html('{$cityDefault}'+data);
                    })
                }else{
                    $('#{$cityId}').html('{$cityDefault}');
                }
            ";
        if (!empty($districtId)) {
            $provinceOnchangeHtml .= "$('#{$districtId}').html('{$districtDefault}');";
        }
        $this->province['options'] = ArrayHelper::merge($this->province['options'], [
            'onchange' => $provinceOnchangeHtml
        ]);

    }

    public function run()
    {
        $output[] = Html::activeDropDownList($this->model, $this->province['attribute'], $this->province['items'],
            $this->province['options']);
        $output[] = Html::activeDropDownList($this->model, $this->city['attribute'], $this->city['items'],
            $this->city['options']);
        if (!empty($this->district)) {
            $output[] = Html::activeDropDownList($this->model, $this->district['attribute'], $this->district['items'],
                $this->district['options']);
        }

        return Html::tag('div', @implode("\n", $output), $this->options);
    }

}
  1. 视图文件添加地区挂件
use common\models\Region as RegionModel;
use common\widgets\Region as RegionWidget;

...
...

<?=$form->field($model, 'city')->widget(RegionWidget::className(), [
        'options' => ['class'=>'c-md-4'],
        'model' => $model,
        'url' => Url::toRoute(['/common/ajax/get-region']),
        'province' => [
            'attribute' => 'province',
            'items' => RegionModel::getRegion(),
            'options' => ['class'=>'form-control c-md-3 inline', 'prompt'=>'选择省份']
        ],
        'city' => [
            'attribute' => 'city',
            'items' => RegionModel::getRegion($model['province']),
            'options' => ['class'=>'form-control c-md-3 inline', 'prompt'=>'选择城市']
        ],
        'district' => [
            'attribute' => 'district',
            'items' => RegionModel::getRegion($model['city']),
            'options' => ['class'=>'form-control c-md-3 inline', 'prompt'=>'选择县/区']
        ],
]); ?>

Tip:

  1. Url::toRoute(['/common/ajax/get-region'])生成的链接,调用是第3步的方法
  2. 'attribute' => 'province'$model模型添加 province字段
  3. 'attribute' => 'city'$model模型添加 city字段
  4. 'attribute' => 'district'$model模型添加 district字段
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

PeakXin

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

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

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

打赏作者

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

抵扣说明:

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

余额充值