vue-app项目知识点总结(三)

本文是Vue App项目的第三部分总结,涵盖分类页面的构建,包括页面结构、网络请求和组件使用;用户登录功能的实现,涉及路由、登录页面布局及前端验证;以及商品详情页的图片点击放大功能预告。项目源码可在GitHub找到。

本项目GitHub地址:https://github.com/Yue-Shang/shop-app
vue-app项目知识点总结(一)
vue-app项目知识点总结(二)

一.分类页面

1.页面结构

在这里插入图片描述

2.新建文件夹

主页面:Category.vue
分类列表:CategoryList.vue
对应商品:CategoryGoods.vue
在这里插入图片描述
网络请求都写到Category.js中
在这里插入图片描述

3.我们先写分页主页面大框

这里我们先把左侧列表引到里面来了
Category.vue

<template>
  <div id="category">
    <nav-bar class="category-nav"><div slot="center">分类</div></nav-bar>
    <div class="content">
        <category-list :category="category" @selectUtem="selectUtem"/>
    </div>
  </div>
</template>

<script>
    import CategoryList from "./childComps/CategoryList";

    import Scroll from "components/common/scroll/Scroll";
    import NavBar from "components/common/navbar/NavBar";

    import {getCategoryList} from "network/Category";

    export default {
        name: "Category.vue",
        components:{Scroll,CategoryList,NavBar},
        data (){
            return{
               scroll:null,
                category:[],
            }
        },
        created() {
            this.getCategoryList()
        },
        methods:{
            getCategoryList(){
                getCategoryList().then(res =>{
                    this.category = res.data.category.list
                })
            }
        }
    }
</script>
css样式代码里看

4.左侧分类列表

1)请求网络数据
Category.js

import {request} from "./request";

export function getCategoryList() {
  return request({
    url:'/category'
  })
}

2)分类列表

<template>
   <scroll>
     <div id="category-list">
       <div class="category-title"
            :class="{active: index === isAction}"
            v-for="(item,index) in category"
            :key="index"
            @click="itemClick(index)"
       >
         {{item.title}}
       </div>
     </div>
   </scroll>
</template>

<script>
    import Scroll from "components/common/scroll/Scroll";
    export default {
        name: "CategoryList",
        components: {Scroll},
        data(){
            return {
                isAction:0
            }
        },
        props:{
            category:Array
        },
        methods:{
            itemClick(index){
                this.isAction = index
                this.$emit('selectUtem',index)
            }
        }
    }
</script>

<style scoped>
  #category-list{
    width: 30%;
    height: 100%;
    box-sizing: border-box;
  }
  .category-title{
    height: 44px;
    width: 100%;
    text-align: center;
    line-height: 44px;
  }
  .category-title.active {
    font-weight: 700;
    color: var(--color-high-text);
    background-color: #fff;
    border-left: 3px solid var(--color-high-text);
  }
</style>

box-sizing: border-box;https://www.w3school.com.cn/cssref/pr_box-sizing.asp
效果:
在这里插入图片描述

5.左侧对应商品展示

1)请求网络数据
Category.js

export function getSubcategory(maitKey) {
  return request({
    url:'http://152.136.185.210:8000/api/n3/subcategory',
    params: {
      maitKey
    }
  })
}

2)导入到父组件中
但是右侧可不是老老实实的显示maitKey对应的数据就完了,商品下还有个便签页,对商品进行分类展示,这个标签页我们之前在首页写过直接拿过来用就可以
在这里插入图片描述
所以我们需要在Category.vue中引用三个组件
i)CategoryGoods
我们根据屏幕显示大小排列不同个数的商品图片

<template>
  <div class="category-goods">
        <div class="item" v-for="(item,index) in subcategories.list" :key="index">
          <a :href="item.link">
            <img class="item-img" :src="item.image" alt="">
            <div class="item-text">{{item.title}}</div>
          </a>
        </div>
  </div>
</template>
...
props:{
            subcategories: {
                type: Object,
                default() {
                    return []
                }
            }
        }
 css样式参考代码,这里我们要注意保证每行是3个商品图片,我们把宽度设置成百分比 

放到Category.vue中

<scroll class="tab-content"
        ref="scroll"
        :probe-type="3"
        :pull-up-load="true"
>
<div>
    <category-goods :subcategories="showSubcategory"></category-goods>
</div>
</scroll>

import CategoryGoods from "./childComps/CategoryGoods";"components/common/tabControl/TabControl";

