Разработка полного стека простого апплета торгового центра (mpvue+koa+mongodb)

база данных Vue.js koa mpvue

предисловие

После периода контакта с апплетом было меньше проектов, и началось путешествие с Vue, в котором больше внимания уделяется управлению данными/состоянием, компонентизации, кроссплатформенности и т. д. MPVUE — это интерфейсная структура, использующая Vue. Апплет разработки .js, который запускает MPVue, чтобы ступить на яму, и хочет увеличить опыт разработки Vue.js при одновременном повышении читабельности кода.

стек технологий

Интерфейс: апплет WeChat, mpvue
Бэкенд: коа
База данных: монгодб Визуализатор базы данных: Robo3T

Запуск апплета торгового центра

Базовый апплет торгового центра, включающий начальную домашнюю страницу, категорию, корзину, четыре вкладки «Мой (заказ)», определение внутренних данных, классификацию и доступ. Каждый из них имеет свои особенности.Я представлю некоторые основные функции ниже, сравню ямы, на которые наступил нативный апплет и vue.js, и функциональное применение серверной базы данных. Если вы хотите узнать или у вас есть вопросы, вы можете перейти наРабочий исходный кодпонять в о.

Обмен достижениями

1. Первая страница и функциональный дисплей

титульная страница:

добавить в корзину:

Оформление корзины:

Управление адресами:

1. Об упаковке компонентов

Например, домашняя страница состоит из трех частей: главная карусельная рекомендация + средняя горизонтальная скользящая рекомендация + список товаров с вертикальной прокруткой. Эти три части являются почти необходимыми функциями для всех приложений торгового центра. Карусельная рекомендация в голове и инкапсуляция горизонтальной скользящей рекомендации в середине, мы все знаем, что такие функциональные компоненты, как этот, в основном необходимы в каждом приложении Первое, что нужно испытать при изучении Vue, — это возможность повторного использования кода компонента. функции, когда некоторые компоненты переиспользуются и переносятся в другие компоненты или страницы, их можно использовать напрямую без изменения кода или изменения небольшого количества кода.Можно сказать, что это довольно удобно, и нативный апплет все еще поддерживается в Компонент mpvue. Пролистывание и прокрутка совместимы. Разработчики, знакомые с апплетами и vue, могут эффективно выполнять эту функцию.
Наконец, файл главной страницы состоит из компонентов, что очень удобно для чтения.Для новичков идея инкапсуляции модулей — это первое, что нужно иметь.

<template>
  <div class="container" @click="clickHandle('test click', $event)">
    <div class="swiperList">
      <swiper :text="motto" :swiperList="swiperlist"></swiper>
    </div>
    <div class="navTab">
      <div class="recTab">
        <text>  ——  为你推荐  ——</text>
    </div>
    </div>
    <scroll></scroll>
    <div class="hot">
      <span> —— 热门商品 ——</span>
    </div>
    <hot :v-text="motto"></hot>
    <div class="fixed-img">
      <img :src="fixImg" alt="" class="fix-img">
    </div>
  </div>
</template>

Однако, что касается проблемы инкапсуляции и комбинации компонентов, из-за недавнего исследования оптимизации производительности Vue и пользовательского опыта была рассмотрена более серьезная проблема:
Давайте взглянем на распространенный метод написания Vue: поместите компонент приложения в html, а компонент приложения ссылается на другие подкомпоненты, чтобы сформировать дерево компонентов с приложением в качестве корневого узла:

<body>
    <app></app> 
</body>

Такой подход вызывает проблемы с производительностью: для инициализации родительского компонента необходимо сначала инициализировать его дочерние компоненты, а у дочерних компонентов есть свои дочерние компоненты. Затем, чтобы инициализировать корневой тег, вам нужно начать всплывать снизу и инициализировать все компоненты страницы. Таким образом, наша страница не начнет отображаться, пока все компоненты не будут инициализированы.
Этот результат, очевидно, не то, что мы хотим, пользователь будет открывать страницу каждый раз, но также будет сталкиваться с пустым и ответом на какое-то время, потому что странице не разрешено реагировать на компоненты страницы инициализации, есть другие компоненты включены в приложении так серьезно Замедлите скорость страницы.
Лучшим результатом является то, что страница может отображаться потоком сверху вниз, что может увеличить общее время, но время первого экрана уменьшается, по мнению пользователя, скорость открытия страницы выше. Некоторые онлайн-методы похожи, и у них есть преимущества и недостатки, так что… Я тоже в сумасшедшем процессе, жду хороших новостей.

**2.Привязка класса и стиля**

При обращении к одному и тому же дочернему компоненту в разных родительских компонентах, но каждый из них должен получить связанный динамический стиль для представления разных стилей, при связывании стиля стиля CSS я наступил на большую яму: mpvue не поддерживает использование объекта. style,сначала я был в бешенстве от стиля который так и не смог подняться.Подробностей о mpvue в интернете очень мало.Позже много где искал и обнаружил что привязка класса и стиля не поддерживает форма classObj и styleObj Я пытался использовать строку, и, конечно... Я изменил код, чтобы сомневаться в жизни, и вы сказали мне, что начало жизни было ошибкой, как я могу не чувствовать душевную боль? ...

решить:

<template>
<div class="swiper-list">
    <d-swiper :swiperList="swiperlist" :styleObject="styleobject"></d-swiper>
</div>
</template>
<script>
    data() {
        return {
            styleobject:'width:100%;height:750rpx;position:absolute;top:0;z-index:3'
        }
    }
</script>

3. Ловушка «v-для гнездования»

При выполнении проекта vue использование цикла неизбежно, и необходимо использовать значение индекса индекса, но индекс нельзя использовать повторно, когда v-for вложен, а внутренний цикл и внешний цикл не могут совместно использовать индекс.

<swiper-item v-for="(items,index) in swiperList" :key="index">
    <div v-for="item in items" class="swiper-info" :key="item.id" @click="choose" >
        <image :src="item.url"  class="swiper-image" :style="styleObject"/>
    </div>
</swiper-item>

Приведенный выше код выдаст ошибку:

И добавив еще один индекс во внутренний цикл, ошибки нет:

<swiper-item v-for="(items,index) in swiperList" :key="index">
    <div v-for="(item,i) in items" class="swiper-info" :key="i" @click="choose" >
        <image :src="item.url"  class="swiper-image" :style="styleObject"/>
    </div>
</swiper-item>

4. это указывает на проблему и применение стрелочных функций

Это исходные слова в документации vue: все хуки жизненного цикла вызываются с контекстом this, указывающим на вызывающий его экземпляр Vue.
Значение: используйте это во всех методах ловушек жизненного цикла Vue (таких как создание, монтирование, обновление и уничтожение), это указывает на экземпляр Vue, который его вызвал, т.е. (новый Vue). То же самое и в mpvue. Мы все знаем, что это в функции жизненного цикла указывает на экземпляр Vue, поэтому мы можем получить доступ к данным и выполнять операции со свойствами и методами.

props:{
    goods:Array
},
mounted: function(options){
    let category = [
      {id: 0, name: '全部'},
      {id: 1, name: 'JAVA'},
      {id: 2, name: 'C++'},
      {id: 3, name: 'PHP'},
      {id: 4, name: 'VUE'},
      {id: 5, name: 'CSS'},
      {id: 6, name: 'HTML'},
      {id: 7, name: 'JavaScript'}
    ]
    this.categories = category
    this.getGoodsList(0)
  },
methods: {
    getGoodsList(categoryId){
      console.log(categoryId);
      if(categoryId == 0){
        categoryId = ''
      }
      wx.request({
        url: 'http://localhost:3030/shop/goods/list',
        data: {
          categoryId: categoryId
        },
        method: 'POST', 
        success: res => {
          console.log(res);
          this.goods = res.data.data;
        }
      })
    },
}

Обычная функция this указывает на контекст, в котором выполняется эта функция, то есть на контекст, в котором она вызывается, поэтому здесь не имеет значения, использует ли функция жизненного цикла обычную функцию или функцию со стрелкой, потому что ее среда определения и рабочая среда одинаковы, поэтому данные, свойства и методы в экземпляре vue также могут быть получены. В стрелочной функции this указывает на самый внешний блок кода, который ее определяет, ()=>{} эквивалентно function(){}.bind(this); поэтому, конечно, это указывает на экземпляр vue. Поначалу указанная этим проблема не учитывалась, в wx.request({}) при успехе использовалась обычная функция, а результат выдавал ошибку "товар не определен", использовалась стрелочная функция чтобы ее решить. Сначала обычная функция this указывала на Контекст getGoodsList(), поэтому нет возможности получить значение.

5. при загрузке и при отображении

При щелчке продукта на главной странице и переходе на страницу сведений функция onLoad() не может получить обновленные данные.
Прежде всего, хотя onLoad: функция (параметры) может принимать значения, это загружается только один раз, а не эффект, который я хочу.Мне нужно перейти с этой страницы (не закрывая ее) на другую страницу.Данные соответствующего продукта получен.
Так что вам нужно поместить код внутри onshow, Каждый раз, когда страница загружается, будет запрашиваться текущее состояние, будут запрашиваться дочерние объекты соответствующих данных, и обновление будет отображаться на странице сведений.

