WebApp商城

一:准备工作
1、项目结构
compnents文件夹 存放整个项目公共的组件
assets文件夹 存放样式和字体图标
api文件夹 存放请求文件
pages文件夹存放项目页面
pages文件夹中有conponents存放的是页面级的公共组件
2、搭建开发环境

  1. 初始化项目
npm init

2)安装开发依赖

npm install --save-dev css-loader@4.2.1 style-loader@1.2.1 file-loader@6.0.0 url-loader@4.1.0 

3)安装生产依赖

npm install art-template@4.13.2 swiper@6.1.1 

4)修改scripts属性值

"start": "webpack-dev-server --open chrome" 

3、配置webpack.config.js文件

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

// 获取绝对路径
const resolve = dir => path.resolve(__dirname, dir);

module.exports = {
  mode: 'development',
  // Webpack 入口文件
  entry: {
    index: './src/pages/index',
    destination: './src/pages/destination'
  },
  // Webpack 输出路径
  output: {
    // 输出的目录
    path: resolve('dist'),
    // 输出的文件名
    filename: 'js/[name].js'
  },
  // source-map,调试用的,出错的时候,将直接定位到原始代码,而不是转换后的代码
  devtool: 'cheap-module-eval-source-map',
  resolve: {
    // 自动补全(可以省略)的扩展名
    extensions: ['.js'],
    // 路径别名
    alias: {
      api: resolve('src/api'),
      icons: resolve('src/assets/icons'),
      styles: resolve('src/assets/styles'),
      components: resolve('src/components'),
      pages: resolve('src/pages'),
      utils: resolve('src/utils')
    }
  },
  // 不同类型模块的处理规则
  module: {
    rules: [
      // css
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader']
      },
      // 模板文件
      {
        test: /\.art$/,
        loader: 'art-template-loader'
      },
      // 图片
      {
        test: /\.(png|jpe?g|gif|svg)$/,
        loader: 'url-loader',
        options: {
          // 小于 10K 的图片转成 base64 编码的 dataURL 字符串写到代码中
          limit: 10000,
          // 其他的图片转移到
          name: 'images/[name].[ext]',
          esModule: false
        }
      },
      // 字体文件
      {
        test: /\.(woff2?|eot|ttf|otf)$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: 'fonts/[name].[ext]'
        }
      }
    ]
  },
  plugins: [
    // 自动将依赖注入 html 模板,并输出最终的 html 文件到目标文件夹
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: './src/pages/index/index.art',
      chunks: ['index']
    }),
    new HtmlWebpackPlugin({
      filename: 'destination.html',
      template: './src/pages/destination/destination.art',
      chunks: ['destination']
    })
  ]
};

二、首页开发
1、头部组件,下方代码是components/header/index.js

import './header.css';

// 需要添加的类名
const CHANGED_CLASS_NAME = 'header-transition';
// 初始状态,主要是为了防止多次触发的问题
const INIT_STATE = 'init';
// 改变状态,主要是为了防止多次触发的问题
const CHANGED_STATE = 'changed';

// 添加Header类
class Header {
 // 需要传递四个参数
 // 1:元素,2、距离,3、滚动条所在的元素,4、绑定事件的元素
 constructor(el, critical_point, scrollContainer, eventEl = scrollContainer) {
   this.el = el;
   this.critical_point = critical_point;

   // 滚动条所在的容器
   this.scrollContainer = scrollContainer;

   // 监听滚动事件的元素
   this.eventEl = eventEl;
   // 调整状态
   this.setState(INIT_STATE);
   // 绑定事件
   this.bindEvent();
 }

 // 设置状态
 setState(state) {
   this.state = state;
 }

 // 绑定事件
 bindEvent() {
   this.eventEl.addEventListener(
     'scroll',
     () => {
       if (this.needChange()) {
         this.setState(CHANGED_STATE);
         this.change();
       } else if (this.needReset()) {
         this.setState(INIT_STATE);
         this.reset();
       }
     },
     false
   );
 }
 // 重置,去掉类名
 reset() {
   this.el.classList.remove(CHANGED_CLASS_NAME);
 }
 // 不是初始的状态,并且滚动的距离大于等于设定的距离
 needReset() {
   return (
     this.state !== INIT_STATE &&
     this.scrollContainer.scrollTop <= this.critical_point
   );
 }

 //   变化,添加类名
 change() {
   this.el.classList.add(CHANGED_CLASS_NAME);
 }

