Vue3 + TS + Egg рефакторинг вашего собственного небольшого проекта [резюме]

Vue.js
Vue3 + TS + Egg рефакторинг вашего собственного небольшого проекта [резюме]

Версия vue-next (3.0) уже давно является открытым исходным кодом, хотя официальная версия не выпущена, это не влияет на наши попытки использовать ее в собственных проектах. Эта статья является кратким изложением моего проекта «кинотрейлер», только что переписанного на vue3.

Демонстрационный адрес проекта

Введение в проект

Я разместил на Наггетспервая статьяЭто только введение в этот проект. Я не ожидал, что прошло два года. Оглядываясь назад на рост последних двух лет... У меня есть сердце, чтобы убить себя! ! ! 🙃

Общие визуальные/интерактивные эффекты проекта не изменились, а именно:

1

Интерфейсный проект

создание проекта

  1. использоватьvue-cliИнструмент может легко создать проект vue.При выборе стека технологий просто отметьте TypeScript.

  2. Проект инициализируется черезvue add vue-nextУстановите официальный плагин, чтобы обновить его версию vue до vue3.0.

  3. Исправлятьshims-vue.d.tsфайл, импорт.vueкомпонент, типdefineComponentтип, возвращаемый функцией

    declare module "*.vue" {
       import { defineComponent } from "vue";
       const Component: ReturnType<typeof defineComponent>;
       export default Component;
    }
    

затрагивает моменты, которые необходимо изменить

  1. Удалитьfiltersфункция фильтра, официальная причина, чтобы сказатьfiltersФункции можно полностью реализовать с помощью функций и вычисляемых свойств, нет необходимости увеличивать затраты на обучение и|Он конфликтует с побитовыми операторами и увеличивает сложность синтаксического анализа шаблона. В частности, вы можете увидетьrfc

  2. отредактированоv-modelAPI и удаленоmodelопции. Прежде чем мы разработали компоненты для двустороннего связывания, мыprops.value,передачаthis.$emit('input')для достижения двусторонней привязки. vue3.0 будет использоватьmodelValueзаменятьvalue,emit('update:modelValue')заменитьinputмероприятие. В частности, вы можете увидетьrfc

<!-- 使用组件 -->
<Comp v-mode="text" />
// modelValue 通过 attrs 获取,emit用于触发事件
export default defineComponent({
  setup(props, { attrs, emit }) {
    const onChange = (e) => {
      emit('update:modelValue', e.target.value)
    }
    return { onChange } 	
  }
})
  1. TransitionкомпонентclassNameизменить, прежде чем эффект перехода будет записан вxxx-enter,xxx-leave-tocss имя класса, сейчасxxx-enterизменить наxxx-enter-from. В частности, вы можете увидетьrfc

  2. Изменились параметры установки плагина. Перед написанием плагина вы можете напрямую использовать входные параметры метода установкиVue, который монтирует метод или свойство вVue.prototypeначальство. Теперь входным параметром метода установки является приложение.

// 之前插件挂载属性的方式
export default {
  install: (Vue, option) => {
    Vue.prototype.$axios = xxx;
  }
}
// vue3.0的方式
export default {
  install: (app, option) => {
    app.config.globalProperties.$axios = xxxx
  }
}
// 另一种方式 也可以使用 provide 、inject , 在composition API中使用
export const symbolKey = Symbol('_axios_');
// setup 函数里使用composition API
export function useAxios() {
  return inject(symbolKey)
}
// 执行插件insall方法注入
export default {
  install: (app, option) => {
    app.provide(symbolKey, xxx)
  }
}

фактическиvue3.0В версии много изменений, но так как проект не очень сложный, он не очень полный, вы можете прочитать егоrfcsОзнакомьтесь с некоторыми обсуждениями изменений.

Применение API композиции

Все компоненты этого проекта используютсяComposition APIразработан, на основеComposition APIМы можем лучше инкапсулировать общую логику.

Инкапсуляция функции запроса

Перед этим необходимо дополнительно определить и поддерживать загрузку асинхронного запроса проекта.Composition APIМы можем инкапсулировать React, похожий на swrФункция ловушки библиотеки выборки.

// 类似于这样
export function useRequest(url, params, config) {
  // 统一维护的变量,最后return出去
  const state = reactive({
    loading: false,
    error: false,
    data: config.initialData
  })
  
  const fetchFunc = () => {
    state.loading = true;
  	// 做请求的公用逻辑
    axios().then(response => {
       const result = response.data;
       state.data = result.data;
       state.loading = false;
    }).catch(err => {
       state.error = true;
    })
  }
  
  onMounted(() => {
    if (config.immediate) {
      fetchFunc();
    }
  });
  
  // toRefs 可以将state,拆解成多个ref,这样调用者就可以使用解构来拿到变量
  return { ...toRefs(state), fetch: fetchFunc };
}

инкапсуляция событий

НапримерtouchСобытия, нам нужно не только связать события и развязать время, но также нужно разделить переменную побочного эффекта в разных обратных вызовах, мы можем разделить ее наcomposableфункция

// 类似于这样
export function useTouch(domRef, ref) {
  // 是否touch进行中标志位
  let initiated = false;
  // 监听domRef改变
  watch(domRef, (el, prev, onCleanup) => {
    const touchStart = (e: TouchEvent) => {
      e.preventDefault();
      initiated = true;
      callbacks.touchStart(e);
    };
   	const touchMove = (e: TouchEvent) => {
      e.preventDefault();
      if (!initiated) return;
      callbacks.touchMove(e);
    };
    const touchEnd = (e: TouchEvent) => {
      initiated = false;
      callbacks.touchEnd(e);
    };
    
    el.addEventListener("touchstart", touchStart);
    el.addEventListener("touchmove", touchMove);
    el.addEventListener("touchend", touchEnd);
	// 取消绑定
    onCleanup(() => {
      el.removeEventListener("touchstart", touchStart);
      el.removeEventListener("touchmove", touchMove);
      el.removeEventListener("touchend", touchEnd);
    });
  })
}

оптимизация

Добавлен travis для отправки автоматических выпусков сборки и отправки статических ресурсов на удаленные серверы через sshpass.

language: node_js
node_js:
  - 12
branchs:
  - master
addons:
  apt:
    packages:
    - sshpass
install:
  "npm install"
script:
  - "npm run build"
after_success:
  - ./script/deploy.sh

вserverPassа такжеserverIPВсе переменные среды настроены на travis.

#!/usr/bin/env sh

# 确保脚本抛出遇到的错误
set -e

# 打包静态资源
npm run build

# 将dist文件发送到远程
sshpass -p ${serverPass} scp -o stricthostkeychecking=no -r dist/ root@${serverIP}:/home/web/movie-trailer

серверный проект

бэкэнд от использованияkoaОбновление фреймворка доEggкадр, используяKoaПри разработке приложений разработчикам необходимо загружать или разрабатывать различное промежуточное программное обеспечение для достижения функциональных улучшений, в то время какEggвыбранныйKoaКак его базовая структура, он помогает разработчикам вносить в него некоторые улучшения.

EggПомимо предоставленияController,ServiceПомимо выполнения бизнес-процессов на уровне, он также обеспечиваетextendИспользуется для расширения собственной функции (несколько расширений). Например, мы можем расширитьContext, монтирует универсальную функцию, которая возвращает результат в своем контексте.

// app/extends/context.js
module.exports = {
  sendSuccess: function(result) {
    this.body = {
      code: 200,
      errMsg: '',
      data: result
    }
  },
  sendError: function(errorMsg) {
    this.body = {
      code: 300,
      errMsg: errorMsg,
    }
  }
};
// app/controller/keyword.js
class KeyWordController extends Controller {
  async index() {
    const { ctx, service } = this;

    const keywordList = await service.keyword.index();
	// 返回200成功
    ctx.sendSuccess(keywordList)
  }
}

До этого я сканировал фильмы Доубана через Python, а потом вручную писал скрипты через crontab,EggФреймворк помогает разработчикам устанавливать временные задачи, используяEgg, нам нужно толькоapp/scheduleСоздайте файл в каталоге для экспорта на основеSubscriptionтип.

class CrawlingDouban extends Subscription {
  // 静态方法,定义执行时机
  static get schedule() {
    return {
      cron: '0 8 * * *', // 每天8点
      type: 'worker',
    };
  }
  async subscribe() {
  	// 爬取逻辑
  }
}

Суммировать

В процессе рефакторинга по-прежнему будут возникать некоторые проблемы, большинство из которых вызвано непрочитанными документами, поэтому по-прежнему очень важно просматривать документы. Я надеюсь, что эта статья будет полезна для всех, и я чувствую, что с проектом все в порядке, так что не скупитесь на старт! .

адрес проекта

Ссылаться на