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

废话不多说直接上车

  1. 创建地区表结构
1
2
3
4
5
6
7
8
9
10
11
12
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

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
41
42
43
44
45
46
47
48
49
50
51
<?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,这个自行定义,只要可以调用就行

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
<?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

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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
<?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. 视图文件添加地区挂件
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
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字段
坚持原创技术分享,您的支持将鼓励我继续创作!
0%