构建第一个Vue项目
之前的文章已经提到了,如何配置Vue的开发环境了,现在开始做一个简单的项目,主要就是介绍怎么使用组件、路由以及通信等,大家就不要吐槽UI和样式的问题。 这是我的src目录,component是放公用组件的,page是页面,static是放静态资源文件 首先先来看看main.js我们需要在这里引入我们需要用到的组件和库// The Vue build version...
之前的文章已经提到了,如何配置Vue的开发环境了,现在开始做一个简单的项目,主要就是介绍怎么使用组件、路由以及通信等,大家就不要吐槽UI和样式的问题。
这是我的src目录,component是放公用组件的,page是页面,static是放静态资源文件
首先先来看看main.js
我们需要在这里引入我们需要用到的组件和库
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue' /* 这里是引入vue文件 */
import App from './App' /* 这里是引入同目录下的App.vue模块 */
import router from './router' /* 这里是引入vue的路由 */
import VueResource from 'vue-resource'
Vue.use(VueResource)
/* eslint-disable no-new */
new Vue({
el: '#app', /* 定义作用范围就是index.html里的id为app的范围内 */
router, /* 引入路由 */
components: { App }, /* 注册引入的组件App.vue */
template: '<App/>' /* 给Vue实例初始一个App组件作为template 相当于默认组件 */
})
我们先来做头部的导航栏,创建一个headerNav.vue
<template lang="html">
<div class="header">
<span class="back-btn" @click="goBack()">←</span>
<h6 class="header-name" v-text="hName"></h6>
</div>
</template>
<script>
export default {
return {
hName:'首页',
},
methods:{
goBack(){
history.back(-1);
}
},
}
</script>
<style lang="css" scoped>/* scoped的意思是这里的样式只对当前页面有效不会影响其他页面,还有可以设置lang="scss"就是支持css预编译,也就是支持sass或者less */
.header{ width: 100%; height: 2rem; padding: 0 2.6rem; position: fixed; left: 0; top: 0; background-color: #42b983; color: #ffffff; } .header-name { width: 80%; margin: 0 10%; text-align: center; line-height: 2rem; font-size: .8rem; } .back-btn{ display: inline-block; position: absolute; top: 0; left: 0; width: 2.6rem; height: 2rem; line-height: 2rem; font-size: 1.1rem; text-align: center; }
</style>
有头就要有尾,footerNav.vue
<template lang="html">
<div class="footer">
<ul class="footer-con b2 ui-transition">
<li class="g1">1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
</div>
</template>
<script>
export default {
data(){
},
}
</script>
<style lang="css">
.footer { height: 2rem; width: 100%; position: fixed; bottom: 0; left: 0; background-color: #fff; } .footer::before{ content: ''; display: block; position: absolute;top: 0;left: 0; width: 100%;height: 1px; background: #e0e0e0; } .footer-con li { float: left; width: 25%; height: 2rem; line-height: 2rem; font-size: .8rem; text-align: center; -webkit-transition: ease 0.25s; -moz-transition: ease 0.25s; -ms-transition: ease 0.25s; -o-transition: ease 0.25s; transition: ease 0.25s; } .footer-con li:active { background-color: rgb(248, 248, 248); } .footer-con:after { content: ''; display: block; clear: both; width: 0; height: 0; }
</style>
接下来就是App.vue
<template lang="html">
<div class="container">
<!-- 引入的header组件 -->
<headerNav></headerNav>
<div class="content">
<router-view></router-view> <!-- 这里是展示来自路由页面数据的 -->
</div>
<!-- 引入的footer组件 -->
<footerNav></footerNav>
</div>
</template>
<script>
/* 引用组件 */
import headerNav from "@/components/headerNav";
import footerNav from "@/components/footerNav";
export default {
data() {
/* 这里是数据,注意数据一定要放data中然后用return返回 */
return {
};
},
components: {
headerNav,
footerNav,
},
mounted(){},
};
</script>
<style lang="css">
blockquote,body,dd,dl,dt,fieldset,figure,h1,h2,h3,h4,h5,h6,hr,html,iframe,legend,li,ol,p,pre,textarea,ul{margin:0;padding:0}html{overflow-y:scroll}body{font-family:Helvetica Neue,Helvetica,PingFang SC,Hiragino Sans GB,Microsoft YaHei,SimSun,sans-serif;font-size:14px;-webkit-font-smoothing:antialiased;background-color:#fff;position:relative}ul,ol{list-style:none}a{text-decoration:none;}em{font-style:normal}*,:after,:before{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;outline:0 none} a{color: inherit} .clear::after{visibility:hidden;display:block;font-size:0;content:" ";clear:both;height:0}.clear{*zoom:1} .ui-transition { -webkit-transition: ease 0.35s; -moz-transition: ease 0.35s; -ms-transition: ease 0.35s; -o-transition: ease 0.35s; transition: ease 0.35s; } .b1{color: #646262;}.b2{color: #555454;} .o1{color: #f16f47;} .r1{color: rgb(233, 10, 103)} .g1{color: #42b983} .bl{color: #2c3e50;} body{background-color: rgba(233, 233, 233, .5);} .container { width: 100%; padding: 2rem 0; position: relative; }
</style>
现在应该就能看到一个只有头尾,中间空白的页面
所以我们要开始丰富内容,movieList.vue
<template lang="html">
<ul class="cont-ul clear">
<li class="cont-li b1" v-for="item in movieList">
<div class="img-con">
<img class="movie-img" :src="item.images.large">
</div>
<div class="movie-msg clear">
<p class="movie-name">{{item.title}}</p>
<p class="movie-price r1">
<span>评分 </span>{{item.rating.average}}</p>
</div>
</li>
</ul>
</template>
<script>
export default {
data() {
return {
movieList: [],
};
},
mounted() {
// 这个是vue的钩子函数,当new Vue()实例创建完毕后执行的函数,关于vue的生命周期,可以去官网查看详情
// 这里我用的是豆瓣的一个公共接口
this.$http
.jsonp("https://api.douban.com/v2/movie/top250?count=10")
.then(res => {
this.movieList = res.data.subjects;
res = null;
})
.catch(error => {
console.log("http error:" + error);
});
},
};
</script>
<style lang="css" scoped>
.cont-ul { padding: 0.5rem 0.5rem 0 0.5rem; } .cont-li { margin-bottom: 0.4rem; width: calc(50% - 0.2rem); float: left; overflow: hidden; border-radius: 4px; background: #ffffff; box-shadow: 1px 1px 4px rgba(131, 131, 131, 0.5); } .cont-li:nth-child(2n-1) { margin-right: 0.4rem; } .img-con { height: 12rem; overflow: hidden; } .movie-img { float: left; width: 100%; } .movie-msg { width: 100%; padding: 0.3rem 0.5rem; } .movie-name { line-height: 1.2rem; font-size: 0.8rem; } .movie-price { text-align: right; line-height: 1rem; font-size: 0.7rem; font-weight: 400; } .movie-price span { font-size: 0.5rem; }
</style>
好了,现在我们就把第一个页面做出来了,很简单对吧。接下来就是详情页了,但是在这之前我们还需要定义跳转方式,详细请看我另一篇文章→ Vue 路由跳转方式 和 路由跳转时传参
下面就是修改后的movieList.vue,增加了goToInfo的跳转方法
<template lang="html">
<ul class="cont-ul clear">
<li class="cont-li b1" v-for="item in movieList" @click="goToInfo(item)">
<div class="img-con">
<img class="movie-img" :src="item.images.large">
</div>
<div class="movie-msg clear">
<p class="movie-name">{{item.title}}</p>
<p class="movie-price r1">
<span>评分 </span>{{item.rating.average}}</p>
</div>
</li>
</ul>
</template>
<script>
export default {
data() {
return {
movieList: [],
};
},
mounted() {
// 这个是vue的钩子函数,当new Vue()实例创建完毕后执行的函数,关于vue的生命周期,可以去官网查看详情
// 这里我用的是豆瓣的一个公共接口
this.$http
.jsonp("https://api.douban.com/v2/movie/top250?count=10")
.then(res => {
this.movieList = res.data.subjects;
console.log(res.data.subjects);
res = null;
})
.catch(error => {
console.log("http error" + error);
});
},
methods:{
goToInfo(info){
//这里因为我想把整个对象传给详情页,所以使用的是session
sessionStorage.setItem('movieInfo',JSON.stringify(info));
this.$router.push({
path:'/movieInfo', //路径
name:'movieInfo', //配置路由时的name
});
}
}
};
</script>
其实正常来说,我们应该是在movieList.vue 通过路由query的方式把id传给详情页,但是因为没有接口的原因所以我用了session
然后就是详情页了,movieInfo.vue
<template lang="html">
<div class="info-con" v-if="info">
<img class="movie-img" :src="info.images.large">
<p class="movie-name">{{info.title}}<span>{{' ('+info.year+')'}}</span></p>
<p>
类型:
<span v-for="genre in info.genres">{{genre+' / '}}</span>
</p>
<p class="o1">评分:{{info.rating.average}}</p>
</div>
</template>
<script>
export default {
data() {
return {
info:'',
};
},
mounted() {
let info = sessionStorage.getItem('movieInfo')||0;
if(info){
this.info = JSON.parse(info);
}
}
};
</script>
<style lang="css" scoped>
.info-con { padding: 1rem; margin: 1rem; border-radius: 8px; background: #ffffff; box-shadow: 1px 1px 6px rgba(131, 131, 131, 0.5); overflow: hidden; } .info-con img{ width: 100%; } .info-con .movie-name { margin-top: .5rem; text-align: left; line-height: 2rem; font-size: .9rem; font-weight: 400; } .movie-name span{color: grey;font-size: .8rem;}
</style>
在运行之前,我们还需要在router文件夹下的index.js文件里配置好路由
import Vue from 'vue'
import Router from 'vue-router' /* 引用vue路由模块,并赋值给变量Router */
import movieList from '@/page/movieList.vue'
import movieInfo from '@/page/movieInfo.vue'
Vue.use(Router) /* 使用路由 */
export default new Router({
routes: [ /* 进行路由配置,规定“/”引入到组件 */
{
path: '/',//默认页面
name: 'movieList',
component: movieList /* 注册组件 */
},
{
path: '/movieList',
name: 'movieList',
component: movieList
},
{
path: '/movieInfo',
name: 'movieInfo',
component: movieInfo
}
]
})
现在在控制台输入 npm run dev 我们就可以看到整个效果了
但是我们希望头尾的导航栏能根据我们的页面显示不同的信息,这时候就需要用到通信功能了,详情→ Vue组件通信
首先我们在movieList.vue 的mounted里给App.vue传一个title和footer的index
mounted() {
this.$emit('setNav',['豆瓣评分Top250电影',1]);
// 这个是vue的钩子函数,当new Vue()实例创建完毕后执行的函数
this.$http
.jsonp("https://api.douban.com/v2/movie/top250?count=10")
.then(res => {
this.movieList = res.data.subjects;
res = null;
})
.catch(error => {
console.log("http error" + error);
});
}
同样的在movieInfo.vue 的mounted里也给App.vue传当前的电影名和footer的index
mounted() {
let info = sessionStorage.getItem('movieInfo')||0;
if(info){
this.info = JSON.parse(info);
}
this.$emit('setNav',[this.info.title,2]);
}
然后在App.vue里通过setNav函数接受子组件的参数,并把这两个参数传递给headerNav和footerNav
<template lang="html">
<div class="container">
<!-- 引入的header组件 -->
<headerNav :navTitle="navTitle"></headerNav>
<div class="content">
<router-view v-on:setNav="setNav"></router-view> <!-- 这里是展示来自路由页面数据的 -->
</div>
<!-- 引入的footer组件 -->
<footerNav :nowTab="nowTab"></footerNav>
</div>
</template>
<script>
/* 引用组件 */
import headerNav from "@/components/headerNav";
import footerNav from "@/components/footerNav";
export default {
data() {
/* 这里是数据,注意数据一定要放data中然后用return返回 */
return {
navTitle:'',
nowTab:1,
};
},
components: {
headerNav,
footerNav,
},
mounted(){},
methods:{
setNav(seterArr){
this.navTitle = seterArr[0];
this.nowTab = seterArr[1];
}
}
};
</script>
然后headerNav和footerNav只需要通过props接收就行了
<template lang="html">
<div class="header">
<span class="back-btn" @click="goBack()">←</span>
<h6 class="header-name" v-text="navTitle"></h6>
</div>
</template>
<script>
export default {
props: {navTitle:String},
methods:{
goBack(){
history.back(-1);
}
},
}
</script>
<template lang="html">
<div class="footer">
<ul class="footer-con b2 ui-transition">
<router-link to="/movieList">
<li :class="{g1:nowTab==1}">1</li>
</router-link>
<li :class="{g1:nowTab==2}">2</li>
<li :class="{g1:nowTab==3}">3</li>
<li :class="{g1:nowTab==4}">4</li>
</ul>
</div>
</template>
<script>
export default {
props: {nowTab:Number},
}
</script>
这里我会给底部导航栏根据nowTab设置class以显示不同的颜色
到这里这个简单的项目就完成了,应该没有漏掉什么东西,如果不能成功的跑起来,欢迎评论问我。
更多推荐
所有评论(0)