 //   需要变化,不是已改变的状态,并且滚动的距离小于设定的距离
 needChange() {
   return (
     this.state !== CHANGED_STATE &&
     this.scrollContainer.scrollTop > this.critical_point
   );
 }
}
// 导出顶部
export default Header;

使用Header类,下方代码是pages/index/components/header/index.js

import Header from 'components/header';

const scrollContainer = document.getElementById('index-page');
const headerEl = scrollContainer.querySelector('.header');

new Header(headerEl, 0, scrollContainer);

2、幻灯片组件
下方代码是:pages/index/components/slider/config.js

// Swiper 配置
export default {
  // 循环模式选项
  loop: true,
  // 是否需要分页器
  pagination: {
    el: '.swiper-pagination'
  }
  // 是否需要前进后退按钮
  //   navigation: {
  //     nextEl: '.swiper-button-next',
  //     prevEl: '.swiper-button-prev'
  //   },
  // 是否需要滚动条
  //   scrollbar: {
  //     el: '.swiper-scrollbar'
  //   }
};

export const SWIPER_CONTAINER_CLASS = '.swiper-container';

使用幻灯片,下方代码是:pages/index/components/slider/index.js

// 引入css
import 'swiper/swiper-bundle.min.css';
import './slider.css';
// 引入js
import Swiper from 'swiper/swiper-bundle.min';
// 引入配置文件
import config, { SWIPER_CONTAINER_CLASS } from './config';

// https://www.swiper.com.cn/api/index.html
// 实例化
new Swiper(SWIPER_CONTAINER_CLASS, config);

3、导航组件
下方代码是:pages/index/components/nav/config.js

export const URL = 'https://www.imooc.com/api/mall-wepApp/index/nav';
export const LAYOUT_ID = 'index-nav';

下方代码是:pages/index/components/nav/index.js

import './nav.css';
// 引入模板
import render from './nav.art';
// ajax请求
import { getData, getDelayedData } from 'api/getData';
// 请求地址和盛放结构的元素
import { URL, LAYOUT_ID } from './config';

// https://www.imooc.com/api/mall-wepApp/index/nav
getData(URL).then(data => {
  document.getElementById(LAYOUT_ID).innerHTML = render({
    items: data
  });
});

4、返回顶部
Backtop 组件,下方代码是:下方代码是components/backtop/index.js

import './backtop.css';
import 'icons/iconfont.css';

const CHANGED_CLASS_NAME = 'backtop-hidden';
const INIT_STATE = 'init';
const CHANGED_STATE = 'changed';

class Backtop {
  constructor(el, critical_point, scrollContainer, eventEl = scrollContainer) {
    this.el = el;
    this.critical_point = critical_point;

    // 滚动条所在的容器
    this.scrollContainer = scrollContainer;

    // 监听滚动事件的元素
    this.eventEl = eventEl;

    this.setState(INIT_STATE);

    this.bindEvent();
  }

  // 设置状态
  setState(state) {
    this.state = state;
  }

  // 绑定事件
  bindEvent() {
    this.eventEl.addEventListener(
      'scroll',
      () => {
        if (this.needChange()) {
          this.setState(CHANGED_STATE);
          this.change();
        } else if (this.needReset()) {
          this.setState(INIT_STATE);
          this.reset();
        }
      },
      false
    );

    this.el.addEventListener(
      'click',
      () => {
        this.scrollTo();
      },
      false
    );
  }

  scrollTo(top = 0, left = 0) {
    this.scrollContainer.scrollTo({
      top,
      left,
      behavior: 'smooth'
    });
  }

  reset() {
    this.el.classList.add(CHANGED_CLASS_NAME);
  }

  needReset() {
    return (
      this.state !== INIT_STATE &&
      this.scrollContainer.scrollTop <= this.critical_point
    );
  }

  //   变化
  change() {
    this.el.classList.remove(CHANGED_CLASS_NAME);
  }

  //   需要变化
  needChange() {
    return (
      this.state !== CHANGED_STATE &&
      this.scrollContainer.scrollTop > this.critical_point
    );
  }
}

export default Backtop;

使用返回顶部组件,下方代码是:pages/index/components/backtop/index.js

import Backtop from 'components/backtop';

const scrollContainer = document.getElementById('index-page');
const backtopEl = scrollContainer.querySelector('.backtop');

new Backtop(backtopEl, window.innerHeight, scrollContainer);
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容