onShow: function(options){
    // console.log(this.styleobject)
      // console.log(options)
    wx.getStorage({
      key: 'shopCarInfo',
      success: (res) =>{
        // success
        console.log(`initshopCarInfo:${res.data}`)
        this.shopCarInfo = res.data;
        this.shopNum = res.data.shopNum
      }
    })
    wx.request({
      url: 'http://localhost:3030/shop/goods/detail',//请求detail数据表的数据
      method: 'POST',
      data: {
        id: options.id
      },
      success: res =>{
        // console.log(res);
        const dataInfo = res.data.data.basicInfo;
        this.saveShopCar = dataInfo;
        this.goodsDetail.name = dataInfo.name;
        this.goodsDetail.minPrice = dataInfo.minPrice;
        this.goodsDetail.goodsDescribe = dataInfo.characteristic;

        let goodsLabel = this.goodsLabel
        goodsLabel = res.data.data;
        // console.log(goodsLabel);
        this.selectSizePrice = dataInfo.minPrice;
        this.goodsLabel.pic = dataInfo.pic;
        this.goodsLabel.name = dataInfo.name;
        this.buyNumMax = dataInfo.stores;
        this.buyNumMin = (dataInfo.stores > 0) ? 1 : 0;
      }
    })
  }

Узнайте о функциях жизненного цикла апплета onLoad и onShow:
onLoad: функция жизненного цикла — отслеживает инициализацию апплета.Когда инициализация апплета завершена, запускается onLoadh (запускается только один раз в глобальном масштабе).
onShow: функция жизненного цикла — следите за отображением апплета, когда апплет запускается или выходит на передний план из фона, onShow будет запущен.

2. Фоновая база данных и доступ к данным

1. Настройте службу HTTP

В глобальном конфигурационном файле: 1) Ввести коа и создать его экземпляр

const Koa = require('koa');
const app = new Koa()

2).app.listen(номер порта): создать и вернуть HTTP-сервер, передав заданные параметры в Server#listen().

const Koa = require('koa');//引入koa框架
const app = new Koa();
app.listen(3000);
这里的app.listen()方法只是以下方法的语法糖:

const http = require('http');
const Koa = require('koa');
const app = new Koa();
http.createServer(app.callback()).listen(3000);

После завершения базовой настройки мы можем использовать «http://localhost3030+ параметры адреса запроса», чтобы получить значение базы данных.

2. Промежуточное ПО маршрутизации Koa-router

koa-router — широко используемая библиотека маршрутизации для koa.
Если вы полагаетесь на ctx.request.url для ручной обработки маршрутизации, вы будете писать много кода обработки. В настоящее время вам необходимо соответствующее промежуточное программное обеспечение маршрутизации для управления маршрутизацией. Вот относительно простое в использовании промежуточное программное обеспечение маршрутизации, коа-маршрутизатор.
Переключение интерфейса управляется коммутацией маршрутизации, а интерфейс «оцифрован».

3. Создайте объектную модель

Прежде чем создавать библиотеку, давайте поговорим об объектном моделировании.
Mongoose — это инструмент объектной модели для удобной работы mongodb в асинхронной среде node.js. Этот пакет npm инкапсулирует методы для управления mongodb.
У мангуста есть две особенности:
1. Проектировать нереляционные данные с помощью идеи реляционной базы данных
2. На основе драйвера mongodb упростите работу

const mongoose = require('mongoose')

const db = mongoose.createConnection('mongodb://localhost/shop') //建立与shop数据库的连接(shop是我本地数据库名)

Магазин локальной базы данных создал пять таблиц данных, а именно «управление адресами», «детали товаров», «детали заказа», «список товаров» и «список пользователей»:

Интерфейс Schema определяет модель данных:
Схема используется для определения структуры базы данных. Подобно определению данных при создании таблицы (можно определить не только структуру и свойства документа, но также метод экземпляра, метод статической модели, составной индекс и т. д. документа), каждая схема будет сопоставлена ​​с таблицей. сбор в mongodb, но схема не позволяет работать с базами данных.
Сопоставление между таблицей данных и объектом также имеет эффект проверки, чтобы проверить, соответствует ли каждая группа данных условиям, определенным в модели. В то же время каждый объект отображается в отчете данных, и объект можно использовать для сохранения операции, что эквивалентно работе с таблицей данных, а не громоздкой операции командной строки mysql.

Возьмем в качестве примера таблицу данных «Список продуктов»:

// 模型通过Schema界面定义。
var Schema = mongoose.Schema;

const listSchema = new Schema({
  barCode: String,
  categoryId: Number,
  characteristic: String,
  commission: Number,
  commissionType: Number,
  dateAdd: String,
  dateStart: String,
  id: Schema.Types.ObjectId,
  logisticsId: Number,
  minPrice: Number,
  minScore: Number,
  name: String,
  numberFav: Number,
  numberGoodReputation: Number,
  numberOrders: Number,
  originalPrice: Number,
  paixu: Number,
  pic: String,
  pingtuan: Boolean,
  pingtuanPrice: Number,
  propertyIds: String,
  recommendStatus: Number,
  recommendStatusStr: String,
  shopId: Number,
  status: Number,
  statusStr: String,
  stores: Number,
  userId: Number,
  videoId: String,
  views: Number,
  weight: Number,
})

Определяет тип элементов данных, требуемых в таблице данных, и таблица данных будет соответствовать один за другим после передачи данных:

4. koa-router "библиотека маршрутизации"

const Router = require('koa-router')()//引入koa-router
const router = new Router();// 创建 router 实例对象
//注册路由
router.post('/shop/goods/list', async (ctx, next) => {
  const params = ctx.request.body
  //以‘listSchema’的模型去取到Goods的数据
  const Goods = db.db.model('Goods', db.listSchema) //第一个‘db’是require来的自定义的,第二个‘db’是取到连接到mongodb的数据库,model代指实体数据(根据schema获取该字段下的数据,然后传给Goods))
  ctx.body = await new Promise((resolve, reject) => {//ctx.body是ctx.response.body的缩写,代指响应数据
    //异步,等到获取到数据之后再将body发出去
    if (params.categoryId) {
      Goods.find({categoryId: params.categoryId},(err, docs) => {
        if (err) {
          reject(err)
        }
        resolve({
          code: 0,
          errMsg: 'success',
          data: docs
        })
      })
    } else {
      Goods.find((err, docs) => {
        if (err) {
          reject(err)
        }
        resolve({
          code: 0,
          errMsg: 'success',
          data: docs
        })
      })
    }
  })
})

Все операции с базой данных являются асинхронными, поэтому вам необходимо инкапсулировать обещания для реализации, чтобы вы могли получить доступ к базе данных локального магазина через POST «http://localhost3030/shop/goods/list». Здесь, кстати, использование контекста «ctx», ctx (context), мы все знаем, что в node.js есть объекты запроса (request) и объекты ответа (response). Koa инкапсулирует эти два объекта в объект ctx. Параметр ctx — это переменная, передаваемая koa, которая инкапсулирует запрос и ответ, через которые мы можем получить доступ к запросу и ответу. (Внешний интерфейс получает данные через ajax-запрос http) Мы можем получить данные в базе данных через запрос ctx или.
Свойство Ctx.body — это то, что отправляется пользователю
body — это тело ответа в протоколе http, а заголовок относится к заголовку ответа.
ctx.body = ctx.res.body = ctx.response.body

5. Настройки слоя модели для кэша данных

1) Зачем нужно кешировать данные?
Я должен упомянуть здесь о важности кэширования данных.Хотя я получил данные из локальной базы данных, из-за большого объема требуемых данных, и упомянутая выше оптимизация производительности не была завершена, каждый раз все еще есть определенное время запроса ., нет необходимости запрашивать бэкэнд каждый раз, когда вы его открываете, а рендеринг страницы происходит медленно, поэтому часто используемые данные нужно кэшировать локально, что может значительно повысить скорость рендеринга страницы.
2) Установите слой модели

setGoodsList: function (saveHidden, total,  allSelect, noSelect, list) {
      this.saveHidden = saveHidden,
      this.totalPrice = total,
      this.allSelect = allSelect,
      this.noSelect = noSelect,
      this.goodsList = list
      var shopCarInfo = {};
      var tempNumber = 0;
      var list = [];
      shopCarInfo.shoplist = list;

      for (var i = 0; i < list.length; i++) {
        tempNumber = tempNumber + list[i].number
      }
      shopCarInfo.shopNum = tempNumber;
      wx.setStorage({
        key: "shopCarInfo",
        data: shopCarInfo
      })
    },

Способ, который должен хранить данные локально, инкапсулирован в модель метода, и когда его необходимо хранить локально, он напрямую ссылается. На сегодняшний день, архитектурные идеи, которые часто используются в Vue и React, имеют определенные требования для инкапсуляции моделей слоя.

bindAllSelect() {
      var list = this.goodsList;
      var currentAllSelect = this.allSelect
      if (currentAllSelect) {
        list.forEach((item) => {
          item.active = false
        })
      } else {
        list.forEach((item) => {
          item.active = true
        })
      }
      this.setGoodsList(this.getSaveHide(), this.totalPrice(), !currentAllSelect, this.noSelect(), list);
    },

Заключение:

Написание этого проекта много раз было безумием, потому что много vue можно использовать, но нельзя реализовать в mpvue, что приводит к множеству обходных путей и множеству ям, но рост программистов не просто падает и лазить в ямы в процессе? Сочинение не простое, друзья могут наградить их, если смогут... Кстати, адрес моего проекта прилагается:"mpvue-демо", но есть еще много мест для улучшения, давайте вместе пройдем долгий путь!