vue进阶 --- 实例演示

  这篇博客将通过一个实例来对vue构建项目的过程有一个了解。

  主要用到的知识点如下所示:

  1. vue-router 2.0路由配置
  2. router-view 和 router-link的使用
  3. transition控制页面的跳转
  4. .vue后缀的单文件组件

 

调整目录结构

  我们先用vue-cli构建项目,然后将 src 目录下的APP.vue删除,然后添加一个pages文件夹,这个文件夹的目的在于存放页面, 页面也是组件,但是在components下的不是一个完整的页面,而pages下的组件是一个页面组件。这样结构更清晰一些。

  

 

.vue后缀的单文件组件

  

  这就是我们最终希望做出来的效果图,其中的组件包括homeHeader和list,他们都是组件,都可以用.vue文件来表示。

  然后我们把HomeHeader.vue和DetailHeader.vue以及List.vue放在components下,因为他们都是一个页面的一部分。 接着把 Home.vue 和 Detail.vue 组件放在pages下,因为这两个是页面。 目录结构如下所示:

  

  OK! 组件的架构大体就是这样的了,接着,我们通过List.vue来看看单页面组件是如何的。

  提示: 写vue文件时,最好先安装vue高亮插件,这样可以提高我们的编码效率。

  

<template>
  <li class="sec-li">
    <router-link to="/detail" class="link">
      <div class="img-wrap">
        <img src="../assets/img/book.jpg" alt="img">
      </div>
      <p class="book-name">{{title}}</p>
      <p class="book-price">¥{{price}}元</p>
    </router-link>
  </li>
</template>

<style scoped>
  .sec-li {
    float: left;
    width: 50%;
    margin-bottom: 0.1rem;
  }
  .link {
    display: block;
    padding: 0.3rem 0;
    text-align: center;
  }
</style>

<script>
  export default {
    props: ['price', 'title']
  }
</script>
  • 其中template就是用于存放html的地方,注意: template下只能有一个标签。 和react是类似的。
  • style是来用存放css样式的,也可以使用sass和less,只要安装相应的包来编译即可。 其中的scoped属性可以让css样式只作用在这个组件之中,这样就不会影响到其他的组件了。
  • script中的js用了es6的语法,导出了对象,其中的props用于父组件像子组件传递数据。

 

使用vue-router2.0

  通过vue的目的是创建单页面应用,所以就没有了页面的跳转,而是组件的跳转,要实现组件的跳转,我们就要用到vue-router了。

  首先,我们可以看到packag.json中是没有vue-router的,所以我们需要自己来安装vue-router,即npm install vue-router --save。 

  router-view是用来实现路由内容的地方,在这里,会通过路由不停地切换routr-view中的内容,这也就是vue创建单页面应用的内在。 

  (注意:下面这段代码是处在根目录下的index.html中的一部分,也就是说,整个页面就这么一个html文件,所以称为单页面应用)

<div id="app">
  <router-view></router-view>
</div>

  router-link相当于a标签,在点击router-link下的元素的时候,我们就可以将to所指向的组件渲染到router-view中。 

   

 

跳转页面动画

  另外,我们在根目录下的index.html中可以设置跳转动画如下所示:

      /* 跳转页面动画 */
.slide-enter,  
      .slide_back-enter {  
          position: absolute;  
          width: 100%;  
      }  
      .slide-leave,  
      .slide_back-leave {  
          position: absolute;  
          width: 100%;  
      }  
      .slide-enter-active,  
      .slide_back-enter-active {  
          transition: all 0.3s linear;  
      }  
      .slide-leave-active {  
          position: absolute;  
          transition: all 0.3s linear;  
          transform: translate(-100%);  
      }  
      .slide-enter{  
          transform: translateX(100%);  
      }  
      .slide_back-leave-active {  
          position: absolute;  
          transition: all 0.3s linear;  
          transform: translate(100%);  
      }  
      .slide_back-enter {  
          transform: translateX(-100%);  
      }  

 

 

 

 

 

 最后贴上代码:

 1.根目录下的index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
    <title>first-vue</title>
    <style type="text/css">
        * { margin: 0; padding: 0; }
        html,body { background: #eee; }
        ul,li { list-style: none; }
        a { text-decoration: none; }
        img { vertical-align: middle; }
        /* 跳转页面动画 */
        .slide-enter,
        .slide_back-enter {
            position: absolute;
            width: 100%;
        }
        .slide-leave,
        .slide_back-leave {
            position: absolute;
            width: 100%;
        }
        .slide-enter-active,
        .slide_back-enter-active {
            transition: all 0.3s linear;
        }
        .slide-leave-active {
            position: absolute;
            transition: all 0.3s linear;
            transform: translate(-100%);
        }
        .slide-enter{
            transform: translateX(100%);
        }
        .slide_back-leave-active {
            position: absolute;
            transition: all 0.3s linear;
            transform: translate(100%);
        }
        .slide_back-enter {
            transform: translateX(-100%);
        }
    </style>
  </head>
  <body>
    <div id="app">
        <transition :name="transitionName">
            <router-view></router-view>
        </transition>
    </div>

    <script type="text/javascript">
        // 计算html的font-size
        (function(){
            function resizeBaseFontSize(){
                var rootHtml = document.documentElement,
                    deviceWidth = rootHtml.clientWidth;
                if(deviceWidth > 640){
                    deviceWidth = 640;
                }
                rootHtml.style.fontSize = deviceWidth / 7.5 + "px";
            }
            resizeBaseFontSize();
            window.addEventListener("resize", resizeBaseFontSize, false);
            window.addEventListener("orientationchange", resizeBaseFontSize, false);
        })();
    </script>
  </body>
</html>
View Code

  这里的代码很简单,就是设置了transition和移动端字体的设置。其中 transition组件是用来控制页面切换的动画用的,transitionName绑定到的是main.js中的data中的transitionName字段。

2. src目录下的main.js代码如下:

// main.js

// 导入Vue,这个是必需的,在使用Vue之前,必须先导入
import Vue from 'vue'

// 导入 vue-router,并使用
import VueRouter from 'vue-router'
Vue.use(VueRouter)

// 导入 pages 下的 Home.vue 
import Home from './pages/Home'
import Detail from './pages/Detail'

// 定义路由配置
const routes = [
    {
        path: '/',
        component: Home
    },
    {
        path: '/detail',
        component: Detail
    }
]

// 创建路由实例
const router = new VueRouter({
    routes
})

// 创建 Vue 实例
new Vue({
  el: '#app',
  data(){
      return {
          transitionName: 'slide'
      }
  },
  router,
  watch: {
      // 监视路由,参数为要目标路由和当前页面的路由
      '$route' (to, from){
          const toDepth = to.path.substring(0, to.path.length-2).split('/').length
          // 官方给出的例子为 const toDepth = to.path.split('/').length 由于现在只有两个路由路径'/'和'/detail'
          // 按照官方给的例子,这两个路由路径深度都为 2 ,所以,这里稍作调整,不知道有什么不妥
          // 但目前在这个demo中能正常运行,如果知道更好的方法,欢迎留言赐教
          const fromDepth = from.path.substring(0, from.path.length-2).split('/').length
          this.transitionName = toDepth < fromDepth ? 'slide_back' : 'slide'
          // 根据路由深度,来判断是该从右侧进入还是该从左侧进入
      }
  }
})
View Code

 这里main.js首先引入了vue和vue-router,然后对router进行了设置,将router挂载到实例上,最后的watch路由实际上就是用来正确实现动画的效果的。不用也是可以的。

3.  HomeHeader.vue如下:

<template>  
    <header class="header">  
        <div class="header_inner">  
            <div class="header_cont">主页</div>  
        </div>  
    </header>  
</template>  
  
<style>  
    .header {  
        height: 0.88rem;  
    }  
    .header_inner {  
        position: fixed;  
        top: 0;  
        left: 0;  
        right: 0;  
        z-index: 99;  
        max-width: 640px;  
        height: 0.88rem;  
        box-sizing: border-box;  
        margin: 0 auto;  
        padding: 0 0.24rem;  
        border-bottom: 0.02rem solid #80ccd6;  
        background-color: #fff;  
    }  
    .header_cont {  
        text-align: center;  
        padding: 0 0.4rem;  
        line-height: 0.86rem;  
        font-size: 15px;  
        overflow: hidden;  
        text-overflow: ellipsis;  
        white-space: nowrap;  
    }  
</style>  
View Code

 

4.  List.vue如下:

<!-- List.vue -->
<template>
    <li class="sec_li">
        <router-link to="/detail" class="lp_li_a">
            <div class="lp_li_imgWrap">
                <img src="../assets/img/lp_01.jpg" alt="">
            </div>
            <p class="lp_li_name">{{ title }}</p>
            <p class="lp_li_price">¥{{ price }}元</p>
        </router-link>
    </li>
</template>

<style scoped>
    .sec_li {
        float: left;
        width: 50%;
        margin-bottom: 0.1rem;
    }
    .lp_li_a {
        display: block;
        padding: 0.3rem 0;
        margin: 0 0.05rem;
        text-align: center;
        background: #fff;
    }
    .lp_li_imgWrap {
        padding: 0.24rem 0;
    }
    .lp_li_imgWrap > img {
        width: auto;
        height: 2.3rem;
    }
    .lp_li_name {
        height: 0.5rem;
        line-height: 0.5rem;
        font-size: 16px;
        color: #333;
    }
    .lp_li_price {
        height: 0.5rem;
        line-height: 0.5rem;
        font-size: 16px;
        color: #fb3b3b;
    }
</style>

<script>
    export default {
        props: ['price', 'title']
    }
</script>
View Code

 

5. DetailHeader.vue如下:

<!-- DetailHeader.vue -->  
<template>  
    <header class="header">  
        <div class="header_inner flexWrap">  
            <div   
                id="header_btn_nav"   
                class="header_btn header_btn_back"  
                v-on:click="goBack"  
                >返回</div>  
            <div class="header_cont flex">详情</div>  
            <div class="header_btn header_btn_cart"></div>  
        </div>  
    </header>  
</template>  
  
<style>  
    .flexWrap {  
        display: -webkit-flex;  
        display: flex;  
    }  
    .flex {  
        flex: 1;  
    }  
    .header {  
        height: 0.88rem;  
    }  
    .header_inner {  
        position: fixed;  
        top: 0;  
        left: 0;  
        right: 0;  
        z-index: 99;  
        max-width: 640px;  
        height: 0.88rem;  
        box-sizing: border-box;  
        margin: 0 auto;  
        padding: 0 0.24rem;  
        border-bottom: 0.02rem solid #80ccd6;  
        background-color: #fff;  
    }  
    .header_btn {  
        width: 0.5rem;  
        height: 100%;  
        background-repeat: no-repeat;  
    }  
    .header_btn_back {  
        line-height: 0.86rem;  
    }  
    .header_cont {  
        text-align: center;  
        padding: 0 0.4rem;  
        line-height: 0.86rem;  
        font-size: 15px;  
        overflow: hidden;  
        text-overflow: ellipsis;  
        white-space: nowrap;  
    }  
    .header_btn:active {  
        opacity: 0.7;  
    }  
</style>  
<script>  
    export default {  
        methods: {  
            goBack(){  
                window.history.back();  
            }  
        }  
    }  
</script>  
View Code

 

6. Home.vue如下:

<!-- Home.vue -->  
<template>  
    <div class="container">  
        <!-- 由于html不区分大小写,所以js中驼峰命名方式在html中要改成用短横线连接的形式 -->  
        <home-header></home-header>  
        <div class="content">  
            <ul class="cont_ul">  
                <list  
                    v-for="item in items"  
                    :price="item.price"  
                    :title="item.title">  
                </list>  
            </ul>  
        </div>  
    </div>  
</template>  
<style>  
    .container {  
        max-width: 640px;  
        margin: 0 auto;  
        overflow-x: hidden;  
    }  
    .cont_ul {  
        padding-top: 0.05rem;  
        margin: 0 -0.12rem;  
    }  
    .cont_ul:after {  
        content: "";  
        display: block;  
        width: 0;  
        height: 0;  
        clear: both;  
    }  
</style>  
<script>  
    // 导入要用到的子组件  
    import HomeHeader from '../components/HomeHeader'  
    import List from '../components/List'  
  
    export default {  
        data () {  
            return {  
                items: [  
                    { price: "129.00", title: "大学" },  
                    { price: "256.00", title: "中庸" },  
                    { price: "399.00", title: "论语" },  
                    { price: "998.00", title: "孟子" },  
                    { price: "99.00", title: "道德经" },  
                    { price: "89.00", title: "老子" },  
                    { price: "188.00", title: "金刚经" },  
                    { price: "209.00", title: "易筋经" },  
                ]  
            }  
        },  
        // 在components字段中,包含导入的子组件  
        components: {  
            HomeHeader,  
            List  
        }  
    }  
</script>  
View Code

 

这里值得注意的是: 我们需要使用import导入子组件。

7. Detail.vue如下:

<!-- Detail.vue -->  
<template>  
    <div class="detail">  
        <detail-header></detail-header>  
        <img src="../assets/img/lp_01.jpg" alt="">  
        <p>崇贤馆始置唐代太宗朝。1999年,李克先生及志同道合者复兴其宗旨。以积累、传播中华优秀传统文化,提供全新国学体验馆为宏愿。</p>  
        <p>其间,在季羡林、冯其庸等国学大师及著名文史学家傅璇琮、毛佩琦先生指导下,耕注先贤原典,以宣纸线装精品形式呈奉世人。作为一家国学传播机构,崇贤馆始终致力于中华传统文化的传承和推广,以古籍线装宣纸书的形式,对浩繁的史海巨著进行经典复刻。不仅如此,崇贤馆还延请了傅璇琮、毛佩奇等诸位在国学界内享有盛誉的专家和学者担纲学术顾问,以精益求精的治学态度面对每一部崇贤馆的作品,使之成为学术史中无尚的精品。</p>  
    </div>  
</template>  
<style>  
    .detail {  
        padding: 0.24rem;  
        font-size: 12px;  
    }  
    img {  
        display: block;  
        width: 80%;  
        margin: 0 auto 0.2rem;  
    }  
    p {  
        font-size: 14px;  
        line-height: 0.5rem;  
        text-align: justify;  
        padding-bottom: 0.24rem;  
    }  
</style>  
<script>  
    import DetailHeader from '../components/DetailHeader'  
  
    export default {  
        components: {  
            DetailHeader  
        }  
    }  
</script>  
View Code

 

同样,这里作为页面组件,我们也需要导入子组件。

 

注意:其中的 npm run dev 是在开发环境中使用, npm run build是在生产环境中使用。

 

  

 

  

 

 

 

 

 

 

参考文章

这里有vue项目和资料的汇总:https://segmentfault.com/q/1010000007073989/a-1020000007074331

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值