import {...getSubcategory} from "network/Category";
export default {
        name: "Category",
        components:{...,CategoryGoods},
        data (){
            return{
               scroll:null,
                category:[],
                currentIndex:-1,
                categoryData: {},
            }
        },
        created() {
            this.getCategoryList()
        },
        computed:{
            showSubcategory() {
                if (this.currentIndex === -1) return {}
                return this.categoryData[this.currentIndex].subcategories
            },
        },
        methods:{
            getCategoryList(){
                getCategoryList().then(res =>{
                    // 1.获取分类数据
                    this.category = res.data.category.list
                    // // 2.初始化每个类别的子数据
                    for (let i = 0; i < this.category.length; i++) {
                        this.categoryData[i] = {
                            subcategories: {},
                        }
                    }
                     // 3.请求第一个分类的数据,不调用的话刚进来currentIndex值为-1,什么都不显示
                    this.getSubcategory(0)
                })
            },
            getSubcategory(index){
                this.currentIndex = index;
                const maitKey = this.category[index].maitKey;
                getSubcategory(maitKey).then(res =>{
                    this.categoryData[index].subcategories = res.data
                    //ES6中的json展开功能
                    this.categoryData = {...this.categoryData}
                })
            },
            //侧边栏的点击事件,点击显示对应的商品信息
            selectUtem(index){
                this.getSubcategory(index)
            }
        }

    }

效果如下
在这里插入图片描述
滑动有点不好使

ii)标签页部分
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

二.用户登录功能

我们点击登录要弹出一个登录页面

1.首先我们就要去建一个登录的路由

router/index.js

路由懒加载
const Login = () => import('../views/login/Login')
...
  {
    path: '/login',
    component: Login
  },

想点击这里
在这里插入图片描述
实现跳转
src\views\profile\childComps\UserInfo.vue
把a标签替换为

<router-link to="/login" class="clear-fix"></router-link>

在这里插入图片描述

2.新建Login文件

在这里插入图片描述
但是我们发现问题,这个底部导航我们不需要呀,怎么处理呢?
在这里插入图片描述
在配置映射的时候有这样一个映射meta,我们给需要导航的路由下加上这个
router/index.js

{
    path:'',
    redirect: '/home',
    meta:{
      showFooter:true
    }
  },

在App.vue
$route代表当前路由

<main-tab-bar v-show="$route.meta.showFooter"/>

3.对登录页面进行布局

<template>
    <div class="login">
      <nav-bar>
        <div slot="left" @click="backClick" class="login-back"></div>
      </nav-bar>
      <div><span class="login-logo"></span></div>
      <div class="login-header">
        <a href="javascript:;" :class="{active: isActive}" @click="isActive=true"><span>短信登录</span></a>
        <a href="javascript:;" :class="{active: !isActive}" @click="isActive=false"><span>密码登录</span></a>
      </div>
      <div class="login_content">
        <form>
          <!-- 短信登陆 -->
          <div :class="{active2: !isActive}">
            <section class="login_message">
              <input type="tel" maxlength="11" placeholder="手机号">
              <button disabled="disabled" class="get_verification">获取验证码</button>
            </section>
            <section class="login_verification">
              <input type="tel" maxlength="8" placeholder="验证码">
            </section>
            <section class="login_hint">
              温馨提示:未注册帐号的手机号,登录时将自动注册,且代表已同意
              <a href="javascript:;">《用户服务协议》</a>
            </section>
          </div>
          <!-- 密码登陆 -->
          <div :class="{active2: isActive}">
            <section>
              <section class="login_message">
                <input type="text" maxlength="11" placeholder="手机/邮箱/用户名" v-model="name">
              </section>
              <section class="login_verification">
                <!-- 是否显示密码 -->
                <input type="text" maxlength="8" placeholder="密码">
                <input type="password" maxlength="8" placeholder="密码" >
                <div class="switch_button off" >
                  <div class="switch_circle" ></div>
                  <span class="switch_text">{{showPwd ? '显示' : '隐藏'}}</span>
                </div>
              </section>
            </section>
          </div>
          <button class="login_submit" @click.prevent="login">登录</button>
        </form>
        <a href="javascript:;" class="other-login">————其他登录方式————</a>
        <div class="weixin"></div>
      </div>
      </div>
</template>

<script>
    import NavBar from "components/common/navbar/NavBar";
    export default {
        name: "Login",
        components: {NavBar},
        data(){
            return{
              isActive:true,
            }
        },
        methods:{
            //返回按钮
            backClick(){
                this.$router.back()
            }
        },
    }
</script>
css查看源代码

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

(1)实现标签切换显示不同内容
<a href="javascript:;" :class="{active: isActive}" @click="isActive=true"><span>短信登录</span></a>
<a href="javascript:;" :class="{active: !isActive}" @click="isActive=false"><span>密码登录</span></a>

在这里插入图片描述

     .active span{
       border-bottom:3px solid #FF8198;
       color: #FF8198;
     }
     .active2 {
       display: none;
     }
(2)手机登录格式规定

双向绑定一个phone

<input type="tel" maxlength="11" placeholder="手机号" v-model="phone">
data(){
    return{
         phone:'',//手机号
    }
},
computed:{
   rightPhone(){
        return /^1\d{10}$/.test(this.phone)
   }
}

