vue模仿饿了么实现横向导航

最近用vue模仿饿了么,写一个外卖商城webApp
先上效果图:
在这里插入图片描述
html部分

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, minimum-scale=1.0,maximum-scale=1.0,user-scalable=no">
    <title>menu-bar</title>
    <link rel="stylesheet" href="./css/font/iconfont.css">
    <link rel="stylesheet" href="./css/style.css">
    <script type="text/javascript" src="./js/common/mock.js"></script>
    <script type="text/javascript" src="./js/common/axios.js"></script>
    <script type="text/javascript" src="./js/common/vue.js"></script>
    <script type="text/javascript" src="./css/font/iconfont.js"></script>
    <script type="text/javascript" src="./js/index.js"></script>
    <script type="text/javascript" src="./js/menu.js"></script>
</head>
<body>
    <div id="menus">
        <div class="menu-list">
            <ul
             class="menus"
             @touchstart="touchStart"
             @touchmove="touchMove"
             @touchend="touchEnd"
             ref="menus">
                <li class="menus-item" v-for="(menu, i) in menuList" :key="i">
                    <i class="iconfont" :class="menu.url"></i>
                    <span>{{menu.title}}</span>
                </li>
            </ul>
        </div>
        <div class="circle" v-if="menuList.length>0">
            <span v-for="j in menuPage" :key="j" :class="{spanactive: j===circleIndex}"></span>
        </div>
    </div>
</body>
</html>

CSS部分

* {
    margin: 0;
    padding: 0;
    list-style: none !important;
}

html {
    width: 100%;
}

.menu-list {
    overflow: hidden;
}

.menus {
    position: relative;
    width: 200%;
    display: flex;
    flex-wrap: wrap;
    font-size: 1.1em;
    text-align: center;
}

.menus-item {
    width: 12.5%;
    cursor: pointer;
}

.menus-item i {
    display: block;
}

.iconfont{
    color: coral;
    margin-bottom: 4px;
    font-size: 30px;
} 

.menus-item span {
    font-size: 18px;
    color: #aaaaaa;
}

.circle {
    width: 100%;
    text-align: center;
}

.circle span {
    display: inline-block;
    width: 5%;
    height: .15em;
    margin-right: 1%;
    margin-bottom: 2%;
    background-color: #cccccc;
}

.circle .spanactive {
    background-color: #0292ff;
}

vue部分

window.onload = () => {
    new Vue({
        el: '#menus',
        data: {
            menuList: [],
            listWidth: '',
            num: 8,
            ulIndex: 0,
            circleIndex: 1,
            startX: 0,
            moveX: 0
        },

        mounted () {
            this.getMenuList()
            this.listWidth = window.innerWidth
            console.log(this.listWidth) 
            console.log(this.$refs.menus.style.transform + 10)
        },

        computed: {
            curTranslateX () {
                return -this.listWidth * this.ulIndex
            },

            // 计算页数
            menuPage () {
                return Math.ceil(this.menuList.length / this.num)
            }
        },

        watch: {
            circleIndex () {
                if (this.circleIndex > this.menuPage) this.circleIndex = this.menuPage
                if(this.circleIndex < 1) this.circleIndex = 1
            }
        },

        methods: {
            getMenuList () {
                axios({
                    methods: 'get',
                    url: '/api/menuList'
                }).then(res => {
                    // console.log(res.data.menuList)
                    this.menuList = res.data.menuList
                }).catch(err => {
                   console.log(err)
                })
            },

            animateEnd () {
                if(this.ulIndex > this.menuPage - 1) {
                    this.ulIndex = this.menuPage - 1
                    this.$refs.menus.style.transition = 'none'
                    this.$refs.menus.style.transform = `translateX(${this.menuList}px)`
                }

                if(this.ulIndex < 0) {
                    this.ulIndex = 0
                    this.$refs.menus.style.transition = 'none' // 过渡动画
                    this.$refs.menus.style.transform = `translateX(${this.curTranslateX}px)` // 调整相对位置
                }
            },

            touchStart (event) {
                this.startX = event.targetTouches[0].clientX
            },

            touchMove (event) {
                this.moveX = event.targetTouches[0].clientX - this.startX
                this.$refs.menus.style.transition = 'none'
                this.$refs.menus.style.transform = `translateX(${this.curTranslateX + this.moveX}px)`
            },

            touchEnd () {
                if(this.moveX > this.listWidth / 3 && this.ulIndex > 0) {
                    this.ulIndex--
                    this.circleIndex--
                }else if(this.moveX < -this.listWidth / 3 && this.ulIndex < this.menuPage - 1) {
                    this.ulIndex++
                    this.circleIndex++
                }
                console.log(this.startX, this.moveX)
                this.$refs.menus.style.transition = 'all .5s' 
                this.$refs.menus.style.transform = `translateX(${this.curTranslateX}px)`
                this.moveX = 0
            }
        }
    })
}

总结,总的来说要实现动画必须先开启定位,移动端的触摸事件包括touchstart,touchmove,touchend三个,touchstart记录开始的触摸点坐标,touchmove算出滑动的距离,touchend可以进行最终过渡动画的操作,相关的状态属性也是很重要的,比如startX,moveX,要明白需要那些状态属性

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值