PHP | 前端

PHP实现省市区三级联动

最近接触的项目都有用到选省市区的,还需要根据地区来做区域代理的方案。
所以不能简单的储存字符串了,要做一个带有地址码的数据,根据地址码来匹配相应的地区。

首先我从哪里获取带有地址码的数据,首先想到的是高德地图和百度地图这些,没找到。于是去composer官网找了一下,发现了有thinkphp的四级联动的拓展插件,里面的功能逻辑倒是无所谓,我只要地址的数据就行了。开工!!!

ThinkPHP省市区(县)街道四级联动扩展

安装拓展

composer require yupoxiong/region

创建数据表

复制vendor/yupoxiong/region/database/migrations目录下的数据库文件
迁移文件到TP迁移目录(一般是 /database/migrations/ )
文件名称示例 (2020082012564_region_table.php)

然后可能需要安装一下TP的数据库迁移拓展

TP 5.0
composer require topthink/think-migration=1.*

TP 5.1
composer require topthink/think-migration=2.*

因为这个逆向的操作,不是从数据库中生成迁移的数据表文件,而是根据数据表文件生成数据。
现在已经有了这个地区的数据表文件,直接生成数据库就行了

注意:项目的数据库连接配置必须正确且可以操作数据库

直接在项目根目录运行下面的命令

php think migrate:run

不出意外已经有数据了

不用自宫也可成功,下面是我整理好的数据,点击就可以下载♥

点击下载我整理好的mysql文件

复制写好的模型文件

//模型文件具体在哪里已经忘了,在vender/yupoxiong/src 里面找找就行
//然后我把模型文件改了一下,放到了我的模型目录了

<?php
/**
 * 省市区模型
 * @author yupoxiong<i@yufuping.com>
 * @date 2018/10/29
 */

namespace app\model;

use think\Model;

class RegionModel extends Model
{

    protected $config = [
        'cache' => 20140210,
        'field' => 'id,name',
        'order' => 'adcode asc',
    ];

    public function __construct($data = [])
    {
        parent::__construct($data);
        $config = config('region');
        if ($config) {
            if (!isset($config['cache']) || !isset($config['field'])|| !isset($config['order'])) {
                throw new \Exception('配置不完整');
            }
            $this->config = $config;
        }
    }

    /**
     * 获取地区
     * @param int $address_id
     * @return array|\PDOStatement|string|\think\Collection
     */
    public function getRegion($address_id = 0)
    {
        return $this
            ->where('id', $address_id)
            ->field($this->config['field'])
            ->cache($this->config['cache'])
            ->order($this->config['order'])
            ->find();
    }

    public function getProvince()
    {
        return $this
            ->where('level', 1)
            ->field($this->config['field'])
            ->cache($this->config['cache'])
            ->order($this->config['order'])
            ->select();
    }

    public function getCity($parent_id)
    {
        return $this
            ->where('parent_id', $parent_id)
            ->where('level', 2)
            ->field($this->config['field'])
            ->cache($this->config['cache'])
            ->order($this->config['order'])
            ->select();
    }

    public function getDistrict($parent_id)
    {
        return $this
            ->where('parent_id', $parent_id)
            ->where('level', 3)
            ->field($this->config['field'])
            ->cache($this->config['cache'])
            ->order($this->config['order'])
            ->select();
    }

    public function getStreet($parent_id)
    {
        return $this
            ->where('parent_id', $parent_id)
            ->where('level', 4)
            ->field($this->config['field'])
            ->cache($this->config['cache'])
            ->order($this->config['order'])
            ->select();
    }

    public function searchRegion($keywords, $parent_id = 0)
    {
        return $this
            ->where('parent_id', $parent_id)
            ->whereLike('name|initial|pinyin', '%' . $keywords . '%')
            ->field($this->config['field'])
            ->cache($this->config['cache'])
            ->order($this->config['order'])
            ->select();
    }