符合这个正则的才能点击‘获取验证码’按钮,prevent禁止默认行为
right_phone样式在手机号符合条件后按钮变色

<button :disabled="!rightPhone" 
		class="get_verification"
        :class="{right_phone: rightPhone}"
        @click.prevent="getCode">
    {{codeTime>0 ? `已发送(${codeTime}s)` : '获取验证码'}}
</button>

如图输入手机号前后按钮变色
在这里插入图片描述在这里插入图片描述

        data(){
            return{
              isActive:true,
              phone:'',//手机号
              codeTime: 0, // 验证码倒计时
            }
        },
        methods:{
            //启动倒计时
            getCode(){
                //如果当前没有计时
                if(!this.codeTime){
                    //发送ajax请求(向指定手机号发送验证短信)
                    this.codeTime = 30
                    const intercalId = setInterval(()=>{
                        this.codeTime--
                        if (this.codeTime<=0){
                            //停止计时
                            clearInterval(intercalId)
                        }
                    },1000)
                }
            },
        }

点击获取验证码后效果
在这里插入图片描述

(3)用户名密码登陆显示、*隐藏问题

添加样式,让输入框获取焦点后变色

     .login_content input:focus{
       border: 1px solid #FF8198;
     }

在这里插入图片描述
密码显示有两个状态text和password,我们要定义一个标识状态showPwd来区分这两种状态。注意这个v-model的内容要都是一样的input框内内容才一样

<input type="text" maxlength="8" placeholder="密码" v-if="showPwd" v-model="pwd">
<input type="password" maxlength="8" placeholder="密码" v-else v-model="pwd">
...
data(){
    return{
      ...
      code:'',//验证码
      name:'',//用户名
      pwd:'',//用户密码
      showPwd:false//是否显示密码
     }
},

接下来点击监听切换showPwd的值

<div class="switch_button" :class="showPwd?'on':'off'" @click="showPwd=!showPwd">
     <div class="switch_circle" :class="{right: showPwd}"></div>
     <span class="switch_text">{{showPwd ? '显示' : '隐藏'}}</span>
</div>
...
.on{
       background: #FF8198;;
   }
.off{
       background: white;
   }
   //小圆圈点完移动位置
.right{
       transform:translateX(30px);
} 

效果如下
在这里插入图片描述在这里插入图片描述

(4)前台表达验证,弹出提示框

在这里插入图片描述
新建一个弹窗组件
在这里插入图片描述

<!--登录页面提示弹框-->
<template>
  <div class="alert_container">
    <section class="tip_text_container">
      <div class="tip_icon"></div>
      <p class="tip_text">{{alertText}}</p>
      <div class="confrim" @click="closeTip">确认</div>
    </section>
  </div>
</template>

<script>
    export default {
    	//拿到父组件传过来的提示信息
        props: {
            alertText: String
        },

        methods: {
            closeTip () {
                // 分发自定义事件(事件名: closeTip)
                this.$emit('closeTip')
            }
        }
    }
</script>
css查看源代码

Login.vue中导入

 <alert-tip :alertText="alertText" v-show="showAlert" @closeTip="closeTip"/>

import AlertTip from "components/common/alertTip/AlertTip";

components: {AlertTip},

data(){
    return{
       ...
       showAlert:false,//是否显示校验弹框
       alertText:'',//提示文本
     }
},
methods:{
        ...
     //异步登录按钮
     alertMessage(alertText){
       this.showAlert = true
       this.alertText = alertText
      },
      login(){
        //前台表单验证
        if(this.isActive){//短信登录
           const {rightPhone,authCode,phone,code} = this
           if (!this.rightPhone){
              //手机号不正确
              this.alertMessage('手机号不正确');
           }else if (!this.authCode) {
              //验证必须是6位数字
               this.alertMessage('验证必须是6位数字');
           }
         }else{//密码登录
            const {name,pwd} = this
            if (!this.name) {
               //用户名必须指定
               this.alertMessage('用户名必须指定');
            }else if(!this.pwd) {
                //密码必须指定
                this.alertMessage('密码必须指定');
            }
         }
      },
      //弹框的“确定”按钮
      closeTip(){
          this.showAlert = false
          this.alertText = ''
      },
},
computed:{
     rightPhone(){
          return /^1\d{10}$/.test(this.phone)
     },
     authCode(){
          return /^\d{6}$/.test(this.code)
     }
}

三.商品详情用户评论图片点击放大

在这里插入图片描述
过几天补充,代码在src\components\content\commentPhoto\CommentPhoto.vue

四.购物车选择功能

在这里插入图片描述
过几天补充,代码在src\views\detail\childComps\selectRules.vue

五.购物车商品左滑删除 ̄□ ̄||还没做出来,购物车登陆有点问题,改完再写这个

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值