本篇写的是左右联动仿饿了么单页,不是网上的高仿饿了么app,但是也从那边做了借鉴,没有使用 VUE,而是用的 JQ和 doT模板。也能达到对应的效果,数据也是模拟的数据,通过 JQ来获取本地的 json数据,通过 doT模板填充数据。项目虽小也算实战,话不多说,直接上代码,都有注释就不写太多了。

贴上代码:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <link rel="stylesheet" href="./reset.css">
    <link rel="stylesheet" href="./common.css">
    <style>
        .goods {
            display: flex;
            position: absolute;
            top: 0;
            bottom: 0;
            width: 100%;
            overflow: hidden;
        }

        .goods .menu-wrapper {
            flex: 0 0 80px;
            width: 80px;
            background: #f3f5f7;
        }

        .goods .menu-wrapper .menu-item {
            display: table;
            height: 54px;
            width: 80px;
            padding: 0 12px;
            line-height: 14px;
        }

        .goods .menu-wrapper .menu-item.current {
            position: relative;
            z-index: 10;
            margin-top: -1px;
            background: #fff;
            font-weight: 700;
        }

        .goods .menu-wrapper .menu-item.current .text {
            border: none
        }

        .goods .menu-wrapper .menu-item .text {
            display: table-cell;
            width: 56px;
            vertical-align: middle;
            text-align: center;
            font-size: 12px;
            border-bottom: 1px solid rgba(7, 17, 27, 0.1);
        }

        .goods .foods-wrapper {
            flex: 1
        }

        .goods .foods-wrapper .title {
            padding-left: 14px;
            height: 26px;
            line-height: 26px;
            border-left: 2px solid #d9dde1;
            font-size: 12px;
            color: rgb(147, 153, 159);
            background: #f3f5f7;
        }

        .goods .foods-wrapper .food-item {
            display: flex;
            margin: 18px;
            padding-bottom: 18px;
            border-bottom: 1px solid rgba(7, 17, 27, 0.1);
        }

        .goods .foods-wrapper .food-item .icon {
            flex: 0 0 57px;
            margin-right: 10px;
        }

        .goods .foods-wrapper .food-item .content {
            flex: 1
        }

        .goods .foods-wrapper .food-item .content .name {
            margin: 2px 0 8px 0;
            height: 14px;
            line-height: 14px;
            font-size: 14px;
            color: rgb(7, 17, 27);
        }

        .goods .foods-wrapper .food-item .content .desc, .goods .foods-wrapper .food-item .content .extra {
            line-height: 12px;
            margin-bottom: 8px
        }

        .goods .foods-wrapper .food-item .content .extra .count {
            margin-right: 12px
        }

        .goods .foods-wrapper .food-item .content .price {
            line-height: 12px;
            margin-bottom: 8px
        }

        .goods .foods-wrapper .food-item .content .price .now {
            margin-right: 8px;
            font-size: 14px;
            color: rgb(240, 20, 20);
        }

        .goods .foods-wrapper .food-item .content .price .old {
            text-decoration: line-through;
            font-size: 10px;
            color: rgb(147, 153, 159);
        }
    </style>

</head>
<body>
<div>
    <div class="goods">
        <div class="menu-wrapper" id="menuWrapper">
            <ul id="wrapperLeft"></ul>
            <script id="wrapperLeftBox" type="text/doTtemplate">
                {{for(var i in it) {}}
                    <li class="menu-item">
                        <span class="text">{{=it[i].name}}</span>
                    </li>
                {{ } }}
            </script>
        </div>
        <div class="foods-wrapper" id="foodsWrapper">
            <ul id="wrapperRight"></ul>
            <script id="wrapperRightBox" type="text/doTtemplate">
                {{for(var i in it) {}}
                    <li class="food-list">
                        <h1 class="title">{{=it[i].name}}</h1>
                        <ul>
                            {{for(var j in it[i].foods){}}
                                <li class="food-item">
                                    <div class="icon">
                                        <img width="57" height="57" src="{{=it[i].foods[j].icon}}">
                                    </div>
                                    <div class="content">
                                        <h2 class="name">{{=it[i].foods[j].name}}</h2>
                                        <p class="desc">{{=it[i].foods[j].description}}</p>
                                        <div class="extra">
                                            <span class="count">月售{{=it[i].foods[j].sellCount}}份</span><span>好评率{{=it[i].foods[j].rating}}%</span>
                                        </div>
                                        <div class="price">
                                            <span class="now">¥{{=it[i].foods[j].price}}</span>
                                            {{? it[i].foods[j].oldPrice != ''}}
                                            <span class="old">¥{{=it[i].foods[j].oldPrice}}</span>
                                            {{?}}
                                        </div>
                                    </div>
                                </li>
                            {{ } }}
                        </ul>
                    </li>
                {{ } }}
            </script>
        </div>
    </div>
