前端fayermall开发项目(页面逻辑)

一、个人用户信息

1、通用模块的开发

1)左边是登录和没登录两个状态

2)页面初始化的时候,会读取用户信息;会请求一个检查登录状态的接口,通过接口判断,如果我们拿到用户信息了,就说明有登陆状态;如果没拿到,报错了,就说明没有登录;

3)页面初始化的时候,同时也要加载购物车数量,请求一个获取购物车数量接口;

require('./nav.css');
var _mm = require('util/mm.js');
var _user = require('service/user-service.js');
var _cart = require('service/cart-service.js');
//导航
var nav = {
    init : function(){
        this.bindEvent();
        this.loadUserInfo();
        this.loadCartCount();
        return this; //this指向 init调用(nav.init()),即把nav又返回去了,输出的时候还是nav对象
    },
    bindEvent : function(){
        //点击登录事件
        $('.js-login').on('click',function(){
            _mm.doLogin();
        });
        //注册点击事件
        $('.js-register').on('click',function(){
            window.location.href = './user-register.html'
        });
        //退出点击事件
        $('.js-logout').on('click',function(){
            _user.logout(function(res){
                window.location.reload();//重新刷新页面
            },function(errMsg){
                _mm.errorTips(errMsg);
            })
        });
    },
    //加载用户信息
    loadUserInfo : function(){
        _user.checkLogin(function(res){
            $('.user.not-login').hide().siblings('.user.login').show()
                .find('.username').text(res.username);
        },function(errMsg){
            //
        })
    },
    //加载购物车数量
    loadCartCount : function(){
        _cart.getCartCount(function(res){
            $('.nav .cart-count').text(res || 0);
        },function(errMsg){
            $('.nav .cart-count').text(0);
        })
    }
}
module.exports = nav.init();//这是因为这个模块被引用后就一定会立即执行init的,所以就在模块的输出时就做了,这样在引用它的地方就不用再每次调用init方法了

 2、通用头部header,两个逻辑

1)搜索提交
【】获取Input的val,就是keyword,如果存在,则通过参数的形式,跳转到list页
2)输入完东西,搜索以后,进入了list.html页以后,input框内不能为空,应该是搜索的内容,所以要根据url参数 进行回填
【】页面一加载进来的时候,读取url的参数,即keyword值,并回填到input
//通用页面头部
var header = {
    init : function(){
        var _this = this;
        this.onLoad();    
        this.bindEvent();
    },
    onLoad : function(){
        var keyword = _mm.getUrlParam('keyword');
        //如果keyword存在,则回填输入框
        if(keyword){
            $('#search-input').val(keyword);
        }
    },
    bindEvent : function(){
        var _this = this;
        //点击搜索,做搜索提交
        $('#search-btn').on('click',function(){
            _this.searchSubmit();
            console.log(222);
        })
        //输入回车后,做搜索提交
        $('#search-input').on('keyup',function(e){
            if(e.keyCode == 13){
                _this.searchSubmit();
            }
        })
        
    },
    //搜索的提交
    searchSubmit : function(){
        var keyword = $.trim($('#search-input').val());
        //如果有keyword的时候,正常跳转到List页
        if(keyword){
            window.location.href = './list.html?keyword=' + keyword;
        }else{
            _mm.goHome();
        }
    }

}
header.init();

 

3、通用侧边导航

 

1)就一个逻辑,就是用js渲染侧边栏

