zoukankan      html  css  js  c++  java
  • 跟我一起做一个vue的小项目(APPvue2.5完结篇)

    先放一下这个完结项目的整体效果

    下面跟我我一起进行下面项目的进行吧~~~
    接下来我们进行的是实现header的渐隐渐显效果,并且点击返回要回到首页
    我们先看效果

    在处理详情页向下移动过程中,header页出现,我们使用的是监听滚动的方法,然后动态传入样式

    //srcpagesdetailcomponentsHeader.vue
    <template>
        <div>
            <router-link
                class="header-abs"
                tag="div"
                to="/"
                v-show="showAbs"
            >
                <div class="iconfont header-abs-back">
                    &#xe624;
                </div>
            </router-link>
            <div
                class="header-fixed"
                v-show="!showAbs"
                :style="opacityStyle"
            >
                <router-link to="/">
                    <div class="iconfont header-icon-back">&#xe624;</div>
                </router-link>
                景点详情
            </div>
        </div>
    </template>
    <script>
    export default {
      name: 'DetailHeader',
      data () {
        return {
          showAbs: true,
          opacityStyle: {
            opacity: 0
          }
        }
      },
      methods: {
        handleScroll () {
          console.log('滾動艦艇', document.documentElement.scrollTop)
          const top = document.documentElement.scrollTop
          if (top > 60) {
            let opacity = top / 140
            opacity = opacity > 1 ? 1 : opacity
            this.opacityStyle = {
              opacity
            }
            this.showAbs = false
          } else {
            this.showAbs = true
          }
        }
      },
      activated () {
        window.addEventListener('scroll', this.handleScroll)
      }
    }
    </script>
    <style lang="stylus" scoped>
    @import '~styles/varibles.styl';
    .header-abs
        position:absolute
        left:.2rem
        top:.2rem
        .8rem
        height:.8rem
        border-radius:.4rem
        background:rgba(0,0,0,0.8)
        text-align:center
        line-height:.8rem
        .header-abs-back
            color:#fff
            font-size:.4rem
    .header-fixed
        height :$headerHeight
        line-height:$headerHeight
        overflow:hidden
        position:fixed
        top:0
        left:0
        right:0
        text-align:center
        color:#fff
        background:$bgColor
        font-size:.32rem
        .header-icon-back
            .64rem
            text-align:center
            font-size:.4rem
            position:absolute
            top:0
            left:0
            color:#fff
    </style>
    
    
    //srcpagesdetailDetail.vue
    <template>
        <div>
    
            <detail-banner></detail-banner>
             <detail-header></detail-header>
             <div class="container"></div>
        </div>
    </template>
    <script>
    import DetailBanner from './components/Banner'
    import DetailHeader from './components/Header'
    export default {
      name: 'Detail',
      components: {
        DetailBanner,
        DetailHeader
      }
    }
    </script>
    <style lang="stylus" scoped>
    .container
      height:50rem
    </style>
    

    接下来我们对项目中,全局事件进行解绑
    当我们在header.vue组件中使用 window.addEventListener('scroll', this.handleScroll)的时候,
    我们会发现,在首页中滚动页面也会调用这个事件

    我们使用keep-alive在缓存过程中产生的钩子函数进行解决这个问题
    当在这些组件之间切换的时候都会请求一些请求过的数据,每次请求都会导致重复渲染影响性能。这些数据可以存到缓存。此时使用 activate:是在被包裹组件被激活的状态下使用的生命周期钩子,deactivated:在被包裹组件停止使用时调用
    我们的header组件中添加

    这样就解决了在首页中,也会进行滚动事件的Bug

    //header.vue
    <template>
        <div>
            <router-link
                class="header-abs"
                tag="div"
                to="/"
                v-show="showAbs"
            >
                <div class="iconfont header-abs-back">
                    &#xe624;
                </div>
            </router-link>
            <div
                class="header-fixed"
                v-show="!showAbs"
                :style="opacityStyle"
            >
                <router-link to="/">
                    <div class="iconfont header-icon-back">&#xe624;</div>
                </router-link>
                景点详情
            </div>
        </div>
    </template>
    <script>
    export default {
      name: 'DetailHeader',
      data () {
        return {
          showAbs: true,
          opacityStyle: {
            opacity: 0
          }
        }
      },
      methods: {
        handleScroll () {
          console.log('滾動艦艇', document.documentElement.scrollTop)
          const top = document.documentElement.scrollTop
          if (top > 60) {
            let opacity = top / 140
            opacity = opacity > 1 ? 1 : opacity
            this.opacityStyle = {
              opacity
            }
            this.showAbs = false
          } else {
            this.showAbs = true
          }
        }
      },
      activated () {
        window.addEventListener('scroll', this.handleScroll)
      },
      //   移除全局事件的影响
      dactivated () {
        window.removeEventListener('scroll', this.handleScroll)
      }
    }
    </script>
    <style lang="stylus" scoped>
    @import '~styles/varibles.styl';
    .header-abs
        position:absolute
        left:.2rem
        top:.2rem
        .8rem
        height:.8rem
        border-radius:.4rem
        background:rgba(0,0,0,0.8)
        text-align:center
        line-height:.8rem
        .header-abs-back
            color:#fff
            font-size:.4rem
    .header-fixed
        height :$headerHeight
        line-height:$headerHeight
        overflow:hidden
        position:fixed
        top:0
        left:0
        right:0
        text-align:center
        color:#fff
        background:$bgColor
        font-size:.32rem
        .header-icon-back
            .64rem
            text-align:center
            font-size:.4rem
            position:absolute
            top:0
            left:0
            color:#fff
    </style>
    

    接下来我们使用递归组件实现详情页的列表
    所谓递归组件是什么?就是在组件里面调用自身。
    我们先放一下实现的效果图

    先在detail页面中定义好数据格式,并将数据传递给子组件

    //list.vue
    <template>
        <div>
    
            <detail-banner></detail-banner>
             <detail-header></detail-header>
             <div class="container">
               <detail-list :list="list"></detail-list>
             </div>
        </div>
    </template>
    <script>
    import DetailBanner from './components/Banner'
    import DetailHeader from './components/Header'
    import DetailList from './components/List'
    export default {
      name: 'Detail',
      components: {
        DetailBanner,
        DetailHeader,
        DetailList
      },
      data () {
        return {
          list: [
            {
              title: '成人票',
              children: [
                {
                  title: '成人一馆联票',
                  children: [
                    {
                      title: '成人一馆联票-宝安连锁店销售'
                    },
                    {
                      title: '成人一馆联票-龙岗连锁店销售'
                    },
                    {
                      title: '成人一馆联票-坂田连锁店销售'
                    }
                  ]
                },
                {
                  title: '成人二馆联票'
                },
                {
                  title: '成人三馆联票'
                }
              ]
            },
            {
              title: '学生票',
              children: [
                {
                  title: '学生一馆联票'
                },
                {
                  title: '学生二馆联票'
                },
                {
                  title: '学生三馆联票'
                }
              ]
            },
            {
              title: '儿童票',
              children: [
                {
                  title: '儿童一馆联票',
                  children: [
                    {
                      title: '儿童一馆联票-宝安连锁店销售'
                    },
                    {
                      title: '儿童一馆联票-龙岗连锁店销售'
                    },
                    {
                      title: '儿童一馆联票-坂田连锁店销售'
                    }
                  ]
                },
                {
                  title: '儿童二馆联票'
                },
                {
                  title: '儿童三馆联票'
                }
              ]
            }
          ]
        }
      }
    }
    </script>
    <style lang="stylus" scoped>
    // .container
    //   height:50rem
    </style>
    
    //list.vue
    //srcpagesdetailcomponentsList.vue
    <template>
    <div>
        <div class="item" v-for="(item,index) of list" :key="index">
            <!-- 渲染最外层数据 -->
            <div class="item-title border-bottom">
                <span class="item-title-icon "></span>
                {{item.title}}
            </div>
            <!-- 如果最外层数据有子数据,就渲染子数据,递归调用本身 -->
            <div v-if="item.children" class="item-children">
                <detail-list :list="item.children"></detail-list>
            </div>
        </div>
    </div>
    </template>
    <script>
    
    export default {
      name: 'DetailList',
      props: {
        list: Array
      }
    }
    </script>
    <style lang="stylus" scoped>
    .item-title-icon
        display: inline-block;
         .36rem;
        height: .36rem;
        background: url(http://s.qunarzz.com/piao/image/touch/sight/detail.png) 0 -.45rem no-repeat;
        margin-right: .1rem;
        background-size: .4rem 3rem;
        vertical-align: middle;
    .item-title
        line-height:0.8rem
        font-size:.32rem
        padding:0 .2rem
    .item-children
        padding-left:0.6rem
    </style>
    

    接下来我们使用ajax来动态渲染数据
    我们在mock数据引入detail.json

    {
        "ret": true,
        "data": {
          "sightName": "大连圣亚海洋世界(AAAA景区)",
          "bannerImg": "http://img1.qunarzz.com/sight/p0/201404/23/04b92c99462687fa1ba45c1b5ba4ad77.jpg_600x330_bf9c4904.jpg",
          "commentsNum": 27,
          "gallaryImgs": [
            "http://img1.qunarzz.com/sight/p0/201404/23/04b92c99462687fa1ba45c1b5ba4ad77.jpg_800x800_70debc93.jpg",
            "http://img1.qunarzz.com/sight/p0/1709/76/7691528bc7d7ad3ca3.img.png_800x800_9ef05ee7.png"
          ],
          "categoryList": [
            {
              "title": "成人票",
              "children": [
                {
                  "title": "成人三馆联票",
                  "children": [
                    {
                      "title": "成人三馆联票 - 某一连锁店销售"
                    }
                  ]
                },
                {
                  "title": "成人五馆联票"
                }
              ]
            },
            {
              "title": "学生票"
            },
            {
              "title": "儿童票"
            },
            {
              "title": "特惠票"
            }
          ]
        }
      }
    

    在detail中引入数据

    //srcpagesdetailDetail.vue
    <template>
        <div>
    
            <detail-banner
              :sightName="sightName"
              :bannerImg="bannerImg"
              :bannerImgs="gallaryImgs"
            ></detail-banner>
             <detail-header ></detail-header>
             <div class="container">
               <detail-list :list="list"></detail-list>
             </div>
        </div>
    </template>
    <script>
    import DetailBanner from './components/Banner'
    import DetailHeader from './components/Header'
    import DetailList from './components/List'
    import axios from 'axios'
    export default {
      name: 'Detail',
      components: {
        DetailBanner,
        DetailHeader,
        DetailList
      },
      data () {
        return {
          sightName: '',
          bannerImg: '',
          gallaryImgs: [],
          list: [
          ]
        }
      },
      methods: {
        getDetailInfo () {
          axios.get('/api/detail.json?id=' + this.$route.params, {
            params: {
              id: this.$route.params.id
            }
          }).then(this.handleGetDataSucc)
        },
        handleGetDataSucc (res) {
          console.log('res', res)
          res = res.data
          if (res.ret && res.data) {
            const data = res.data
            console.log('data', data)
            this.sightName = data.sightName
            this.bannerImg = data.bannerImg
            this.gallaryImgs = data.gallaryImgs
            this.list = data.categoryList
          }
        }
      },
      mounted () {
        this.getDetailInfo()
      }
    }
    </script>
    <style lang="stylus" scoped>
    // .container
    //   height:50rem
    </style>
    

    将detail中传入的数据,传递给子组件

    //srcpagesdetailcomponentsList.vue
    <template>
    <div>
        <div class="item" v-for="(item,index) of list" :key="index">
            <!-- 渲染最外层数据 -->
            <div class="item-title border-bottom">
                <span class="item-title-icon "></span>
                {{item.title}}
            </div>
            <!-- 如果最外层数据有子数据,就渲染子数据,递归调用本身 -->
            <div v-if="item.children" class="item-children">
                <detail-list :list="item.children"></detail-list>
            </div>
        </div>
    </div>
    </template>
    <script>
    
    export default {
      name: 'DetailList',
      props: {
        list: Array
      }
    }
    </script>
    <style lang="stylus" scoped>
    .item-title-icon
        display: inline-block;
         .36rem;
        height: .36rem;
        background: url(http://s.qunarzz.com/piao/image/touch/sight/detail.png) 0 -.45rem no-repeat;
        margin-right: .1rem;
        background-size: .4rem 3rem;
        vertical-align: middle;
    .item-title
        line-height:0.8rem
        font-size:.32rem
        padding:0 .2rem
    .item-children
        padding-left:0.6rem
    </style>
    
    //srcpagesdetailcomponentsBanner.vue
    <template>
        <div>
          <div class="banner" @click="handleBannerClick">
              <img :src="bannerImg" alt="" class="banner-img">
              <div class="banner-info">
                <div class="banner-title">
                 {{this.sightName}}
                </div>
                <div class="banner-number">
                  <span class="iconfont">&#xe758;</span>
                  {{this.bannerImgs.length}}
                </div>
            </div>
          </div>
          <common-gallary
            :imgs="bannerImgs"
            v-show="showGallery"
            @close="handlegalleryClose"
          ></common-gallary>
        </div>
    </template>
    <script>
    import CommonGallary from 'common/gallary/Gallary'
    export default {
      name: 'DetailBanner',
      props: {
        sightName: String,
        bannerImg: String,
        bannerImgs: Array
      },
      data () {
        return {
          showGallery: false,
          imgs: [
            // 'http://img1.qunarzz.com/sight/p55/201211/04/fbcab3e5d6479ce893835fbb.jpg_r_800x800_6360f514.jpg',
            // 'http://img1.qunarzz.com/wugc/p180/201306/16/7f08e81624346b1693835fbb.jpg_r_800x800_5f03ad73.jpg'
          ]
        }
      },
      components: {
        CommonGallary
      },
      methods: {
        handleBannerClick () {
          this.showGallery = true
        },
        handlegalleryClose () {
          this.showGallery = false
        }
      }
    }
    </script>
    <style lang="stylus" scoped>
    .banner
      overflow:hidden
      height:0
      padding-bottom:55%
      position:relative
      .banner-img{
        100%
      }
      .banner-info
        display:flex
        position:absolute
        left:0
        right:0
        bottom:0
        line-height:0.6rem
        background-image:linear-gradient(top,rgba(0,0,0,0),rgba(0,0,0,0.8))
        color:#fff
        .banner-title
          flex:1
          font-size:.32rem
          padding:0 .2rem
        .banner-number
          padding:0 .4rem
          height:.32rem
          line-height:.4rem
          margin-top:.24rem
          border-radius:.2rem
          background:rgba(0,0,0,.8)
          font-size:0.24rem
          .iconfont
            font-size:.24rem
    
    </style>
    

    接下来我们给项目添加一些动画效果,点击我们的banner图片,进入gallery图片,给他一个动画的效果
    封装动画组件,transition里面的slot插槽,可以插入各种我们要进行动画处理的组件

    //srccommonfadeFadeAnimation.vue
    <template>
        <div>
            <transition>
                <slot></slot>
            </transition>
        </div>
    </template>
    <script>
    export default {
      name: 'FadeAnimation'
    }
    </script>
    <style lang="stylus" scoped>
    .v-enter,.v-leave-to
        opacity:0
    .v-enter-active,.v-leave-active
        transition: opacity 0.5s
    </style>
    

    我们在gallery中使用

    效果如下

    我已经将我跟着视频做的项目传到了github上面:https://github.com/JserJser/dailyPush/tree/master/travel
    恬不知耻向你们求一个star~~~~~

    后记:今天接到了一个电话,大抵是以前实习的时候的,问我同学,说是打我同学电话没有打到,然后问我有没有同他联系。有些唏嘘。
    想想毕业已经三年了。
    不知道自己对自己的未来有什么期许呢~你想成为什么样的人呢?是不是三年前自己想成为的人呢?
    好好看视频,好好学习,好好掌握项目吧~我呀, 还差的很远呢~

    第十部分主要讲解的是项目接口联调部分,将mock中的数据放入XAMPP中,还有如何手机真机测试,以及如何打包数据,这部分我就是看了而已,没有实际操作。真实数据是与后端联调。视频的老师给了有些学习vue的建议,可以多多研究vue的一些常见组件的源码,还有研究vue的源码,以及,学习vue的ssr服务端的渲染问题等。

    还有很多东西不会,要精通,要很厉害啊~~~

  • 相关阅读:

    入门动态规划问题
    AC自动机
    KMP算法
    [OpenGL]用鼠标拖拽图形移动
    HDU-2222 Keywords Search
    Trie
    Manacher算法
    linux环境搭建
    Android Studio使用JNI和NDK进行开发
  • 原文地址:https://www.cnblogs.com/smart-girl/p/11190335.html
Copyright © 2011-2022 走看看