vue进阶 --- 实例演示

vue

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

转自http://www.cnblogs.com/zhuzhenwei918/p/6822964.html

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

  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>

  这里的代码很简单,就是设置了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'

// 根据路由深度,来判断是该从右侧进入还是该从左侧进入

}

}

})

 这里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>

 

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>

 

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>

 

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>

 

这里值得注意的是: 我们需要使用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>

 

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

 

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

 

  

 

  

 

 

 

 

 

 

参考文章

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

以上是 vue进阶 --- 实例演示 的全部内容, 来源链接: utcz.com/z/377318.html

回到顶部