</div>
</body>
<script src="bscroll.js"></script>
<script src="doT.min.js"></script>
<script src="jquery-3.1.1.min.js"></script>
<script>

    $( document ).ready( readyHandler );

    function readyHandler() {
        // 1:先请求列表数据
        $.post( "data.json", null, loadHandler, "json" );
    }

    /**
     * 数据列表加载完成
     * @param data
     */
    function loadHandler( data ) {
        console.log( data );

        var menuWrapper,foodsWrapper,scrollY;

        // 给左侧内容填充数据
        var wrapperLeftBoxTpl = doT.template(document.getElementById('wrapperLeftBox').innerHTML);
        document.getElementById("wrapperLeft").innerHTML = wrapperLeftBoxTpl(data.goods);

        // 给右侧内容填充数据
        var wrapperRightBoxTpl = doT.template(document.getElementById('wrapperRightBox').innerHTML);
        document.getElementById("wrapperRight").innerHTML = wrapperRightBoxTpl(data.goods);

        // 判断左侧内容是否有数据,如果有则初始化 Bscroll 滚动
        if($("#wrapperLeft").html()){
            menuWrapper =  new BScroll(document.getElementById('menuWrapper'), {
                click: true
            });
        }

        // 判断右侧内容是否有数据,如果有则初始化 Bscroll 滚动
        // BScroll 穿入两个参数,第一个el (dom元素),第二个是个对象(默认不阻止点击,可实时监听滚动)
        if($("#wrapperRight").html()){
            foodsWrapper = new BScroll(document.getElementById('foodsWrapper'), {
                click: true,
                probeType: 3
            })
        }

        /*
         * 1. 现获取右侧所有 li 的高度
         * 2. 获取的高度保存数组内
         * 3. 循环点击左侧的 li,判断数据的内容是否跟点击的数据一致,通过 BScroll 提供的方法 scrollToElement 滚动到对应的文档位置
         *    scrollToElement 接受五个参数 el(必填)表示 dom 元素,time 表示动画时间,offsetX 和 offsetY 表示坐标偏移量,easing 表示缓动函数
         *    scrollToElement (el, time, offsetX, offsetY, easing)
         * 4. 设置点击时候的对应的 class ,现移除所有同级元素的 class(current),再给自己的加一个class(current)
         */

        var foodList = document.getElementsByClassName("food-list")

        var height = 0;
        var listHeight = [];
        listHeight.push(height);

        for (var i = 0; i < foodList.length; i++) {
            var item = foodList[i];
            height += item.clientHeight;

            listHeight.push(height);
            console.log(listHeight)
        }

        $("#wrapperLeft").delegate("li", "click", function(e){
            //console.log(e.target.innerText)
            for(var i = 0; i < data.goods.length; i++){
                if(data.goods[i].name == e.target.innerText){
                    foodsWrapper.scrollToElement(document.getElementsByClassName("food-list")[i], 800); //800毫秒滚动到顶
                    $(this).addClass("current").siblings().removeClass("current")
                }
            }
        })

        // 实时监听右侧滚动
        foodsWrapper.on('scroll', function(pos) {
            scrollY = Math.abs(Math.round(pos.y));
            for(var i = 0; i < listHeight.length; i++){
                var height1 = listHeight[i];
                var height2 = listHeight[i + 1];
                if (!height2 || (scrollY >= height1 && scrollY < height2)) {
                    $($(".menu-item")[i]).addClass("current").siblings().removeClass("current")
                }
            }
        });

        // 给第一个添加默认点击
        $("#wrapperLeft").children().first().trigger("click")

    }

</script>
</html>

猛戳这里预览 →