    public function searchProvince($keywords)
    {
        return $this
            ->where('level', 1)
            ->whereLike('name|initial|pinyin', '%' . $keywords . '%')
            ->field($this->config['field'])
            ->cache($this->config['cache'])
            ->order($this->config['order'])
            ->select();
    }

    public function searchCity($keywords, $parent_id = 0)
    {
        return $this
            ->where('level', 2)
            ->where('parent_id', $parent_id)
            ->whereLike('name|initial|pinyin', '%' . $keywords . '%')
            ->field($this->config['field'])
            ->cache($this->config['cache'])
            ->order($this->config['order'])
            ->select();
    }

    public function searchDistrict($keywords, $parent_id = 0)
    {
        return $this
            ->where('level', 3)
            ->where('parent_id', $parent_id)
            ->whereLike('name|initial|pinyin', '%' . $keywords . '%')
            ->field($this->config['field'])
            ->cache($this->config['cache'])
            ->order($this->config['order'])
            ->select();
    }

    public function searchStreet($keywords, $parent_id = 0)
    {
        return $this
            ->where('level', 4)
            ->where('parent_id', $parent_id)
            ->whereLike('name|initial|pinyin', '%' . $keywords . '%')
            ->field($this->config['field'])
            ->cache($this->config['cache'])
            ->order($this->config['order'])
            ->select();
    }

}

既然数据有了那我可以把插件拓展卸载了

composer remove yupoxiong/region

前端我用的是layui

//先使用模板渲染把省的数据渲染上去,监听省下拉框的值
//改变了就用ajax把市,以及第一个市下面的区域信息异步拿到并渲染
//再写一个方法监听市的值,改变了就异步渲染该市下面区域信息

<div class="layui-form-item">
    <label class="layui-form-label">联动选择框</label>
    <div class="layui-input-inline">
        <select name="province_id" lay-filter="province_filter">
            <option value="">请选择省</option>
            {volist name="province" id="pv"}
                <option value="{$pv.id}">{$pv.name}</option>
            {/volist}
        </select>
    </div>
    <div class="layui-input-inline">
        <select name="city_id" id="city" lay-filter="city_filter">
            <option value="">请选择市</option>

        </select>
    </div>
    <div class="layui-input-inline">
        <select name="district_id" id="district">
            <option value="">请选择县/区</option>

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

// js 记得要更新渲染一下layui的form
// form.render();

layui.use(['form'], function(){
    var form = layui.form;

    form.on('select(province_filter)', function(data){
        var province_id = $(data.elem).find("option:selected").val();
        $.get("{:url('admin/Machine/get_city')}",{province_id:province_id},function(res){
            if (res.code == 0) {
                $('#city').children('option').remove();
                var city = res.data;
                for (var prop in city) {
                    $('#city').append("<option value="+city[prop].id+">"+city[prop].name+"</option>");
                }
                form.render();
                $.get("{:url('admin/Machine/get_area')}",{city_id:city[0].id},function(res){
                    if (res.code == 0) {
                        $('#district').children('option').remove();
                        var area = res.data;
                        for (var prop in area) {
                            $('#district').append("<option value="+area[prop].id+">"+area[prop].name+"</option>");
                        }
                    }
                    form.render();
                },'json');
            }

        },'json');
    });

    form.on('select(city_filter)', function(data){
        var city_id = $(data.elem).find("option:selected").val();
        $.get("{:url('admin/Machine/get_area')}",{city_id:city_id},function(res){
            if (res.code == 0) {
                $('#district').children('option').remove();
                var area = res.data;
                for (var prop in area) {
                    $('#district').append("<option value="+area[prop].id+">"+area[prop].name+"</option>");
                }
            }
            form.render();
        },'json');
    });

});

PHP

//获取省
$province = (new RegionModel())->getProvince();

//获取省下面的市
$province_id = 省id;
$city = (new RegionModel())->getCity($province_id);

//获取市下面区域
$city_id = 市id;
$area = (new RegionModel())->getDistrict($city_id);

方法很多,这个是我实现的方法。也可以一次性把数据全部拿完放到页面上操作的,只是我的前端水平不够~

类似文章