【】把侧边导航当做一个通用模块,单独写成一个.string的模块,然后通过本地创建数据,把数据渲染到里面。
【】添加active:通过其他页面传进来option和已经创建的option进行合并选项,把传进来的option.name和this.name.option作为判断条件,如果相等,就给navlist添加一个标记位,用来添加active;
//侧边导航
var navSide = {
    option : {
        name : '',
        navlist : [
            {name : 'user-center',desc : '个人中心',href : './user-center.html'},
            {name : 'order-list',desc : '我的订单',href : './order-list.html'},
            {name : 'user-pass-update',desc : '修改密码',href : './user-pass-update.html'},
            {name : 'about',desc : '关于MMall',href : './about.html'}
        ]
    },
    init : function(option){
        //合并选项,后者覆盖前者
        $.extend(this.option,option);
        this.renderNav();
    },
    //渲染导航菜单                    
    renderNav : function(){
        var iLength = this.option.navlist.length;
        for(var i = 0; i < iLength; i++ ){
            if(this.option.navlist[i].name === this.option.name){
                this.option.navlist[i].isActive = true;
            }
        };
        //渲染list数据
        var navHtml = _mm.renderHtml(templateNavSide,{
            navlist : this.option.navlist
        });
        $('.nav-side').html(navHtml);
    }    
}
module.exports = navSide;
{{#navlist}}
    {{#isActive}}
    <li class="nav-item active">
    {{/isActive}}
    {{^isActive}}
    <li class="nav-item">
    {{/isActive}}
        <a class="link" href="{{href}}">{{desc}}</a>
    </li>
{{/navlist}}

 

4、个人中心开发

1)个人中心展示 user-center.html

【】创建user-center.string模板,请求接口渲染

2)个人信息修改 user-center-update

 

【】初始化,左侧导航

init: function(){
        this.onLoad();
        this.bindEvent();
    },
    onLoad : function(){
        // 初始化左侧菜单
        navSide.init({
            name: 'user-center'
        });
        // 加载用户信息
        this.loadUserInfo();
    },

 

【】做验证,点击提交

先定义一个变量validateResult,即validateForm函数的返回值result对象,通过返回对象状态码status的true or false 来进行提交以及验证,验证通过(true),请求接口;验证错误,就返回一个msg;
bindEvent : function(){
        var _this = this;
        // 点击提交按钮后的动作
        $(document).on('click', '.btn-submit', function(){
            var userInfo = {
                phone       : $.trim($('#phone').val()),
                email       : $.trim($('#email').val()),
                question    : $.trim($('#question').val()),
                answer      : $.trim($('#answer').val())
            },
            //输入框验证信息
            validateResult = _this.validateForm(userInfo);
            if(validateResult.status){
                // 更改用户信息
                _user.updateUserInfo(userInfo, function(res, msg){
                    _mm.successTips(msg);
                    window.location.href = './user-center.html';
                }, function(errMsg){
                    _mm.errorTips(errMsg);
                });
            }
            else{
                _mm.errorTips(validateResult.msg);
            }
        });
    },
    // 验证字段信息
    validateForm : function(formData){
        var result = {
            status  : false,
            msg     : ''
        };
        // 验证手机号
        if(!_mm.validate(formData.phone, 'phone')){
            result.msg = '手机号格式不正确';
            return result;
        }
        // 验证邮箱格式
        if(!_mm.validate(formData.email, 'email')){
            result.msg = '邮箱格式不正确';
            return result;
        }
        // 验证密码提示问题是否为空
        if(!_mm.validate(formData.question, 'require')){
            result.msg = '密码提示问题不能为空';
            return result;
        }
        // 验证密码提示问题答案是否为空
        if(!_mm.validate(formData.answer, 'require')){
            result.msg = '密码提示问题答案不能为空';
            return result;
        }
        // 通过验证,返回正确提示
        result.status   = true;
        result.msg      = '验证通过';
        return result;
    }

  

二、首页(纯属静态页面,没有请求接口http://localhost:8080/dist/view/index.html)

1、左侧关键字导航

1)产品关键字,点击跳转到list.html?keyword=xxx页面,所以要在a标签里把关键字参数keyword写到链接里
<li class="keywords-item">
    <a class="link" target="_blank" href="./list.html?keyword=电脑">电脑</a>
    <span class="cate_menu_line">/</span>
    <a class="link" target="_blank" href="./list.html?keyword=办公配件">办公配件</a>
</li>

2、首页banner

1)样式布局:用绝对定位,然后用透明度属性,来切换图片。还另外加了css3的transform和transition的变化和过渡。

 
2)把轮播的脚本单独放在slider-img.js,然后在Index.js里引用。webpack用requrie方式引入模块
1 require('page/common/nav/nav.js');
2 require('page/common/header/header.js');
3 var sliderImg = require('util/slider/slider-img.js');
4 var navSide = require('page/common/nav-side/nav-side.js');
5 var _toolbar = require('page/common/toolbar/toolbar.js');
6 var _mm             = require('util/mm.js');
 
 
3、产品列表
1)这里的内容是直接从后台导入的数据,因为没有请求接口,所以每个产品的categoryId都需要手动添加;这里注意一个情况,就是在html里面引用图片的时候,一定要用requrie的方式,然后通过相对路径来添加图片;
 <li class="floor-item">
     <a href="./list.html?categoryId=100007">
         <span class="floor-text">电视</span>
         <img class="floor-img" src="<%= require('../image/floor/floor1-2.jpg') %>" alt="电视" />
      </a>
</li>

 4、左侧悬浮和右侧悬浮,头部悬浮

1)都用了固定定位fixed

2)左侧和顶部的悬浮,用同一个脚本做显示隐藏,在Index.js引入toolbar.js,单独封装.webpack用module.exports输出模块(对象)

