• vue-day13----City页面数据渲染-难点:cityList数据结构分析、数据优化-存储到localStorage中、点击右侧边栏字母去到对应的title、better-scroll的使用、scrollTo()方法、better-scroll二次封装(父组件访问子组件内部的方法:this.$refs.ref属性值.方法)、better-scroll组件(BScroll)横向滚动、sass


    ### City页面数据渲染-难点:cityList数据结构分析

        ①api/index.js中添加city接口:
            cityList:{
                city:"/v3/city"
            }
        ②api下新建request.js:
            import http from "@utils/request.js";
            import api from "./index.js";
            export const cityApi=()=>{
                return http({
                    method:"get",
                    url:api.cityList.city
                })
            }
        ③将数据存在vuex中,所以在store/index.js中
        引入cityApi:
            import { cityApi } from "@api/request.js";
        state中定义:
            state: {
                hotCity: [],
                cityList: []
            }
        通过actions请求数据:
            actions: {
                async getCityList({ commit }) {
                    let data = await cityApi();
                    commit("mutationsCityList", data.data.cities);
                }
            }
        actions中触发mutations中mutationsCityList()方法:
            mutations: {
                mutationsCityList(state, cities) {
                    let hotCity = [], cityList = [];
                    // 热门城市
                    for (let i = 0; i < cities.length; i++) {
                        if (cities[i].isHot == 1) {
                            hotCity.push({ id: cities[i].id, nm: cities[i].nm });
                        }
                    }
                    // 城市列表
                    /*
                        分析数据结构:
                            [
                                {title:A,list:[{id:1,nm:"鞍山"},{id:2,nm:"安庆"}]},
                                {title:B,list:[{id:1,nm:"北京"},{id:2,nm:"亳州"}]},
                            ]
                    */
                    for (let i = 0; i < cities.length; i++) {
                        // initials-首字母
                        let initials = cities[i].py.slice(0, 1).toLocaleUpperCase();
                        if (isFirst(initials).flag) {// 如果首字母在cityList中存在,则往这个字母对应的title下的list中push一个对象:{id,nm}
                            cityList[isFirst(initials).index].list.push({ id: cities[i].id, nm: cities[i].nm });
                        } else {// 如果首字母在cityList中不存在,则将这个首字母作为title的值,push一个对象{title:A,list:[{id,nm}]}
                            cityList.push({ title: initials, list: [{ id: cities[i].id, nm: cities[i].nm }] });
                        }
                    }
                    function isFirst(initials) {
                        let index = -1, flag = false;
                        for (let i = 0; i < cityList.length; i++) {
                            if (cityList[i].title == initials) {
                                flag = true;
                                index = i;
                                break;
                            }
                        }
                        return { index, flag };
                    }
                    cityList.sort(function (a, b) {
                        return a.title.charCodeAt() - b.title.charCodeAt();
                    });
                    // 更改state中的hotCity、cityList
                    state.hotCity = hotCity;
                    state.cityList = cityList;
                    // 存储到localStorage中
                    localStorage.setItem("hotCity",JSON.stringify(state.hotCity));
                    localStorage.setItem("cityList",JSON.stringify(state.cityList));
                }
            }
        ③City页面created中执行请求函数,通过辅助函数拿到数据:
            import {mapActions,mapState} from "vuex";
            export default {
                name:"City",
                created() {
                    this.getCityList();
                },
                computed: {
                    ...mapState({
                        hotCity:state=>state.hotCity,
                        cityList:state=>state.cityList
                    })
                },
                methods: {
                    ...mapActions({
                        getCityList:"getCityList"
                    })
                },
            }



    ### 数据优化-存储到localStorage中

        ①设置好state.hotCity、state.cityList将其存储到localStorage中(store/index.js):
            localStorage.setItem("hotCity",JSON.stringify(state.hotCity));
            localStorage.setItem("cityList",JSON.stringify(state.cityList));
        ②在state中设置cityList和hotCity的时候,先判断localStorage中有没有(store/index.js):
            state: {
                cityList:localStorage.getItem("cityList")?JSON.parse(localStorage.getItem("cityList")):[],
                hotCity:localStorage.getItem("cityList")?JSON.parse(localStorage.getItem("hotCity")):[]
            }
        ③在City/index.vue中进行数据请求时先判断localStorage中有没有cityList或hotCity:
            created() {
                if(!localStorage.getItem("cityList")||!localStorage.getItem("hotCity")){
                    this.getCityList();
                }
            }

    ### 点击右侧边栏字母去到对应的title

        ①为每个li绑定tap事件(scrollToTitle(index)),将下标值传过去:
            <v-touch tag="li" v-for="(item,index) in cityList" :key="index" @tap="scrollToTitle(index)">{{item.title}}</v-touch>
        ②最外层盒子设置ref属性:
            <div class="city_body" ref="city_body">
        ③在所有的字母标题(.city_title_letter)中找到当前下标对应的字母标题,将offsetTop设置给city_body的scrollTop:
            methods: {
                scrollToTitle(index){
                    let title=this.$refs.city_list.querySelectorAll(".city_title_letter")[index];
                    let t=title.offsetTop;
                    this.$refs.city_body.scrollTop=t;
                }
            }

    ### better-scroll的使用

        ①安装:npm i better-scroll
        ②引入:import BS from "better-scroll";
        ③mounted中实例化:this.BS=new BS(this.$refs.city_body);

     注意:

            1、city_body这个盒子里面只能有一个盒子,并且city_body的高度小于它的子级盒子高度。
            2、如果使用了better-scroll,后代元素中的fixed定位都会失效。
            3、better-scroll会破坏点击事件,所以在实例的时候,配置项中加上 click:true,tap:true

    ### better-scroll的scrollTo()方法

        在使用better-scroll初始化city_body后,点击字母去到对应的字母title时,滚动有bug,通过scrollTo()解决。
     
        在scrollToTitle()函数中用 this.BS.scrollTo(0,-t,500); 替代原来的 this.$refs.city_body.scrollTop=t; :
            scrollToTitle(index){
                let title=this.$refs.city_list.querySelectorAll(".city_title_letter")[index];
                let t=title.offsetTop;
                // this.$refs.city_body.scrollTop=t;
                // 往下滚动是正值,往上滚动是负值,和数学里的y轴坐标相反
                this.BS.scrollTo(0,-t,500);
            }

    ### better-scroll二次封装(父组件访问子组件内部的方法:this.$refs.ref属性值.方法

        ①plugins下新建BetterScroll/index.vue:
            <template>
                <div class="wrapper" ref="wrapper">
                    <slot></slot>
                </div>
            </template>
            <script>
            import BScroll from "better-scroll";
            export default {
                name:"BScroll",
                mounted() {
                    this.BScroll=new BScroll(this.$refs.wrapper,{click:true,tap:true});
                },
                methods: {
                    scrollTo(l=0,t=0){
                        this.BScroll.scrollTo(l,t,500);
                    }
                },
            }
            </script>
            <style>
            .wrapper{
                height: 100%;
            }
            </style>
        ②src下新建common/components.js(用于注册所有的组件):
            import Vue from "vue";
            import BScroll from "@plugins/BetterScroll/index.vue";
            Vue.component(BScroll.name,BScroll);
        ③main.js中全局注册:
            import "./common/components.js";
        ④City页面实现边缘回弹效果:
            只需要用<BScroll><BScroll>标签将需要页面包裹,不需要引入better-scroll:
                <template>
                    <div class="city_body" ref="city_body">
                        <BScroll ref="BScroll">
                            <div>
                                <!-- 热门城市 -->
                                <div class="hot_city">
                                    <div class="hot_title">热门城市</div>
                                    <div class="hot_city_list">
                                        <div class="hot_city_name" v-for="item in hotCity" :key="item.id">{{item.nm}}</div>
                                    </div>
                                </div>
                                <!-- 城市列表 -->
                                <div class="city_list" ref="city_list">
                                    <div class="city_list_item" v-for="item in cityList" :key="item.index">
                                        <div class="city_title_letter">{{item.title}}</div>
                                        <div class="city_list_name">
                                            <div class="city_list_name_item" v-for="cityName in item.list" :key="cityName.id">{{cityName.nm}}</div>
                                        </div>
                                    </div>
                                </div>
                            </div>
                        </BScroll>
                        <!-- 城市列表下标 -->
                        <aside class="city_list_title">
                            <ul>
                                <v-touch tag="li" v-for="(item,index) in cityList" :key="index" @tap="scrollToTitle(index)">{{item.title}}</v-touch>
                            </ul>
                        </aside>
                    </div>
                </template>
        ⑤City页面实现点右击侧边栏滚动到对应title:
            (1)在<BScroll></BScroll>标签上添加ref属性:
                <BScroll ref="BScroll">
            (2)scrollToTitle()方法中使用 this.$refs.BScroll.scrollTo(0,-t); :
                scrollToTitle(index){
                    let title=this.$refs.city_list.querySelectorAll(".city_title_letter")[index];
                    let t=title.offsetTop;
                    // this.$refs.city_body.scrollTop=t;
                    // 往下滚动是正值,往上滚动是负值,和数学里的y轴坐标相反
                    // this.BS.scrollTo(0,-t,500);
                    this.$refs.BScroll.scrollTo(0,-t);
                }

    ### better-scroll组件(BScroll)横向滚动

        ①better-scroll配置项中设置scrollX:true,支持横向滚动:
            this.BScroll=new BScroll(this.$refs.wrapper,{
                click:true,
                tap:truescrollX: true
            });
        ②components/RecommendList/index.vue中用<BScroll></BScroll>标签将原来的内容包裹:
            <template>
                <BScroll>
                    <div class="recommend_list">
                        <div
                            class="recommend_list-item"
                            v-for="item in recommend"
                            :key="item.target_id"
                            :data-id="item.target_id"
                        >
                            <div>
                                <img v-lazy="item.image" />
                            </div>
                            <div class="goodsName">{{item.title}}</div>
                            <div class="price">
                                <span>¥{{item.vip_price}}/{{item.volume}}</span>
                                <span>+</span>
                            </div>
                        </div>
                    </div>
                </BScroll>
            </template>

    ### sass

        ①安装:npm i sass-loader node-sass -D
        ②style标签添加lang属性:
            <style lang="scss">
            $color:red;
            .classify{
                background: $color;
            }
            </style>
        注意:
            1、sass定义变量用$,less定义变量用@
            2、sass基于ruby,less基于JavaScript
            3、less比sass简单,less中可以直接写css语句
            4、sass通过服务端处理,less是通过客户端处理,sass的解析速度更快








  • 相关阅读:
    Apollo与ROS
    QT windeployqt
    自定义QGraphicsItem
    ROS与C++
    aptitude与apt-get
    解决tcp粘包问题
    网络中两台主机通信
    I/O多路复用之select、poll、epoll
    Nginx命令行控制
    C++11
  • 原文地址:https://www.cnblogs.com/wuqilang/p/12424181.html
Copyright © 2020-2023  润新知