vue this.$refs[this.letter] 报underfined

功能 通过点击右侧字母ABCD(alphabet.vue里的)等让 左侧ABCD(list.vue中的)的下的列表和左侧一一对应
$refs报错.PNG
city.vue

<template>
  <div>
    <city-header></city-header>
    <city-search></city-search>
    <city-list :cities="cities" :hot="hotCities" :letter="letter"></city-list>
    <city-alphabet
      :cities="cities"
      @change="handleLetterChange"
    ></city-alphabet>
  </div>
</template>
<script>
import axios from "axios";
import CityHeader from "./components/Header";
import CitySearch from "./components/Search";
import CityList from "./components/List";
import CityAlphabet from "./components/Alphabet";
export default {
  name: "City",
  data() {
    return {
      cities: {},
      hotCities: [],
      letter: ""
    };
  },
  components: {
    CityHeader,
    CitySearch,
    CityList,
    CityAlphabet
  },
  methods: {
    getCityInfo() {
      axios.get("/js/city.json").then(this.getCityInfoSucc);
    },
    getCityInfoSucc(res) {
      res = res.data;
      if (res.ret && res.data) {
        const data = res.data;
        this.cities = data.cities;
        this.hotCities = data.hotCities;
        // console.log(this.cities);
        // console.log(this.hotCities);
        // console.log(res);
      }
    },
    handleLetterChange(letter) {
      this.letter = letter;
    }
  },
  mounted() {
    this.getCityInfo();
  }
};
</script>

<style lang="stylus" scoped></style>

list.vue

<template>
  <div class="list" ref="wrapper">
    <div>
      <div class="area">
        <div class="title border-topbottom">当前城市</div>
        <div class="button-list">
          <div class="button-wraper">
            <div class="button">北京</div>
          </div>
        </div>
      </div>
      <div class="area">
        <div class="title border-topbottom">热门城市</div>
        <div class="button-list">
          <div class="button-wraper" v-for="item of hot" :key="item.id">
            <div class="button">{{ item.name }}</div>
          </div>
        </div>
      </div>
      <div class="area" v-for="(item, key) of cities" :key="key" :ref="key">
        <div class="title border-topbottom">{{ key }}</div>
        <div class="item-list" v-for="innerItem of item" :key="innerItem.id">
          <div class="item border-bottom">{{ innerItem.name }}</div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import Bscroll from "better-scroll";
export default {
  name: "CityList",
  props: {
    cities: Object,
    hot: Array,
    letter: String
  },
  mounted() {
    this.scroll = new Bscroll(this.$refs.wrapper);
  },
  watch: {
    letter() {
      if (this.letter) {
        console.log(this.letter); // 能正常輸出 this.letter和v-for循環的标签的key一样
        //const element = this.$refs["B"]; //輸出了一個div
        const element = this.$refs[this.letter]; //報錯 undefined 取不到div數組
        // this.scroll.scrollToElement(element);
        console.log(element);
      }
    }
  }
};
</script>

<style lang="stylus" scoped>
@import '~css/varibles.styl';

.border-topbottom {
  &:before {
    border-color: #cccccc;
  }

  &:after {
    border-color: #cccccc;
  }
}

.list {
  overflow: hidden;
  position: absolute;
  top: 1.58rem;
  left: 0;
  right: 0;
  bottom: 0;

  .border-bottom {
    &:before {
      border-color: #cccccc;
    }
  }

  .title {
    line-height: 0.54rem;
    background: #eee;
    height: 0.44rem;
    padding-left: 0.2rem;
    font-size: 0.26rem;
    // border-bottom .02rem solid ;
    margin-top: 0.1rem;
  }

  .button-list {
    overflow: hidden;
    padding: 0.1rem 0.6rem 0.1rem 0.1rem;

    .button-wraper {
      float: left;
      width: 33.3%;

      .button {
        text-align: center;
        border: solid 0.02rem #cccccc;
        margin: 0.1rem;
        padding: 0.1rem;
        border-radius: 0.06rem;
      }
    }
  }

  .item-list {
    .item {
      line-height: 0.76rem;
      padding-left: 0.2rem;
    }
  }
}
</style>

alpahbet.vue

<template>
  <div class="list">
    <div
      class="item"
      v-for="(item, key) of cities"
      :key="key"
      @click="handleLetterClick"
    >
      {{ key }}
    </div>
  </div>
</template>

<script>
export default {
  name: "CityAlpahbet",
  props: {
    cities: Object
  },
  methods: {
    handleLetterClick(e) {
      // console.log(e.target.innerHTML);
      this.$emit("change", e.target.innerHTML);
    }
  }
  // mounted() {
  //   this.scroll = new Bscroll(this.$refs.wrapper);
  // }
};
</script>

<style lang="stylus" scoped>
// @import '~css/varibles.styl';
.list {
  overflow hidden
  display: flex;
  flex-direction: column;
  justify-content: center;
  position: absolute;
  top: -2.2rem;
  right: 0;
  bottom: 0;
  width: 0.4rem;
  // background: red;
  // padding-top 1rem

  .item {
    line-height: 0.4rem;
    text-align: center;
    color: green;
  }
}
</style>
阅读 1.5k
1 个回答

alpahbet.vue中有问题。

handleLetterClick中$emit传递的参数为e.target.innerHTML,你以为是C,其实是'\nC\n'。

这是因为你在div中写这个key的时候留有换行符,所以你需要在template中把这个换行符去掉,或者使用e.target.innerText

最合理的就是在点击事件中把这个key当作参数传入。

推荐问题