vue2.0+webpack高仿饿了么商家页面

阅读: 评论:0

vue2.0+webpack高仿饿了么商家页面

vue2.0+webpack高仿饿了么商家页面

vue2.0+webpack高仿饿了么商家页面

一、项目说明

1. 项目技术
  • vue cli
  • vue
  • ES6
  • vue-resource
  • vue-router
  • better-scroll
  • sass
  • webpack
  • git
2. 项目地址:Github
3. 项目演示
  • sell
  • 手机扫描二维码

二、项目初始化

1. 使用vue官网给出的命令行工具
# 全局安装 vue-cli
$ npm install --global vue-cli
# 创建一个基于 webpack 模板的新项目
$ vue init webpack my-project(sell)
# 安装依赖,走你
$ cd my-project(sell)
$ npm install
$ npm run dev
2. 初始项目目录(小部分修改)
├── build              // 构建服务和webpack配置
├── config             // 项目不同环境的配置
├── index.html         // 项目入口文件
├── package.json       // 项目配置文件
├── src                // 生产目录
│   ├── common        // 公共的css js 资源
│   ├── components    // 各种组件
│   ├── router        // 路由
│   ├── App.vue       // 主页面 
│   └── main.js       // Webpack 预编译入口
3. 完整项目目录

接下来开始项目的开发

