vue之组件封装(1)

betterscroll滚动

<template>
    <div ref="wrapper">
        <slot></slot>
    </div>
</template>

<script>
import BScroll from "better-scroll";

export default {
    name: "Scroll",
    props: {
        probeType: {
            type: Number,
            default: 1,
        },
        data: {
            type: Array,
            default: () => {
                return [];
            },
        },
        pullUpLoad: {
            type: Boolean,
            default: false,
        },
    },
    data() {
        return {
            scroll: {},
        };
    },
    mounted() {
        setTimeout(this.__initScroll, 20);
    },
    methods: {
        __initScroll() {
            // 1.初始化BScroll对象
            if (!this.$refs.wrapper) return;
            this.scroll = new BScroll(this.$refs.wrapper, {
                probeType: this.probeType,
                click: true,
                pullUpLoad: this.pullUpLoad,
            });

            // 2.将监听事件回调
            this.scroll.on("scroll", (pos) => {
                this.$emit("scroll", pos);
            });

            // 3.监听上拉到底部
            this.scroll.on("pullingUp", () => {
                console.log("上拉加载");
                this.$emit("pullingUp");
            });
        },
        refresh() {
            this.scroll && this.scroll.refresh && this.scroll.refresh();
        },
        finishPullUp() {
            this.scroll &&
                this.scroll.finishPullUp &&
                this.scroll.finishPullUp();
        },
        scrollTo(x, y, time) {
            this.scroll &&
                this.scroll.scrollTo &&
                this.scroll.scrollTo(x, y, time);
        },
    },
    watch: {
        data() {
            setTimeout(this.refresh, 20);
        },
    },
};
</script>

<style scoped>

</style>

使用

<!--codewhy的代码演示部分-->
<template>
    <div id="home">
        <nav-bar class="nav-bar"><div slot="center">购物街</div></nav-bar>
        <tab-control
            v-show="isTabFixed"
            class="fixed"
            @itemClick="tabClick"
            :titles="['流行', '新款', '精选']"
        ></tab-control>
        <scroll
            class="content"
            ref="scroll"
            @scroll="contentScroll"
            @pullingUp="loadMore"
            :data="showGoodsList"
            :pull-up-load="true"
            //这里加:代表传递的是数字 不加:传递的是字符串
            :probe-type="3"
        >
            <div>
                <home-swiper :banners="banners" ref="hSwiper"></home-swiper>
                <feature-view :features="recommends"></feature-view>
                <recommend-view></recommend-view>
                <tab-control
                    @itemClick="tabClick"
                    :titles="['流行', '新款', '精选']"
                    ref="tabControl"
                ></tab-control>
                <goods-list :goods-list="showGoodsList"></goods-list>
            </div>
        </scroll>
        <back-top @backTop="backTop" class="back-top" v-show="showBackTop">
            <img src="~assets/img/common/top.png" alt="" />
        </back-top>
    </div>
</template>

<script>
import NavBar from "common/navbar/NavBar";
import Scroll from "common/scroll/Scroll";
import TabControl from "content/tabControl/TabControl";
import BackTop from "content/backTop/BackTop";
import HomeSwiper from "./childComps/HomeSwiper";
import FeatureView from "./childComps/FeatureView";
import RecommendView from "./childComps/RecommendView";
import GoodsList from "./childComps/GoodsList";
import { getHomeMultidata, getHomeData, RECOMMEND, BANNER } from "network/home";
import { NEW, POP, SELL, BACKTOP_DISTANCE } from "@/common/const";

export default {
    name: "Home",
    components: {
        NavBar,
        Scroll,
        TabControl,
        BackTop,
        HomeSwiper,
        FeatureView,
        RecommendView,
        GoodsList,
    },
    data() {
        return {
            banners: [],
            recommends: [],
            goodsList: {
                pop: { page: 1, list: [] },
                new: { page: 1, list: [] },
                sell: { page: 1, list: [] },
            },
            currentType: POP,
            isTabFixed: false,
            tabOffsetTop: 0,
            showBackTop: false,
        };
    },
    computed: {
        showGoodsList() {
            return this.goodsList[this.currentType].list;
        },
    },
    created() {
        console.log("创建Home");
        // 1.请求多个数据
        this.getMultiData();

        // 2.请求商品数据
        this.getHomeProducts(POP);
        this.getHomeProducts(NEW);
        this.getHomeProducts(SELL);
    },
    activated: function () {
        this.$refs.hSwiper.startTimer();
    },
    deactivated: function () {
        this.$refs.hSwiper.stopTimer();
    },
    updated() {
        // this.tabOffsetTop = this.$refs.tabControl.$el.offsetTop
        // console.log(this.tabOffsetTop);
    },
    methods: {
        tabClick(index) {
            switch (index) {
                case 0:
                    this.currentType = POP;
                    break;
                case 1:
                    this.currentType = NEW;
                    break;
                case 2:
                    this.currentType = SELL;
                    break;
            }
        },
        contentScroll(position) {
            // 1.决定tabFixed是否显示
            this.isTabFixed = position.y < -this.tabOffsetTop;

            // 2.决定backTop是否显示
            this.showBackTop = position.y < -BACKTOP_DISTANCE;
        },
        loadMore() {
            this.getHomeProducts(this.currentType);
        },
        backTop() {
            this.$refs.scroll.scrollTo(0, 0, 300);
        },
        /**
         * 网络请求相关方法
         */
        getMultiData() {
            getHomeMultidata().then((res) => {
                this.banners = res.data[BANNER].list;
                this.recommends = res.data[RECOMMEND].list;
                // 下次更新DOM时,获取新的tabOffsetTop值(不保险,可以在updated钩子中获取)
                this.$nextTick(() => {
                    this.tabOffsetTop = this.$refs.tabControl.$el.offsetTop;
                });
            });
        },
        getHomeProducts(type) {
            getHomeData(type, this.goodsList[type].page).then((res) => {
                const goodsList = res.data.list;
                this.goodsList[type].list.push(...goodsList);
                this.goodsList[type].page += 1;

                this.$refs.scroll.finishPullUp();
            });
        },
    },
};
</script>

