美文网首页
Laravel npm引入省市三级联动vue组件

Laravel npm引入省市三级联动vue组件

作者: 前端组件库 | 来源:发表于2019-12-26 12:16 被阅读0次

    我们知道这个组件有很多版本的,例如有香草JS版的,Jquery版的。我们这里用的是一个vue版的。vue组件在laravel开发中显得很方便,直接引入便可。我们可以采用内联的方式引入,中文叫内联模板(inline template)。我们接下来谈谈如何引入这个三级联动的npm包。

    1.安装npm插件

    执行命令:

    npm install china-area-data
    

    就可以了。

    2.创建vue组件

    在resources/js/components文件夹下创建一个文件selectArea.js, 具体内容如下:

    // 从刚刚安装的库中加载数据
    const addressData = require('china-area-data/v3/data');
    // 引入 lodash,lodash 是一个实用工具库,提供了很多常用的方法
    import _ from 'lodash';
    
    // 注册一个名为 select-area 的 Vue 组件
    Vue.component('select-area', {
      // 定义组件的属性
      props: {
        // 用来初始化省市区的值,在编辑时会用到
        initValue: {
          type: Array, // 格式是数组
          default: () => ([]), // 默认是个空数组
        }
      },
      // 定义了这个组件内的数据
      data() {
        return {
          provinces: addressData['86'], // 省列表
          cities: {}, // 城市列表
          districts: {}, // 地区列表
          provinceId: '', // 当前选中的省
          cityId: '', // 当前选中的市
          districtId: '', // 当前选中的区
        };
      },
      // 定义观察器,对应属性变更时会触发对应的观察器函数
      watch: {
        // 当选择的省发生改变时触发
        provinceId(newVal) {
          if (!newVal) {
            this.cities = {};
            this.cityId = '';
            return;
          }
          // 将城市列表设为当前省下的城市
          this.cities = addressData[newVal];
          // 如果当前选中的城市不在当前省下,则将选中城市清空
          if (!this.cities[this.cityId]) {
            this.cityId = '';
          }
        },
        // 当选择的市发生改变时触发
        cityId(newVal) {
          if (!newVal) {
            this.districts = {};
            this.districtId = '';
            return;
          }
          // 将地区列表设为当前城市下的地区
          this.districts = addressData[newVal];
          // 如果当前选中的地区不在当前城市下,则将选中地区清空
          if (!this.districts[this.districtId]) {
            this.districtId = '';
          }
        },
        // 当选择的区发生改变时触发
        districtId() {
          // 触发一个名为 change 的 Vue 事件,事件的值就是当前选中的省市区名称,格式为数组
          this.$emit('change', [this.provinces[this.provinceId], this.cities[this.cityId], this.districts[this.districtId]]);
        },
      },
      // 组件初始化时会调用这个方法
      created() {
        this.setFromValue(this.initValue);
      },
      methods: {
        // 
        setFromValue(value) {
          // 过滤掉空值
          value = _.filter(value);
          // 如果数组长度为0,则将省清空(由于我们定义了观察器,会联动触发将城市和地区清空)
          if (value.length === 0) {
            this.provinceId = '';
            return;
          }
          // 从当前省列表中找到与数组第一个元素同名的项的索引
          const provinceId = _.findKey(this.provinces, o => o === value[0]);
          // 没找到,清空省的值
          if (!provinceId) {
            this.provinceId = '';
            return;
          }
          // 找到了,将当前省设置成对应的ID
          this.provinceId = provinceId;
          // 由于观察器的作用,这个时候城市列表已经变成了对应省的城市列表
          // 从当前城市列表找到与数组第二个元素同名的项的索引
          const cityId = _.findKey(addressData[provinceId], o => o === value[1]);
          // 没找到,清空城市的值
          if (!cityId) {
            this.cityId = '';
            return;
          }
          // 找到了,将当前城市设置成对应的ID
          this.cityId = cityId;
          // 由于观察器的作用,这个时候地区列表已经变成了对应城市的地区列表
          // 从当前地区列表找到与数组第三个元素同名的项的索引
          const districtId = _.findKey(addressData[cityId], o => o === value[2]);
          // 没找到,清空地区的值
          if (!districtId) {
            this.districtId = '';
            return;
          }
          // 找到了,将当前地区设置成对应的ID
          this.districtId = districtId;
        }
      }
    });
    

    3.在app.js中引入组件,注意位置,一定要在

    Vue.component('example-component', require('./components/ExampleComponent.vue').default);
    

    之后引入,否则无法加载输入。

    require('./components/SelectArea');
    

    执行命令:

    npm run dev
    

    如果是在npm run watch-poll运行的情况下可以不执行命令。

    4.插入内联模板

    在html代码里面以内联的方式插入:

    <select-district inline-template>
                  <div class="form-row">
                    <label class="col-form-label col-sm-2 text-md-right">省市区</label>
                    <div class="col-sm-3">
                      <select class="form-control" v-model="provinceId">
                        <option value="">选择省</option>
                        <option v-for="(name, id) in provinces" :value="id">@{{ name }}</option>
                      </select>
                    </div>
                    <div class="col-sm-3">
                      <select class="form-control" v-model="cityId">
                        <option value="">选择市</option>
                        <option v-for="(name, id) in cities" :value="id">@{{ name }}</option>
                      </select>
                    </div>
                    <div class="col-sm-3">
                      <select class="form-control" v-model="districtId">
                        <option value="">选择区</option>
                        <option v-for="(name, id) in districts" :value="id">@{{ name }}</option>
                      </select>
                    </div>
                  </div>
                </select-district>
    

    5.提交到后端

    我们发现这里其实没有name这个属性,没有这个属性我们是无法提交到后端的,为此我们再创建了一个组件叫change,在resources/js/components文件夹下。我们需要设置一个隐藏的提交表单。

        <user-addresses-create-and-edit inline-template>
          <form class="form-horizontal" role="form">
            <!-- 引入 csrf token 字段 -->
          {{ csrf_field() }}
          <!-- 注意这里多了 @change -->
            <select-district @change="onDistrictChanged" inline-template>
              <div class="form-group row">
                <label class="col-form-label col-sm-2 text-md-right">省市区</label>
                <div class="col-sm-3">
                  <select class="form-control" v-model="provinceId">
                    <option value="">选择省</option>
                    <option v-for="(name, id) in provinces" :value="id">@{{ name }}</option>
                  </select>
                </div>
                <div class="col-sm-3">
                  <select class="form-control" v-model="cityId">
                    <option value="">选择市</option>
                    <option v-for="(name, id) in cities" :value="id">@{{ name }}</option>
                  </select>
                </div>
                <div class="col-sm-3">
                  <select class="form-control" v-model="districtId">
                    <option value="">选择区</option>
                    <option v-for="(name, id) in districts" :value="id">@{{ name }}</option>
                  </select>
                </div>
              </div>
            </select-district>
            <!-- 插入了 3 个隐藏的字段 -->
            <!-- 通过 v-model 与 user-addresses-create-and-edit 组件里的值关联起来 -->
            <!-- 当组件中的值变化时,这里的值也会跟着变 -->
            <input type="hidden" name="province" v-model="province">
            <input type="hidden" name="city" v-model="city">
            <input type="hidden" name="district" v-model="district">
    </user-addresses-create-and-edit>
    

    6.显示修改值

    当我们提交到后端的时候我们还是发现,选择的下拉菜单选项值没有选择我们修改的值。接下来是省市区,我们一开始在 select-district 组件里定义的 initValue 的属性现在可以派上用场了:
    这里的$user->home_province是我自己的数据,请改成你自己的数据。

    <select-area @change="onDistrictChanged" :init-value="{{ json_encode([old('province', $user->home_province), old('city', $user->home_city), old('district', $user->home_county)]) }}" inline-template>
    

    7.做两个或多个三级联动模块

    要把模块复制一遍,起别的名称,纳入到app.js, 然后再把province,city,district重新起名,包括最初赋值的那个部分。别忘了重新执行一下npm run dev这个命令。把onDistrictChanged这个方法重新命名写一遍。

    相关文章

      网友评论

          本文标题:Laravel npm引入省市三级联动vue组件

          本文链接:https://www.haomeiwen.com/subject/jbkkoctx.html