1. webpack 预编译入口文件 main.js
import Vue from 'vue';
import App from './App';
import router from './router';
// index.js会自动寻找到,也可以写全(import router from './router/index.js')
import VueResource from 'vue-resource';
import './common/styles/index.scss';/* 设置为 false 以阻止 vue 在启动时生成生产提示 */
fig.productionTip = false;Vue.use(VueResource); // 全局注册/* eslint-disable no-new */
new Vue({el: '#app',router,components: { App },template: '<App/>'
});
2. 主页面 App.vue
(1)先上代码
<template><div id="app"><v-header v-bind:seller="seller"></v-header><div class='tab border-b-1px'><div class='item-tab'><router-link to="/goods">商品</router-link></div><div class='item-tab'><router-link to="/ratings">评论</router-link></div><div class='item-tab'><router-link to="/seller">商家</router-link></div></div><!--主要用于保留组件状态或避免重新渲染--><keep-alive><router-view v-bind:seller="seller"></router-view></keep-alive></div>
</template><script>
import header from './components/header/header.vue';
import {urlParse} from './common/js/util.js';
// import data from './common/json/data.json';
const ERR_OK=0;
export default {name:'App',data () {return {seller:{id: (() => {let queryParam=urlParse();return queryParam.id;})()}};},created (){this.$('/api/seller?id=' + this.seller.id).then(response => {if(===ERR_OK){// 用于对象的合并 , Object.assign方法的第一个参数是目标对象,后面的参数都是源对象。this.seller=Object.assign({},this.seller,response.data.data);}else{console.log('no data');}});// this.seller=Object.assign({},this.seller,data.seller);},components:{'v-header':header}
};
</script><style lang="scss" scoped>@import "./common/styles/mixin.scss";#app{.tab{display:flex;width:100%;height:40px;line-height:40px;font-size:14px;color:rgb(240,20,20);@include border-b-1px(rgba(7,17,27,0.1));.item-tab{flex:1;text-align:center;.active{color:rgb(240,20,20);}}}}
</style>
(2)代码关键说明
主页面的结构
  • v-header 组件
  • 路由渲染组件
功能实现
1) 获取mock数据
  • 在入口文件中main.js 中, 引入 vue-resource ,并全局注册
import VueResource from 'vue-resource';Vue.use(VueResource); // 全局注册
  • App.vue 中 ,使用生命周期钩子 created , 在实例创建完成后被立即调用,请求数据。且需要在data 选项中返回数据对象(其中的id 放在后面介绍)。
data () {return {seller:{id: (() => {let queryParam=urlParse();return queryParam.id;})()}};},
created (){this.$('/api/seller?id=' + this.seller.id).then(response => {if(===ERR_OK){// 用于对象的合并 , Object.assign方法的第一个参数是目标对象,后面的参数都是源对象。this.seller=Object.assign({},this.seller,response.data.data);}else{console.log('no data');}});// this.seller=Object.assign({},this.seller,data.seller);},

当一个组件被定义,data 必须声明为返回一个初始数据对象的函数,因为组件可能被用来创建多个实例。如果 data 仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象!通过提供 data 函数,每次创建一个新实例后,我们能够调用 data 函数,从而返回初始数据的一个全新副本数据对象。

3) 在父组件中使用子组件
  • 首先,引入子组件
import header from './components/header/header.vue';
  • 然后 ,父组件 通过 components 选项声明
components:{'v-header':header
}
  • 使用很简单
<v-header v-bind:seller="seller"></v-header>
4) 父子组件的数据传递
  • 父组件 App.vue:通过 v-bind:seller=”seller” 将数据传递
  • 子组件 header.vue :通过 props 接收(只显示核心代码)
<template>
...
</template><script>
export default{
...props: {seller:{type:Object,required:true}}
...
};
</script><style lang="scss" scoped>
...
</style>
这样, 在子组件中就可以使用父组件的数据了
5) 路由
  • 首先我们需要将 路由的定义 单独放在一个文件中 index.js
import Vue from 'vue';
import Router from 'vue-router';
import goods from '@/components/goods/goods.vue';
import ratings from '@/components/ratings/ratings.vue';
import seller from '@/components/seller/seller.vue';Vue.use(Router);const routes=[{path: '/',redirect: 'goods', // 重定向},{path: '/goods',component: goods},{path: '/ratings',component: ratings},{path: '/seller',component: seller}
];
export default new Router({// 激活class类名linkActiveClass:'active',routes
});
  • 然后在 main.js 中 引入routerindex.js ,并且传一个路由属性给Vue实例 ,实现路由的注入
new Vue({el: '#app',router,components: { App },template: '<App/>'
});
  • App.vue 中通过 router-link 组件实现

    <router-link to="/goods">商品</router-link>

    注意:不支持target=”_blank”属性,如果你想打开一个新标签页,你必须用标签。

  • 最后通过 router-view 组件渲染

<keep-alive><router-view v-bind:seller="seller"></router-view>
</keep-alive>
// keep-alive 主要用于保留组件状态或避免重新渲染
以上就实现了一个简单的路由
(3) 第一个组件 header.vue
<template><div class="header"><!--内容区--><div class="content-wrapper"><div class="avatar"><img v-bind:src="seller.avatar" width="64" height='64'/></div><div class="content"><div class="title"><span class="brand"></span><span class="name">{{seller.name}}</span></div><div class="description">{{seller.description}}/{{seller.deliveryTime}}分钟送达</div><div v-if="seller.supports" class="support"><!--判断是否存在--><span class="icon" v-bind:class="classMap[seller.supports[0].type]"></span><span class="text">{{seller.supports[0].description}}</span></div></div><div v-if="seller.supports" class="support-count" @click="showDetail"><span class="count">{{seller.supports.length}}个</span><i class="icon-keyboard_arrow_right"></i></div></div><!--公告区--><div class="bulletin-wrapper" @click="showDetail"><span class="bulletin-title"></span><span class="bulletin-text">{{seller.bulletin}}</span><i class="icon-keyboard_arrow_right"></i></div><!--背景--><div class="background"><img v-bind:src="seller.avatar" width="100%" height="100%" /></div><!--遮罩层 ,详情页--><transition name="fade"><div class="detail" v-show="detailShow"><div class="detail-wrapper clearfix"><div class="detail-main"><h1 class="name">{{seller.name}}</h1><div class="star-wrapper"><star :size="48" :score="seller.score"></star></div><div class="title"><div class="line"></div><div class="text">优惠信息</div><div class="line"></div></div><ul v-if="seller.supports" class="supports"><li class="support-item" v-for="(item ,index) in seller.supports"><span class="icon" :class="classMap[seller.supports[index].type]"></span><span class="text">{{seller.supports[index].description}}</span></li></ul><div class="title"><div class="line"></div><div class="text">商家公告</div><div class="line"></div></div><div class="bulletin"><p class="content">{{seller.bulletin}}</p></div></div></div><div class="detail-close" @click="hideDetail"><i class="icon-close"></i></div></div></transition></div>
</template><script>
import star from "../star/star.vue";
export default{data(){return{classMap:[],detailShow:false}},methods:{showDetail(){this.detailShow=true;},hideDetail(){this.detailShow=false;}},props: {seller:{type:Object,required:true}},created (){this.classMap=['decrease','discount','guarantee','invoice','special'];},components:{star}
};
</script><style lang="scss" scoped>
@import "../../common/styles/mixin.scss";.header {position:relative;overflow:hidden;color:#fff;background:rgba(7,17,27,0.5);.content-wrapper { position:relative;padding:24px 12px 18px 24px;font-size:0;.avatar { display:inline-block;vertical-align:top;img{ border-radius:2px;}}.content {display:inline-block;margin-left:16px;font-size:14px;.title { margin:2px 0 8px 0;.brand { display:inline-block;vertical-align:top;width:30px;height:18px;@include bg-image("img/brand"); background-size:30px 18px;background-repeat: no-repeat;}.name {margin-left:6px;font-size:16px;line-height:18px;font-weight: bold;}}.description {margin-bottom: 10px;line-height:12px;font-size:12px;}.support {.icon { display:inline-block;vertical-align:top;width:12px;height:12px;margin-right: 4px;background-size: 12px 12px;background-repeat: no-repeat;&.decrease { @include bg-image("img/decrease_1"); } &.discount { @include bg-image("img/discount_1"); } &.guarantee { @include bg-image("img/guarantee_1"); } &.invoice { @include bg-image("img/invoice_1"); } &.special { @include bg-image("img/special_1"); } } .text{ line-height:12px;font-size:10px;}}}.support-count {position:absolute;right:12px;bottom:14px;padding:0 8px;height:24px;line-height: 24px;border-radius:14px;background-color:rgba(0,0,0,0.2);.count{ vertical-align:top;font-size: 10px;}.icon-keyboard_arrow_right{margin-left: 2px;line-height:24px;font-size: 10px;}}}.bulletin-wrapper{position:relative;height:28px;line-height: 28px;padding:0 22px 0 12px;white-space: nowrap;overflow:hidden;text-overflow:ellipsis;background:rgba(7,17,27,0.2);.bulletin-title{ display:inline-block;vertical-align:top;margin-top:8px;width:22px;height:12px;@include bg-image("img/bulletin"); background-size:22px 12px;background-repeat:no-repeat;}.bulletin-text{vertical-align:top;margin:0 4px;font-size:10px;}.icon-keyboard_arrow_right{position:absolute;font-size:10px;right:12px;top:8px;}}.background{position:absolute;top:0;left:0;width:100%;height:100%;background:red;z-index:-1;filter:blur(10px);}.detail{position:fixed;z-index:100;top:0;left:0;width:100%;height:100%;overflow:auto;background:rgba(7,17,27,0.8);backdrop-filter:blur(10px);transition: all 0.5s;&.fade-enter,&.fade-leave-to{ opacity:0;}.detail-wrapper{width:100%;min-height: 100%;.detail-main{ margin-top:64px;padding-bottom:64px;.name{ line-height:16px;text-align:center;font-size:16px;font-weight: 700;}.star-wrapper{margin-top:16px;padding:2px 0;text-align:center;}.title{display:flex;width:80%;margin:28px auto 24px auto;.line{ flex:1;position:relative;top:-6px;border-bottom:1px solid rgba(255,255,255,0.2);}.text{padding:0 12px;font-size:15px;font-weight:700;}}.supports{width:80%;margin:0 auto;.support-item{ padding:0 12px;margin-bottom:12px;font-size:0px;&:last-child{ margin-bottom:0;}.icon{display:inline-block;vertical-align: top;width:16px;height:16px;margin-right:6px;background-size:16px 16px;background-repeat: no-repeat;&.decrease { @include bg-image("img/decrease_2"); } &.discount { @include bg-image("img/discount_2"); } &.guarantee { @include bg-image("img/guarantee_2"); } &.invoice { @include bg-image("img/invoice_2"); } &.special { @include bg-image("img/special_2"); } } .text{ line-height:16px;font-size:12px;}}}.bulletin{width:80%;margin:0 auto;.content{ padding:0 12px;line-height:24px;font-size:12px;}}}}.detail-close{position:relative;width:32px;height:32px;margin:-64px auto 0 auto;font-size:32px;}}
}
</style>
主要知识点
  • 指令

    • v-if :根据表达式的值的真假条件渲染元素
    • v-for :基于源数据多次渲染元素或模板块
    • v-bind :动态地绑定一个或多个特性,或一个组件 prop 到表达式
    • v-on :绑定事件监听器
      • 修饰符
      • stop:阻止事件冒泡
      • prevent:阻止默认事件
      • v-on:click.stop="doThis"
  • 过渡动画 :transition 组件

  • 选项 :methods,created
功能实现
1)动画 : 利用 transition 组件
  • 在需要实现动画的容器最外层 包裹 transition 组件,并且指定name 属性
<transition name="fade">
...
</transition>
  • 在css 中制定样式
transition: all 0.5s;
&.fade-enter,&.fade-leave-to{opacity:0;
}
在进入/离开的过渡中,会有 6 个 class 切换。下面这个图很清楚的可以看出类名的切换

本文发布于:2024-02-02 22:31:54,感谢您对本站的认可!

本文链接:https://www.4u4v.net/it/170688431446872.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:饿了   商家   页面   webpack
留言与评论(共有 0 条评论)
   
验证码:

Copyright ©2019-2022 Comsenz Inc.Powered by ©

网站地图1 网站地图2 网站地图3 网站地图4 网站地图5 网站地图6 网站地图7 网站地图8 网站地图9 网站地图10 网站地图11 网站地图12 网站地图13 网站地图14 网站地图15 网站地图16 网站地图17 网站地图18 网站地图19 网站地图20 网站地图21 网站地图22/a> 网站地图23