<style scoped>
#home {
    /*position: relative;*/
    height: 100vh;
}
.nav-bar {
    background-color: var(--color-tint);
    font-weight: 700;
    color: #fff;
}
.content {
    position: absolute;
    top: 44px;
    bottom: 49px;
    left: 0;
    right: 0;
}
.fixed {
    position: fixed;
    top: 44px;
    left: 0;
    right: 0;
}
.back-top {
    position: fixed;
    right: 10px;
    bottom: 60px;
}
</style>

vue-scroller封装

// 使用vue的混入方式 
import {initData} from '@/api/baseData'

export default {
    data() {
        return {
            loading: false,
            data: [],
            page: 0,
            limit: 10,
            total: 0,
            url: '',
            params: {},
            pageInfo: {},
            time: 170,
            noDate: false,
            hasAlive:false,
        }
    },
    mounted() {
        this.top = 10
        this.bottom = 20
    },
    methods: {
        async init(done) {
            this.hasAlive = true;  //keepalive组件内是否已经调用过init标识
            if (!await this.beforeInit()) {
                return
            }
            if(this.loading){
                this.$refs.scroller.finishPullToRefresh();
                return
            }

            return new Promise((resolve, reject) => {

                this.loading = true;
                initData(this.url, this.params).then(res => {
                    this.loading = false;
                    this.$refs.scroller.finishPullToRefresh();
                    done()
                    this.total = Number(res.data.total)
                    if ((this.page - 1) * this.limit >= this.total) {
                        this.noDate = true;
                    } else {
                        this.noDate = false
                    }
                    if (this.noDate) {
                        this.$refs.scroller.finishInfinite(true);
                    }
                    // 判断是下拉刷新还是上拉加载(这一步也是比较巧妙的,当然也很好理解)
                    if (this.page <= 1) {
                        this.data = res.data.records;
                    } else {
                        this.data = this.data.concat(res.data.records)
                        console.log(this.data)
                    }
                }).catch(err => {
                    this.noDate = true;  //防止死循环
                    this.loading = false;
                    done();
                    reject(err)
                })
            })
        },

        beforeInit() {
            return true
        },

        loadNewData(done) {
            this.page = 1;//重置页数刷新每次页数都是第一页
            this.noDate = false;//重置数据判断
            setTimeout(function () {
                this.init(done)
            }.bind(this), 200)
        },

        loadMore(done) {
            setTimeout(() => {
                if (this.noDate) {
                    this.$refs.scroller.finishInfinite(true);
                } else {
                    this.page++;//下拉一次页数+1
                    this.init(done);
                }
            }, 200);
        },

        // 预防删除第二页最后一条数据时,或者多选删除第二页的数据时,页码错误导致请求无数据
        dleChangePage(size) {
            if (size === undefined) {
                size = 1
            }
            if (this.data.length === size && this.page !== 1) {
                this.page = this.page - 1
            }
        },
        //查询
        handleQuery() {
            this.$refs.scroller.triggerPullToRefresh()
        }
    }
}

使用方法:

<template>
    <div class="flex1 posi-rel pb-250 yet-adv" v-if="flag">
        <scroller ref="scroller" :on-refresh="loadNewData" :on-infinite="loadMore" >
            <div class="advert-item click w702 bg-fff"  v-for="(item,idx) in data" :key="idx" @click="gotoAdvDetail(item.siteId)">
                <div class="adv-left">
                    <div class="fs-30 color-000 flex-center">
                        <span class="label fs-24" 
                            :class="{'label' : item.gradeInfo.gradeName=='一级屏','label2' : item.gradeInfo.gradeName=='二级屏','label3' : item.gradeInfo.gradeName=='三级屏','label4' : item.gradeInfo.gradeName=='四级屏'}"
                            >{{item.gradeInfo.gradeName}}
                        </span>
                        <span class="adv-title font-bold">{{item.siteName}}</span> 
                    </div>
                    <div class="flex-center mt-15">
                        <div class="tag fs-24">{{item.businessName}}</div>
                        <div class="line"></div>
                        <div v-for="(item2,idx2) in item.deviceProp" :key="idx2" class="flex-center  border-none">
                            <div class="tag fs-24">{{item2.value}}</div>
                            <div class="line-right"></div>
                        </div>
                    </div>
                    <div class="fs-24 color-333 mt-10">{{item.detailedAddress}}</div>
                    <div class="mt-24"><span class="coin fs-28">{{item.price}}/</span><span class="qty fs-20 ml-24">日均曝光量{{item.dailyExposure}}</span></div>
                </div>
                <div class="adv-right">
                    <div class="adv-img">
                        <template v-if="item.picViewList[0]">
                            <img :src="item.picViewList[0].fileUrlView" alt="">
                        </template>
                    </div>
                    <div class="dist fs-20">{{item.distance}}</div>
                </div>
            </div>
        </scroller>
    </div>
</template>

<script>
import backTitleBar from "@/components/titleBar/backTitleBar";
import initData from "@/mixins/initData";
import { advAlreadyEnter, advWaitEnter } from "@/api/advMine";

