@SM_ST

Как убрать зацикливание при вводе номера телефона во Vue?

Не могу понять, где ошибся - если я ввожу вот такой номер 37533 то идет зависание компонента

[Vue warn]: You may have an infinite update loop in a component render function.

found in

---> <TheMask>
       <PhoneInput> at src/components/phone-input.vue
           <auth/signin.vue> at src/pages/auth/signin.vue


компонент для ввода телефона

<template>
  <div class="phone-flag__wrapper">
    <app-phone-country-flag v-if="country" :country="country" class="phone-flag__icon"/>
    +
    <the-mask
        ref="phoneMask"
        v-model="innerValue"
        :class="classInput"
        :mask="mask"
        :name="name"
        :tokens="plusTokens"
        class="phone-flag__input"
        type="tel"
        @input="onInput"
    />
  </div>
</template>

<script>
import PhoneCountry from "./phone-country";

import {parsePhoneNumberFromString} from "libphonenumber-js";

import visitorInfo from "visitor-info";

import {findFirstCountryByCode, getMaskToLibPhoneNumber} from "../phone-countries";

export default {
  components: {PhoneCountry},
  props: {
    value: {
      type: String,
    },
    name: {},
    classInput: {
      type: String,
      default: '',
    },
    autoDetectCountry: {
      type: Boolean,
      default: false
    },
  },
  data() {
    return {
      innerValue: this.value.replace('+', ''),
      countryCode: "",
      mask: "*############",
      defaultMask: "*############",
      country: "",
      isValid: false,
      plusTokens: {
        "#": {
          pattern: /\d/
        },
        "*": {
          pattern: /\d|\+/
        }
      }
    };
  },
  computed: {
    currentNumber: function () {
      const plus = /^\+/.test(this.innerValue) || !this.innerValue ? "" : "+";

      const filteredNumberArr = this.innerValue
          ? this.innerValue.match(/[\d+]/g)
          : null;

      const filteredNumber = filteredNumberArr
          ? filteredNumberArr.join("")
          : "";

      return this.mask === this.defaultMask
          ? `${plus}${filteredNumber}`
          : filteredNumber;
    }
  },
  methods: {
    onInput: function (value) {
      let filteredValue = value.match(/[\d+]/g);

      this.innerValue = filteredValue ? filteredValue.join("") : "";

      this.updateMaskData();

      this.$nextTick(function () {
        setTimeout(this.setFocusToEnd.bind(this), 0);

        this.$emit("input", `+${this.countryCode}${value}`);
      });
    },

    setFocusToEnd: function () {
      const length = this.$refs.phoneMask.$el.value.length;

      this.$refs.phoneMask.$el.focus();

      this.$refs.phoneMask.$el.setSelectionRange(length, length);
    },

    updateMaskData: function () {
      let {
        visitorCountry,
        innerValue,
        countryCode,
        defaultMask,
        autoDetectCountry,
      } = this;

      let phoneInfo = parsePhoneNumberFromString(this.currentNumber);

      if (autoDetectCountry && visitorCountry && !innerValue && !phoneInfo) {
        phoneInfo = {country: visitorCountry};
      }

      if (!phoneInfo && this.currentNumber.length > 2) {
        phoneInfo = {country: findFirstCountryByCode(this.currentNumber)};
      }

      const computedMask = getMaskToLibPhoneNumber(phoneInfo);

      const computedCountry = phoneInfo && phoneInfo.country ? phoneInfo.country.toLowerCase() : "";

      if (autoDetectCountry && visitorCountry) {
        if (!innerValue && computedMask) this.innerValue = computedMask.countryCode;

        this.visitorCountry = null;
      }

      if (computedMask && computedMask.mask) {
        this.mask = computedMask.mask;
        this.country = computedCountry;
        this.countryCode = computedMask.countryCode;
        this.isValid = !!phoneInfo && !!phoneInfo.isValid && phoneInfo.isValid();
      } else if (countryCode.length > this.currentNumber.length) {
        this.mask = defaultMask;
        this.country = "";
        this.countryCode = "";
        this.isValid = false;
      }
    }
  },
  beforeMount() {
    if (this.autoDetectCountry) {
      const visitorCountryInfo = visitorInfo();

      this.visitorCountry =
          visitorCountryInfo && visitorCountryInfo.country
              ? visitorCountryInfo.country.alpha2
              : "";
    }

    this.updateMaskData();
  },
}
</script>

<style lang="scss" scoped>
.phone {
  &-flag {
    &__wrapper {
      display: flex;
      align-items: center;
      font-size: 1rem;
      line-height: 1.5rem;
    }

    &__input {
      flex: 1;
    }

    &__icon {
      margin: -20px -15px -18px -20px;
      transform: scale(0.3);
    }
  }
}
</style>


и файл с масками номеров

export const countries = [
    ["Bahrain (‫البحرين‬‎)", "bh", "973", "...-....-...."],
    ["Bangladesh (বাংলাদেশ)", "bd", "880", "...-..-...-..."],
    ["Barbados", "bb", "1246", ". ... ...-...."],
    ["Belarus (Беларусь)", "by", "375", "... .. ...-..-.."],
];

const addCountryCodeToMask = (mask, code) => {
    const codeLength = code.length;
    let temporaryMask = mask;

    for (let i = 0; i < codeLength; i++)
        temporaryMask = temporaryMask.replace(/#/, code[i]);

    return temporaryMask;
};


export const findFirstCountryByCode = code => {
    let filteredCode = code.match(/\d/g).join("");
    const filteredCountries = countries.filter(
        countryArr => countryArr[2] === filteredCode && countryArr[3]
    );

    if (!filteredCountries[0]) return ""

    let country = filteredCountries[0][1]

    return country.toUpperCase();
};


export const findFirstCountryByAlpha2 = alpha2 => {
    if (!alpha2) return null;

    const filteredCountries = countries.filter(
        countryArr => countryArr[1] === alpha2
    );

    if (!filteredCountries[0]) return null

    return {country: filteredCountries[0][1], code: filteredCountries[0][2]};
};

export const getMaskToLibPhoneNumber = libPhoneNumberObj => {
    const country = libPhoneNumberObj ? libPhoneNumberObj.country : "";

    if (!country) return null;

    const filteredCountries = countries.filter(
        countryArr => countryArr[1].toUpperCase() === country.toUpperCase()
    );

    if (!filteredCountries[0]) return null;

    let mask = filteredCountries[0][3]
        ? filteredCountries[0][3].replace(/\./g, "#")
        : null;

    return {
        mask: addCountryCodeToMask(mask, filteredCountries[0][2]),
        countryCode: `${filteredCountries[0][2]}`
    };
};
  • Вопрос задан
  • 265 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы