兄弟组件通信及滚动逻辑

子组件(字母A/B/C)

Alphabet.vue

<template>
    <ul class="list">
        <!-- <li class="item" 
            v-for="(item,key) of cities"
            :key="key"
            @click="handleLetterClick"
            @touchstart="handleTouchStart"
            @touchmove="handleTouchMove"
            @touchend="handleTouchEnd"
        >{{key}}</li> -->
        <li class="item" 
            v-for="item of letters"
            :key="item"
            :ref="item"
            @click="handleLetterClick"
            @touchstart="handleTouchStart"
            @touchmove="handleTouchMove"
            @touchend="handleTouchEnd"
        >{{item}}</li>
    </ul>
</template>

<script>
// 引入better-scroll插件
import Bscroll from 'better-scroll'
export default{
    name:'CityAlphabet',
    props:{
        cities:Object
    },
    // 计算属性
    computed:{
        // 先定义一个数组。letters=['A','B','C']
        letters(){
            const letters = []
            for(let i in this.cities){
                letters.push(i)
            }
            return letters
            // ['A','B','C']
        }
    },
    data(){
        return {
            touchStart:false
        }
    },
    methods:{
        handleLetterClick(e){
            console.log(e.target.innerText);  // 打印点击的字母
            // 子组件传值给父组件。向外触发事件。父组件监听。
            this.$emit('change',e.target.innerText)
        },
        // 监听左边城市的滚动。
        handleTouchStart (){
            // 手指触摸
            this.touchStart=true
        },
        handleTouchMove (e){
            /*
                1.a到顶部的高度.
                2.当前滑动到哪的位置与顶部的高度。注意:要减去header的高度.
                3.算出两个值之间的差值。除以每个字母的高度。算出当前是第几个字母。
                4.获取到字母,触发自定义事件。传值给父级,父级再传值给兄弟组件。
                
            */
            const startY = this.$refs['A'][0].offsetTop;  // 1.a到顶部的高度
            // console.log(startY);
            const touchY = e.touches[0].clientY - 79;  // 2.当前滑动到哪的位置与顶部的高度。注意:要减去header的高度.
            // console.log(touchY);

            const index = Math.floor((touchY - startY)/20);  // 3.算出两个值之间的差值。除以每个字母的高度。算出当前是第几个字母。
            // console.log(index);
            if(index >= 0 && index < this.letters.length){
                this.$emit('change', this.letters[index]);
            }
        },
        handleTouchEnd (){
            // 结束滑动
            this.touchStatus = false;
        }
    }
}

</script>


<style lang="stylus" scoped>
    @import '~styles/varibles.styl'
    .list
        display:flex
        flex-direction:column
        justify-content:center
        position:absolute
        top:1.58rem
        right:0
        bottom:0
        width:.4rem
        .item
            line-height:.4rem
            text-align:center
            color:$bgColor
</style>

父组件

City.vue

<template>
    <div>
        <city-header></city-header>
        <city-search></city-search>
        <city-list 
            :hotCities="hotCities" 
            :cities="cities"
            :letter="letter"
        >
        </city-list>
        <city-alphabet 
            :cities="cities" 
            @change="handleLetterChange"
        >
        </city-alphabet>
    </div>
</template>


<script>
// ajax工具
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',
    // 组件
    components:{
        CityHeader,
        CitySearch,
        CityList,
        CityAlphabet
    },
    data(){
        return {
            // 热门城市
            hotCities:[],
            // 城市
            cities:{},
            letter:''
        }
    },
    // 函数
    methods:{
        getCityInfo(){
            axios.get('/api/city.json')
                .then(this.handleGetCityInfoSucc)
        },
        handleGetCityInfoSucc(res){
            console.log(res);
            res = res.data;
            if (res.ret && res.data){
                const data = res.data
                this.hotCities = data.hotCities
                this.cities = data.cities
            }
        },
        // 父组件监听子组件自定义事件。
        handleLetterChange(letter){
            console.log('父组件接收到了letter:',letter);  // 父组件接收到子组件接收到的数据。
            // 父组件再通过属性传递给另一个子组件。
            this.letter = letter
        }
    },
    //dom加载完成
    mounted (){
        this.getCityInfo()
    }
}    
</script>

<style lang="stylus" scopend>
    
</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-wrapper">
                        <div class="button">北京</div>
                    </div>
                </div>
            </div>
            <div class="area">
                <div class="title border-topbottom">热门城市</div>
                <div class="button-list">
                    <div class="button-wrapper" v-for="item of hotCities" :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">
                    <div 
                        class="item border-bottom"
                        v-for="innerItem of item"
                        :key="innerItem.id"
                    >{{innerItem.name}}</div>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
// 引入better-scroll插件
import Bscroll from 'better-scroll'
export default{
    name:'CityList',
    props:{
        hotCities:Array,
        cities:Object,
        letter: String
    },
    // dom挂载完毕之后执行.
    mounted(){
        // ref="wrapper" ref可以帮我们获取dom.
        this.scroll = new Bscroll(this.$refs.wrapper)
    },
    // 侦听器
    watch:{
        // 监听letter的变化。
        letter(){
            // console.log('兄弟组件收到了letter:',this.letter)
            if(this.letter){
                // 点击到哪个字母,div区域就显示哪一块内容。$refs[key]
                const element = this.$refs[this.letter][0];  // 注意:这是一个数组。不是一个元素。不能直接传给滚动对象。后面加一个0就好了。
                console.log(element);

                this.scroll.scrollToElement(element);  // 传的参数必须是dom元素。
            }
        }
    }
}

</script>


<style lang="stylus" scoped>
    .border-topbottom
        &:before
            border-color:#ccc
        &:after
            border-color:#ccc

    .border-bottom
        &:before
            border-color:#ccc

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

        .title
            line-height:.54rem
            background:#eee
            padding-left:.2rem
            color:#666
            font-size:.26rem

        .button-list
            overflow:hidden
            padding:.1rem .6rem .1rem .1rem

            .button-wrapper
                float:left
                width:33.33%
                .button
                    margin:.1rem
                    padding:.1rem 0
                    text-align:center
                    border:.02rem solid #ccc
                    border-radius:.06rem
        .item-list
            .item
                line-height:.76rem
                padding-left:.2rem

</style>

猜你喜欢

转载自www.cnblogs.com/c-x-m/p/10047014.html