export default {
    name:'yetAdv',
    mixins:[initData],
    data() {
        return {
            yetadvList:[],
            flag:false
        }
    },
    methods: {
        beforeInit() {
            this.params = { page : this.page, limit: this.limit};
            this.url = 'backstage/udianAdvertSiteInfo/xxx';
            this.query = {
                flag:1
            }
            for (var key in this.query){
                if(this.query[key]){
                    this.params[key] = this.query[key]
                }
            }
            return true  
        },
        async getYetAdvData(){
            let params = {
                flag:1
            }
            let res = await advAlreadyEnter(params)
            this.yetadvList = res.data.records
            this.flag = true
            console.log(res)
            this.$emit("yetAdvData", this.yetadvList)
        },
        gotoAdvDetail(value){
            console.log(value)
            // this.$goRouter('advertDetail',{siteId : value})
        }
    },
    created() {
        this.getYetAdvData()
    },
    computed: {
        yetadv(){
            return this.yetadvList.length == 0
        },
    },
};
</script>
<style scoped lang="scss">
.yet-adv{
    height:80vh;
    // padding-bottom: 1.3rem;
}
.page-state{
    position: relative;
    // top: 0.88rem;
}
.advert-list{
    background: #f5f5f5;
    // padding-top: 2rem;
    padding-bottom: 2rem;
    // overflow: auto;
}
// 这部分是已入驻列表
.advert-item{
    height: 2.43rem;
    padding: 0.26rem 0.24rem 0;
    margin-left: 0.24rem;
    margin-bottom: 0.18rem;
    display: flex;
    justify-content: space-between;
    border-radius: 0.18rem;
    &:nth-child(2){
        margin-top: 0.18rem;
    }
    .label{
        width: 0.8rem;
        height: .34rem;
        line-height: 0.34rem;
        text-align: center;
        display: inline-block;
        background: linear-gradient(90deg, #FECB00 0%, #FEBA00 100%);
        border-radius: .08rem;
        font-size: .2rem;
        color: #fff;
    }
    .label2{
        background: #C3D8E6;
        color: #fff;
    }
    .label3{
        background: #E0C19D;
        color: #fff;
    }
    .label4{
        background:#F5F5F5;
        color: #333333;
    }
    .adv-title{
        margin-left: 0.18rem;
        width: 3.5rem;
        display: inline-block;
        overflow: hidden;
        text-overflow:ellipsis;
        white-space: nowrap;
    }
    .tag{
        color: #8C8C8C;
    }
    .line{
        height: 0.19rem;
        background: #8C8C8C;
        margin: 0 0.23rem;
        position: relative;
        &::after{
            content: '';
            display: block;
            position: absolute;
            top: 0;
            bottom: 0;
            right: 0;
            -webkit-transform: scale(0.5, 1);
            transform: scale(0.5, 1);
            border-right: 1px solid  #8C8C8C;
		}
        &:last-child::after{
            border: 0;
        }
    }
    .coin{
        color: $main-color;
    }
    .adv-img{
        width: 1.6rem;
        height: 1.6rem;
        border-radius: 0.18rem;
        img{
            width: 100%;
            height: 100%;
        }      
    }
    .dist{ 
        color:#8C8C8C;
        margin-top: 0.03rem;
        text-align: right;
    }      
}
</style>

发送短信验证码

<template>
    <div class="btn-code click" :class="{'disable': isGet}" @click="getCode">{{codeName}}</div>
</template>

<script>
    // import { getCode } from "@/api/user";
    import { getCode } from "@/api/advMine";
    export default {
        name: "msgCode",
        props:{
            mobileno:{
                type:String,
                default:''
            }
        },
        data(){
            return {
                codeName: '获取验证码',
                isGet: false,
                timer: null,
                num: "-1",
            }
        },
        methods:{
            getCode() {
                if (this.isGet) {
                    return;
                }
                if (!this.mobileno) {
                    this.$toast("请输入手机号码");
                    return;
                } else {
                    if (!this.mobileno.match(/^1\d{10}$/)) {
                        this.$toast("请输入正确的手机号码");
                        return;
                    }
                }
                this.setTimer();
                getCode(this.mobileno, "inAgent").then(res => {
                    this.$toast("短信发送成功,请注意查收");
                    this.setTimer();
                });
            },
            setTimer() {
                let _this = this;
                if (this.num < 0) {
                    this.isGet = true;
                    this.num = 60;
                    this.codeName = "重新获取(" + this.num + "s)";
                }
                if (this.num > 0) {
                    this.timer = setInterval(function() {
                        _this.num -= 1;
                        if (_this.num < 0) {
                            clearInterval(_this.timer);
                            _this.isGet = false;
                            _this.num = -1;
                            _this.codeName = "重新获取";
                        } else {
                            _this.codeName =  "重新获取(" + _this.num + "s)";
                        }
                    }, 1000);
                }
            },
        }
    }
</script>

<style scoped lang="scss">
    .btn-code{
        width: 2rem;
        height: .64rem;
        background: linear-gradient(90deg, #FECB00 0%, #FEBA00 100%);
        text-align: center;
        line-height: .64rem;
        color: #fff;
        font-size: .24rem;
        border-radius: .32rem;
    }
    .disable{
        background: #ccc;
    }
</style>

		// 没封装时的代码
 		// async getCodeInfo(){
        //     if(this.getCode){
        //         this.numberCode = 60
        //     }
        //     this.getCode = false
        //     this.timer()
        //     // 发送请求获取验证码
        //     let params = {
        //         mobile: this.contactInformation.userPhone,
        //         tmplType: 'inAgent',
        //     }
        //     let res = await applyAdvMsg(params)
        //     // console.log(res)
        // },
        //发送手机验证码倒计时
        // timer() {
        //     if (this.numberCode > 0) {
        //         this.numberCode--;
        //         if(this.numberCode < 10 && this.numberCode > 0 ){
        //             this.numberCode = "0" +this.numberCode
        //         }
        //         setTimeout(this.timer, 1000);
        //     } else{
        //         this.numberCode = 0;
        //         this.codetxt = "发送验证码";
        //         this.getCode = true
        //     }
        // },

在这里插入图片描述

地址弹窗的封装

<template>
    <div class="pick-area">
        <div class="address-title color-333 fs-28 mt-20">联系地址</div>
        <!-- 进度条 -->
        <div class="pd-030 mt-40" v-show="isSelectCity">
            <div class="fs-28 color-000" @click="selpro()"><span class="mr-24 circle"></span>{{prov}}</div>
            <div class="shu-line"></div>
            <div class="fs-28 color-000" @click="selcit()"><span class="mr-24" :class="[showcountry ? 'circle' : 'circle-hollow']"></span>{{city}}</div>
            <div class="shu-line" v-show="showcountry"></div>
            <div class="fs-28 color-000" @click="selcou()" v-show="showcountry"><span class="mr-24 circle-hollow" :class="[showcountry ? 'circle' : 'circle-hollow']"></span>{{country}}</div>
            <div class="heng-line"></div>
        </div>
        <!-- 定位 -->
        <div class="current-address pd-030 mt-40" v-show="showlocator" @click="getAddress()">
            <div class="fs-28 color-000">当前定位</div>  
            <div class="address-detail pd-040 text-el mt-24 flex-center">
                <span class="iconfont alifont iconzu275 fs-24 mr-20" style="color:#fecb00;"></span>
                <!-- <div v-if="true">{{location}}</div> -->
                <div class="fs-28 color-000" v-if="locationProvince == ''&& !errFlag">{{location}}</div>
                <div v-if="locationProvince !== ''&& !errFlag">
                    <span class="fs-28 color-000">{{locationProvince}}</span>
                    <span class="fs-28 color-000 mg-010">{{locationCity}}</span>
                    <span class="fs-28 color-000">{{locationCountry}}</span>
                </div>
                <div class="fs-28 color-000" v-show="errFlag">{{errorLocation}}</div>
            </div>
        </div>
        <!-- 热门城市 -->
        <div class="hot-city pd-030 mt-40" v-show="showhotcity">
            <div class="fs-28 color-8C8 mb-28">热门省份</div>
            <div class="hot-city-box">
                <div 
                    class="hot-city-item fs-28 color-000" 
                    v-for="(item,idx) in hotPro" :key="idx" 
                    @click="selecthotcity(item.codename)"
                >{{item.codename}}</div>
                <!-- <div class="hot-city-item fs-28 color-000">北京北京北京</div>
                <div class="hot-city-item fs-28 color-000">北京北</div> -->
            </div>
        </div>

        <div class="wrapper">
            <div class="select-city-area mt-10 pd-030" v-show="showprovinceList">
                <div class="fs-28 color-8C8">选择省份/地区</div>
                <div class="mt-25">
                    <div class="mb-48" v-for="(item,idx) in provinceList" :key="idx" @click="selectprovince(item.areaname)">
                        <!-- <span class="color-8C8 fs-28 mr-27">A</span> -->
                        <span class="color-000 fs-28">{{item.areaname}}</span>
                    </div>
                </div>
            </div>
            <div class="select-city-area mt-10 pd-030" v-show="showcityList">
                <div class="fs-28 color-8C8">选择城市</div>
                <div class="mt-25">
                    <div class="mb-48" v-for="(item,idx) in cityList" :key="idx" @click="selectcity(item.areaname)">
                        <!-- <span class="color-8C8 fs-28 mr-27">A</span> -->
                        <span class="color-000 fs-28">{{item.areaname}}</span>
                    </div>
                </div>
            </div>
            <div class="select-city-area mt-10 pd-030" v-show="showcountryList" >
                <div class="fs-28 color-8C8">选择区/</div>
                <div class="mt-25">
                    <div class="mb-48" v-for="(item,idx) in countryList" :key="idx" @click="selectcountry(item.areaname)">
                        <!-- <span class="color-8C8 fs-28 mr-27">A</span> -->
                        <span class="color-000 fs-28">{{item.areaname}}</span>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script>
import {getArea, getHotProvince} from "@/api/advMine"

export default {
    name: "pickAreaSelect",
    data() {
        return {
            popupShow: false,
            // 显示进度条
            showlocator:true,
            // 显示进度条中区县
            showcountry:false,
            // 显示热门城市
            showhotcity:true,
            hotPro:[],
            flag: 1,
            prov:'',
            city:'请选择城市',
            country:' 请选择区/县',
            provID:'',
            cityID:'',
            countryID:'',
            provinceList: [],
            cityList: [],
            countryList: [],
            // 显示省市区列表
            isSelectCity:false,
            showprovinceList:true,
            showcityList:false,
            showcountryList:false,
            // 定位的
            location: '定位中...',
            locationProvince:'',
            locationCity:'',
            locationCountry:'',
            errFlag: false,
            errorLocation:'',
        };
    },
    created() {
        // 获取用户定位
        this.getLocation();
        // 调用热门城市
        this.getHotPro("hotProvince")
        // 调用省列表
        this.getAreaList("-1", "provinceList");
    },
    methods: {
        // 进度条
        selpro(){
            console.log(1)
            this.showhotcity = false
            this.showprovinceList = true
            this.showcityList = false
            this.showcountryList = false
            this.city = '请选择城市'
            this.showcountry = false
        },
        selcit(){
            console.log(2)
            this.showprovinceList = false
            this.showcityList = true
            this.showcountryList = false
            this.showcountry = true
            this.country = ' 请选择区/县'
        },
        selcou(){
            this.showprovinceList = false
            this.showcityList = false
            this.showcountryList = true
        },
        // 列表选择
        selectprovince(value){
            this.isSelectCity = true
            this.showhotcity = false
            this.showlocator = false
            this.showprovinceList = false
            this.showcityList = true
            this.showcountryList = false
            console.log(value)
            let _this = this
            this.provinceList.forEach((item, index)=>{
                if(item.areaname == value){
                    this.prov = item.areaname
                    this.provID = item.areacode
                    this.getAreaList(item.areacode, "cityList");
                }
            })
        },
        selectcity(value){
            this.isSelectCity = true
            this.showhotcity = false
            this.showlocator = false
            this.showprovinceList = false
            this.showcityList = false
            this.showcountryList = true
            this.showcountry = true
            let _this = this
            this.cityList.forEach((item, index)=>{
                if(item.areaname == value){
                    this.city = item.areaname
                    this.cityID= item.areacode
                    this.getAreaList(item.areacode, "countryList");
                }
            })
        },
        selectcountry(value){
            this.isSelectCity = true
            this.showhotcity = false
            this.showlocator = false
            this.showprovinceList = false
            this.showcityList = false
            this.showcountryList = true
            let _this = this
            this.countryList.forEach((item, index)=>{
                if(item.areaname == value){
                    this.country = item.areaname
                    this.countryID= item.areacode
                }
            })
            // 取消弹框
            let data= {
                flag:false,
                prov:this.prov,
                city:this.city,
                country:this.country,
                provID:this.provID,
                cityID: this.cityID,
                countryID:this.countryID

            }
            this.$emit("cancelPopup", data);
        },
        // 选择热门城市
        selecthotcity(value){
            console.log(value)
            this.isSelectCity = true
            this.prov = value
            this.hotPro.forEach(item=>{
                if(item.codename == value){
                    this.getAreaList(item.code, "cityList");
                    this.showprovinceList = false
                    this.showcityList = true
                }
            })
            if(this.flag == 0){
                this.showlocator = true
                this.showhotcity = true
                this.flag = 1
            }else{
                this.showlocator = false
                this.showhotcity = false
                this.flag = 0
            }
        },
        getHotPro(hotProvince){
            let params = {
                codetype: "hotProvince",
            }
            getHotProvince(params).then(res=>{
                this.hotPro = res.data.records
                console.log(this.hotPro)
            })
        },
        getAreaList(pcode, name) {
            let params = {
                pcode: pcode || "-1",
            };
            getArea(params).then(res=>{
                if(name == 'provinceList'){
                    this[name] = res.data;
                    // this.getAreaList(res.data[0].areacode,'cityList');
                }else if(name == 'cityList'){
                    this[name] = res.data;
                    // this.getAreaList(res.data[0].areacode,'countryList');
                }else if(name == 'countryList'){
                    this[name] = res.data;
                    // this.getAreaList(res.data[0].areacode,'countryList');
                }
            })
        },
        // 获取当前位置
        getLocation() {
            const _this = this;
            _this.$toast("正在定位中...")
            AMap.plugin('AMap.Geolocation', function () {
                var geolocation = new AMap.Geolocation({
                    // 是否使用高精度定位,默认:true
                    enableHighAccuracy: true,
                    // 设置定位超时时间,默认:无穷大
                    timeout: 10000
                });
    
                geolocation.getCurrentPosition();
                AMap.event.addListener(geolocation, 'complete', onComplete);
                AMap.event.addListener(geolocation, 'error', onError);
    
                function onComplete (value) {
                    // value是具体的定位信息
                    console.log('定位成功信息:', value);
                    console.log('定位成功信息:', value.addressComponent.province);
                    console.log('定位成功信息:', value.addressComponent.city);
                    console.log('定位成功信息:', value.addressComponent.district);
                    _this.address = value.addressComponent.city;
                    _this.locationProvince = value.addressComponent.province
                    _this.locationCity = value.addressComponent.city
                    _this.locationCountry = value.addressComponent.district
                    // 取消弹框
                    let data = {
                        flag:false,
                        prov:_this.locationProvince,
                        city: _this.locationCity,
                        country:_this.locationCountry,
                        provID:'',
                        cityID: '',
                        countryID:''
                    }
                    _this.$emit("cancelPopup", data);
                }
    
                function onError (value) {
                    // 定位出错
                    console.log('定位失败错误:', value);
                    // 调用IP定位
                    // _this.getLngLatLocation();
                    _this.errFlag = true
                    _this.errorLocation = "定位失败,请手动选择地址"
                }
            });
        },
        // 通过IP获取当前位置
        getLngLatLocation () {
            AMap.plugin('AMap.CitySearch', function () {
                var citySearch = new AMap.CitySearch();
                citySearch.getLocalCity(function (status, result) {
                    if (status === 'complete' && result.info === 'OK') {
                        // 查询成功,result即为当前所在城市信息
                        console.log('通过ip获取当前城市:', result);
                        // 逆向地理编码
                        AMap.plugin('AMap.Geocoder', function () {
                            var geocoder = new AMap.Geocoder({
                              // city 指定进行编码查询的城市,支持传入城市名、adcode 和 citycode
                              city: result.adcode
                            });

                            var lnglat = result.rectangle.split(';')[0].split(',');
                            geocoder.getAddress(lnglat, function (status, data) {
                              if (status === 'complete' && data.info === 'OK') {
                                // result为对应的地理位置详细信息
                                console.log(data);
                              }
                            });
                        });
                    }
                });
            });
        },
        // 点击获取定位
        getAddress(){
            this.errFlag = false
            this.getLocation();
        }
    },
};
</script>

<style scoped lang="scss">
.pick-area {
    height: 10.15rem;
    overflow: hidden;
}
.address-title{
    width: 100%;
    text-align: center;
}
.address-detail{
    width: 4.6rem;
    height: 0.78rem;
    border-radius: 0.42rem;
    text-align: left;
    line-height: 0.78rem;
    background: #F5F5F5;
    // display: flex;
}
.hot-city-box{
    flex-wrap: wrap;
    display: flex;
    align-items: center;
    justify-content: flex-start;
}
.hot-city-item{
    padding: 0 0.35rem;
    height: 0.58rem;
    text-align: center;
    line-height: 0.58rem;
    background: #F5F5F5;
    margin-bottom: 0.3rem;
    border-radius: 0.3rem;
    margin-right: 0.16rem;
}
.wrapper{
    flex: 1;
    height: 6rem;
    overflow: auto;
}
.circle{
    display: inline-block;
    margin-bottom: 0.05rem;
    width: 0.1rem;
    height: 0.1rem;
    border-radius: 50%;
    background: $main-color;
}
.circle-hollow{
    display: inline-block;
    margin-bottom: 0.05rem;
    width: 0.1rem;
    height: 0.1rem;
    border-radius: 50%;
    border: 0.02rem solid $main-color;
}
.shu-line{
    width: 1px;
    height: 0.5rem;
    background: $main-color;
    margin-left: 0.05rem;
}
.heng-line{
    width: 100%;
    height: 1px;
    background: #DDDDDD;
    margin: 0.4rem 0;
}
</style>

<style lang="scss">
.pick-area .van-popup__close-icon--top-right{
    top: 8px;
}  
.pick-area .van-icon-cross::before{
    color: #B3B3B3;
}
</style>

import request from "@/service/index"
import postJson from "@/service/postJson"

//获取地区信息列表
export function getArea(params) {
    return request({
        url: 'base/area',
        method: 'get',
        params
    })
}

//获取地区信息列表
export function getHotProvince(params) {
    return request({
        url: 'base/code',
        method: 'get',
        params,
    })
}

在这里插入图片描述
在这里插入图片描述

可编辑框组件

<template>
    <div>
        <div v-if="isEdit">
            <input type="text" v-model='newVal'>
            <button @click="save">保存</button>
            <button @click="cancel">取消</button>
        </div>
        <div v-else @dblclick="edit">{{newVal}}</div>
    </div>
</template>
<script>
export default {
    name: 'EditTableField',
    props:['val'],
    data() {
        return {
            newVal:this.val,
            bakup:null,
            isEdit:false,
            nameCom: 'EditTableField',
        }
    },
    created(){
    },
    computed:{
    },
    methods:{
        cancel(){
        	// 原来的值赋值于变量bakup
            this.newVal = this.bakup
            this.isEdit = false
        },
        save(){
            this.isEdit = false
        },
        edit(){
        	// 修改的值赋值于变量newVal
            this.bakup = this.newVal
            // 拿到所有的父级下的子级元素
            // console.log(this.$parent.$children)
            console.log(this.$parent.$children.filter(item=>item.nameCom === 'EditTableField'))
            // 让其他的编辑框都隐藏
            this.$parent.$children.filter(item=>item.nameCom === 'EditTableField').forEach(item=>{
                item.isEdit = false
            })
            this.isEdit = true
        }
    },
}
</script>
<style lang="scss" scoped>

</style>

使用

<EditTableField :val='obj.nickname'></EditTableField>
<EditTableField :val='obj.age'></EditTableField>
<EditTableField :val='obj.gender'></EditTableField>

单图片预览

<template>
    <div>
        <img class="image-small"
            :src="imgSrc"
            alt=""
            @click="isPreview=true"
        />
        <div class="preview-img" v-if="isPreview"  @click="isPreview=false">
            <img class="image-big"
                :src="imgSrc"
                alt=""
                @click.stop="handleClick"
            />
        </div>
    </div>
</template>
<script>
export default {
    name: "SingleImagePreview",
    props:{
        imgSrc:{
            type:String,
            defalut:''
        }
    },
    data() {
        return {
            isPreview:false,
            showImg:true
        };
    },
    created() {},
    computed: {},
    methods: {
        handleClick(e){
            console.log(e)
            // 阻止事件冒泡 或者用@click.stop
            e.stopPropagation();
            // this.isPreview=false;
        }
    },
};
</script>
<style lang="scss" scoped>
.image-small{
    width: 200px;
    height: 100px;
}
.image-big{
    width: 500px;
    height: 300px;
}
.preview-img {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    background: rgba(255,255,255, 0.2);
    z-index: 99;
    display: flex;
    align-items: center;
    justify-content: center;
}
</style>

使用

<ImgPreview :imgSrc='imgSrc'></ImgPreview>

多图片预览

<template>
    <div>
        <img
            class="image-small"
            :src="img"
            alt=""
            @click="visibleImg(img)"
            v-for="(img,index) in imgSrcList"
            :key='index'
        />
        <div
            class="preview-img"
            v-if="isPreview"
            @click="isPreview = false"
        >
            <img class="image-big" :src="currentImg" alt=""  @click.stop="handleClick" />
        </div>
    </div>
</template>
<script>
export default {
    name: "MoreImagePreview",
    props:{
        imgSrcList:{
            type:Array,
            default:()=>{
                return []
            }
        }
    },
    data() {
        return {
            currentImg:'',
            isPreview:false
        };
    },
    created() {},
    computed: {},
    methods: {
        visibleImg(img){
            this.isPreview = true
            this.currentImg = img
        },
        handleClick(e){
            console.log(e)
            // 阻止事件冒泡 或者用@click.stop
            e.stopPropagation();
            // this.isPreview=false;
        }
    },
};
</script>
<style lang="scss" scoped>
.image-small{
    width: 200px;
    height: 100px;
}
.image-big{
    width: 500px;
    height: 300px;
}
.preview-img {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    background: rgba(255,255,255, 0.2);
    z-index: 99;
    display: flex;
    align-items: center;
    justify-content: center;
}
</style>

抽屉组件

<template>
    <div class="drawer"  v-if="value"  @click="innerVisible=false">
        <div class="container" :style="{width,height}" v-if="value" :class="position"  @click.stop>
            <slot></slot>
        </div>
    </div>
</template>
<script>
export default {
    name: 'Drawer',
    props:{
        value:{
            type:Boolean,
            default:false
        },
        width:{
            type:String,
            // default:'300px'
        },
        height:{
            type:String,
            // default:'300px'
        },
        position:{
            type:String,
            default:'left'
        }
    },
    data() {
        return {
            innerVisible:this.value
        }
    },
    watch:{
        value(){
            this.innerVisible = this.value
        },
        innerVisible(val){
            this.$emit('input',val)
        }
    },
    created(){
        
    },
    computed:{

    },
    methods:{
        
    },
}
</script>
<style lang="scss" scoped>
.container{
    position: fixed;
    background: #fff;
    z-index: 999;
}
.drawer{
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    width: 100%;
    height: 100%;
    background: rgba(0,0,0,0.5);
    z-index: 9;
}
.container.left{
    position: absolute;
    height: 100%;
    left:0;
    top: 0;
}
.container.right{
    position: absolute;
    height: 100%;
    right:0;
    top: 0;
}
.container.top{
    position: absolute;
    width: 100%;
    left:0;
    top: 0;
}
.container.bottom{
    position: absolute;
    width: 100%;
    left:0;
    bottom: 0;
}
</style>

使用

<template>
    <div>
        <Drawer v-model="visible" :position='pos' height="300px" width="500px">
            <div>内容</div>
        </Drawer>
        <button @click="showDrawer()">按钮</button>
    </div>
</template>
<script>

import Drawer from '../../components/Drawer'
export default {
    name: "blogs",
    components: { 
        Drawer
     },
    data() {
        return {        
            // pos:'left',
            // pos:'right',
            pos:'top',
            // pos:'bottom',
        };
    },
    created() {},
    computed: {},
    methods: {
        showDrawer(){
            this.visible = !this.visible
    
        }
    },
};
</script>
<style lang="scss" scoped>
</style>

日历组件

分页组件

<template>
    <div>
        <ul class="page flex">
            <li v-show="current>1" @click="current=1">first</li>
            <li :class="{disaled:current==1}" @click="current--" >prev</li>
            <li class="item" 
                :class="{active:item===current}"
                v-for='(item,index) in pageCount' :key="index"
                @click="current=item"
            >{{item}}</li>
            <li  :class="{disaled:current==pageCount}" @click="current++">nest</li>
            <li  v-show="current<pageCount"  @click="current=pageCount">last</li>
        </ul>
    </div>
</template>
<script>
export default {
    name: 'Pagination',
    props:{
        total:{
            type:Number,
            required:true,
            default:10
        },
        pageSize:{
            type:Number,
            default:10
        },
        value:{
            type:Number,
            defalult:1
        }
    },
    data() {
        return {
            current:this.value,
        }
    },
    created(){
    },
    computed:{
        pageCount(){
            return Math.ceil(this.total/this.pageSize)
        }
    },
    methods:{
    },
    watch: {
        current(val){
            if(val < 1) this.current = 1
            else if(val > this.pageCount) this.current = this.pageCount
            // 把带有当前页数传递出去
            this.$emit('input',this.current)
        }
    },
}
</script>
<style lang="scss" scoped>
.page{
    display: flex;
}
.page li{
    border: 1px solid red;
    width: 30px;
    height: 30px;
    font-size: 14px;
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0 2px;
    -moz-user-select: none;
    cursor: pointer;
}
.page li:not(.item){
    width: 50px;
}
.page li.active{
    background: red;
    color: #fff;
}
.page li.disaled{
    background: #ccc;
    color: #eee;
    border: 1px solid #eee;
    cursor: not-allowed;
}
</style>

使用

<template>
    <div>
        <ul>
            <li v-for="(item,index) in list" :key='index'>{{item.areaName}}</li>
        </ul>
        <Pagination :total='total' :page-size='pageSize' v-model="pageIndex"></Pagination>
        <!-- 这里的change是为了拿到里面的页数  用v-model也可以 -->
        {{pageIndex}}
        <!-- <Pagination :total='15' :page-size='5' @change='pageIndex=$event'></Pagination> -->
        <!-- <Pagination :total='15' :page-size='5'></Pagination>
        <Pagination :total='20'></Pagination> -->
    </div>
</template>
<script>
import {getPageData,getCityArea} from '../../api/test'
import Pagination from '../../components/Pagination';
export default {
    name: "blogs",
    components: { 
        Pagination
     },
    data() {
        return {
            pageIndex :1,
            pageSize:50,
            total:'',
            list:[]
        };
    },
    computed: {},
    methods: {  
        async getData(){
            let params = {
                // 页数
                page : this.pageIndex, 
                limit: this.pageSize,
                city: '',
                district:'',
                r: '',
                lon: '',
                lat:'',
                tmt: '',
                secondTmt: '',
                dayExposure: '',
                ratio: '',
            }
            let {data} = await getPageData(params)
            // let data = await getCityArea()
            console.log(data)
            this.list = data.advertInfoList
            this.total = data.total
        }
    },
    created() {
        this.getData()
    },
    watch: {
        pageIndex(){
            this.getData()
        }
    },
};
</script>
<style lang="scss" scoped>
</style>
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值