require('./toolbar.css');
//参数 $fixedBar 要定位的对象
//参数Topobj 相对于某个定位的对象
//参数docClass fiexd显示隐藏的控制class值
var _toolbar = {
    //fixedbar 切换
    fixedbar : function(obj,Topobj,docClass){
        var $fixedBar = $(obj),
        $offsetTop = '';
        if(obj === '.leftbar'){
            $offsetTop = $(Topobj).offset().top-200;
        }else{
            $offsetTop = $(Topobj).offset().top;
        }
        $(window).scroll(function(){
            if($(window).scrollTop() > $offsetTop){
                $fixedBar.addClass(docClass);
            }else{
                $fixedBar.removeClass(docClass);
            }
        });
    }
}
module.exports = _toolbar;

 3)悬浮的样式效果,都添加了css3简单的动画效果


.transition(@transition){
    -webkit-transition:@transition;
    -moz-transition:@transition;
    -ms-transition:@transition;
    -o-transition:@transition;
    transition:@transition;
}
.transform-origin(@right, @bottom){
    -webkit-transform-origin:@right @bottom;
    -moz-transform-origin:@right @bottom;
    -o-transform-origin:@right @bottom;
    -ms-transform-origin:@right @bottom;
    transform-origin:@right @bottom;
}
.scale(@scale){
    -webkit-transform : scale(@scale);
    -moz-transform : scale(@scale);
    -ms-transform : scale(@scale);
    -o-transform : scale(@scale);
    transform : scale(@scale);
} 

 三、商品列表页(http://localhost:8080/dist/view/list.html?keyword=手机)

1、商品列表页list.html分为两个路口从首页进入,一个是点击商品通过传递参数categoryId,一个通过搜索,通过传递参数keyword;

 2、页面是通过新建list.string用hogan.js渲染的

{{#list}}
    <li class="p-item">
        <div class="p-img-con">
            <a class="link" href="./detail.html?productId={{id}}" target="_blank">
                <img class="p-img" src="{{imageHost}}{{mainImage}}" alt="{{name}}" />
            </a>
        </div>
        <div class="p-price-con">
            <span class="p-price">¥{{price}}</span>
        </div>
        <div class="p-name-con">
            <a class="p-name" href="./detail.html?productId={{id}}" target="_blank">{{name}}</a>
        </div>
    </li>
{{/list}}
{{^list}}
    <p class="err-tip">很抱歉,实在找不到您要的商品。</p>
{{/list}}

 

3、页面处理的脚本

1)01页面一加载进来,02点击默认,升序降序按钮,03点击分页;分别都会加载list;

2)通过url获取keyword或者categoryId参数

data : {
        listParam : {
            keyword         : _mm.getUrlParam('keyword')    || '',
            categoryId      : _mm.getUrlParam('categoryId') || '',
            orderBy         : _mm.getUrlParam('orderBy')    || 'default',
            pageNum         : _mm.getUrlParam('pageNum')    || 1,
            pageSize        : _mm.getUrlParam('pageSize')   || 5
        }
    }

 

四、详情页 

1、先通过url获取到productId,然后传递参数,来渲染详情页

2、包含的事件

bindEvent : function(){
        var _this = this;
        // 图片预览
        $(document).on('mouseenter', '.p-img-item', function(){
            var imageUrl   = $(this).find('.p-img').attr('src');
            $('.main-img').attr('src', imageUrl);
        });
        // count的操作
        $(document).on('click', '.p-count-btn', function(){
            var type        = $(this).hasClass('plus') ? 'plus' : 'minus',
                $pCount     = $('.p-count'),
                currCount   = parseInt($pCount.val()),
                minCount    = 1,
                maxCount    = _this.data.detailInfo.stock || 1;
            if(type === 'plus'){
                $pCount.val(currCount < maxCount ? currCount + 1 : maxCount);
            }
            else if(type === 'minus'){
                $pCount.val(currCount > minCount ? currCount - 1 : minCount);
            }
        });
        // 加入购物车
        $(document).on('click', '.cart-add', function(){
            _cart.addToCart({
                productId   : _this.data.productId,
                count       : $('.p-count').val()
            }, function(res){
                window.location.href = './result.html?type=cart-add';
            }, function(errMsg){
                _mm.errorTips(errMsg);
            });
        });
    }

3、添加购物车功能,请求接口,跳转到加入购物车成功后提示页

五、购物车和订单(不详细说明了,面试的时候演示)

 六、登录注册页面

 

 

 

 

 

 

 

 

 

 

posted on 2017-08-06 23:29  fayerSmile  阅读(1045)  评论(0编辑  收藏  举报

导航