Оптимизированное решение Vue для мобильных устройств

Vue.js

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

  • Пользовательская загрузка vuex-plugins
  • Анимация переключения маршрутов + поддержка динамического управления компонентами кеша
  • Рекомендации по использованию Better-Scroll и Vue (vueization of better-scroll)
  • Пользовательские команды (vue-finger: включая щелчок, длительное нажатие, двойной щелчок, перетаскивание, мультитач, скольжение, поворот, жесты масштабирования)
  • Решение для адаптации мобильного терминала
  • Как быть с верхом страницы по ситуации
  • Отложенная загрузка маршрута

Пользовательская загрузка vuex-plugins

Если каждая страница отображает загрузку до загрузки данных. Первое, что приходит вам в голову, это установить состояние для каждой страницы, показать и скрыть состояния. Но это слишком много избыточного кода, и писать его самому надоедает. Я использовал dva в своем предыдущем проекте React, включая библиотеку загрузки dva, которую я изучал ранее, поэтому я использовал его идеи, чтобы написать vuex-загрузку самостоятельно.
Идея реализации: зарегистрировать модуль для управления загрузкой в ​​vuex и сохранить загрузку каждого действия в vuex, привязав асинхронные действия, чтобы мне нужно было только выполнить соответствующую загрузку действия в хранилище vuex на каждой странице.

 ## 核心代码
    store.subscribeAction({
      before: action => {
        if (shouldEffect(action, includes, excludes)) {
          store.commit({ type: namespace + '/SHOW', payload: action.type })
        }
      },
      after: action => {
        if (shouldEffect(action, includes, excludes)) {
          store.commit({ type: namespace + '/HIDE', payload: action.type })
        }
      }
    })
  }
}

Прежде чем использовать его, вы можете понять егоsubscribeAction
Чтобы установить этот плагин,пожалуйста, нажмите здесь, не забудьте поставить звезду
Примечание. Чтобы использовать приведенный выше код, vuex должен быть версии 3.1.0. Поскольку subscribeAction был добавлен в 3.1.0

Пополнить

Думаю, лучше написать о том, почему вам рекомендуют использовать vuex-plugins-loading, идею обработки потоков данных.

Когда я познакомился с dva.js в прошлом году, я почувствовал, что эта идея обработки потока данных сделает весь ваш проект более понятным и легким для итерации. Легче понять, что кто-то другой берет на себя весь ваш фреймворк.

Сейчас я расскажу о том, как я инкапсулирую vuex по идее dva.js. на самом деле это очень легко

## store 文件目录下的 index.js
import Vue from 'vue'
import Vuex from 'vuex'
import home from './modules/home'
import createLoadingPlugin from 'vuex-plugins-loading'
Vue.use(Vuex)

export default new Vuex.Store({
  modules: {
    home,
  },
  plugins: [createLoadingPlugin()]
})
# home.js
import { loadDataApi } from '../../service/api'

const state = {
  listData: [],
}

const mutations = {
  getData (state, payload) {
    state.listData = state.listData.concat(payload.res.data.data)
    state.page = payload.res.data.page
    state.pageNumber = Math.ceil(payload.res.data.total / payload.res.data.pageSize)
  },
  refreshData (state, payload) {
    state.listData = payload.res.data.data
  },
}
const getters = {

}
const actions = {
  loadMore ({ commit, state }, data) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        const { page, type } = data
        loadDataApi({ page }).then(res => {
          if (res.code === 200) {
            if (type === 'loadMore') {
              commit({
                type: 'getData',
                res: res
              })
            } else {
              commit({
                type: 'refreshData',
                res: res
              })
            }
            resolve()
          } else {
            reject(res.error)
            Toast(res.error)
          }
        })
      }, 1000)
    })
  }
}
## Home.vue
computed: {
    // Getting Vuex State from store/modules/home
    ...mapState({
      listData: state => state.home.listData,
      loading: state => state['@@loading'].effects['home/loadMore']
    }),
  },
  methods: {
    ...mapActions('home', ['initData', 'plusPage', 'initPage']),
    // onLoad 加载数据
    onLoad () {
      this.requestData('loadMore')
    },
    requestData (type) {
      setTimeout(() => {
        this.$store.dispatch('home/loadMore', {

        }).then(() => {
        })
      }, 1000)
    },
    onRefresh () {
      this.initPage().then(() => {
        this.requestData('refresh')
      })
    },

1. Во-первых, как реализован внутренний слой загрузки vuex-plugins?

1.plugins: [createLoadingPlugin()],

2.loading: state => state['@@loading'].effects['home/loadMore']

При использовании 1 этот плагин будет связывать каждое действие, которое вы использовали, а когда я использую 2, я получу загрузку связанного действия.
Здесь есть два процесса. до и после в store.subscribeAction. Моя загрузка всегда истинна после того, как я вызываю действие, которое было до этого. Когда мое действие заключено в обещание, все действие не будет завершено до тех пор, пока не будет завершено решение() или отклонение(). После этого пойдет после.

before

after

after

Я знаю, что все спросят, почему в vuex заложено так много логики. На самом деле, я думаю, что это сделает весь ваш проект понятным и удобным в сопровождении. Легко повторить.

Файл .vue просто отображает данные в vuex на странице.

Данные доступны и фильтруются в хранилище.

Уровень обслуживания используется для инкапсуляции вашего API.

это так очевидно

Анимация переключения маршрутов + поддержка динамического управления компонентами кеша

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

До трансформации он также основывался на практиках других

## app.vue
 <transition :name="transitionName"> 
    <keep-alive :include="data">
        <router-view></router-view>
    </keep-alive>
 </transition>
 
  computed: {
    // 数据存放在vuex里面
    ...mapState({
      data: state => {
        return state.global.data
      }
    })
  },
  methods: {
    // 设置Keep_alive路由
    setKeep_alive (to) {
      if (to.meta.keepAlive) {
        this.$store.dispatch({
          type: 'global/setData',
          payload: to.name
        })
      }
    }
  },
  watch: {
    '$route' (to, from) {
      // 此时从from页面跳转到to页面
      this.setKeep_alive(to)
      const routeDeep = ['/', '/list', '/detail', '/reservation', '/addCars']
      const toDepth = routeDeep.indexOf(to.path)
      const fromDepth = routeDeep.indexOf(from.path)
      if (!from.name) {
        this.transitionName = 'fold'
        return
      }
      this.transitionName = toDepth > fromDepth ? 'fold-left' : 'fold-right'
    }
  },
## router.js
scrollBehavior (to, from, savedPosition) {
    // keep-alive 返回缓存页面后记录浏览位置
    if (savedPosition && to.meta.keepAlive) {
      return savedPosition
    }
    // 异步滚动操作
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve({ x: 0, y: 1 })
      }, 0)
    })
  },

два вопроса

  1. После того, как страница списка перемещается в определенную позицию, она переходит на страницу сведений и возвращается на страницу списка, а страница возвращается обратно.
    Причина: Положение родной полосы прокрутки не изменилось.Используя scrollBehavior, по приведенному выше коду видно, что полоса прокрутки сначала будет иметь процесс мерцания, а потом прокручивается до последней зарезервированной позиции.
  2. Там будут временные пустые страницы при переходе перехода не нормально.

После преобразования

## app.vue
<keep-alive :include="data">
  <router-view></router-view>
</keep-alive>
computed: {
    // 数据存放在vuex里面
    ...mapState({
      data: state => {
        return state.global.data
      }
    })
  },
  methods: {
    // 设置Keep_alive路由
    setKeep_alive (to) {
      if (to.meta.keepAlive) {
        this.$store.dispatch({
          type: 'global/setData',
          payload: to.name
        })
      }
    }
  },
  watch: {
    '$route' (to, from) {
      // 此时从from页面跳转到to页面
      this.setKeep_alive(to)
    }
  },
list.vue
<Scroll
  ref="scroll"
  class="scroll-home"
  :scrollbar="scrollbar"
  :probeType="3"
  :pullDownRefresh="pullDownRefresh"
  :pullUpLoad="true"
  @pullingDown="onRefresh"
  @scroll="scroll"
  @pullingUp="onLoad"
>
 <div class="contantView">
 </div>
</Scroll>

1. После использования Better-Scroll первая проблема может быть решена напрямую. И вам не нужно устанавливать scrollBehavior, вы можете увидеть, если вы не понимаетеbetter-scroll

2. В CSS страницы добавить настройку position:absolute;, в это время страница отделена от документооборота и не занимает места, чтобы следующая страница не выдавливалась и плавно переход будет завершен. Используйте лучшую прокрутку, чтобы добавить настройку «position:fixed;» в CSS страницы.

Если в макете страницы используется гибкий макет, обязательно добавьте элемент div с абсолютной или фиксированной позицией во гибкий компонент.

В приведенном выше коде уже есть идея поддержания динамического управления маршрутами кеша.

Лучшие практики для лучшей прокрутки и vue

В предыдущей статье я видел, что BetterScroll может быть лучшим плагином для мобильной прокрутки в настоящее время, поэтому я хочу попробовать его на этот раз.Большинство скользящих компонентов, используемых в библиотеке компонентов кубического пользовательского интерфейса с открытым исходным кодом Didi, основаны на better -scroll, это очень приятно испытать это. Почему ты больше не используешь куб? Потому что я лично считаю, что цвет темы немного уродлив. Поэтому я планирую инкапсулировать vue-версию компонента прокрутки на основе better-scroll. Не будем много говорить, давайте сразу сфотографируем:

Есть еще одна причина, по которой я хочу использовать лучшую прокрутку, я хочу настроить анимацию вверх и вниз.

Хотите увидеть демо и исходный кодпожалуйста, нажмите здесь. Не забудьте дать звезду

Пользовательская директива vue-finger

Включая касание, длительное нажатие, двойное нажатие, перетаскивание для перемещения, мультитач, пролистывание, поворот, жесты масштабирования

Эта часть основана на моей сторонеМодифицировано чужой демоверсией, в этих командах вы можете делать множество вещей, которые вы хотите сделать с точки зрения мобильных жестов. В дальнейшем я буду продолжать повторять эти инструкции и разрабатывать компоненты с почти родным опытом.Все должны обратить на меня вниманиеgithubЭй

Решение для адаптации мобильного терминала

## rem.js
const baseSize = 32
// 设置 rem 函数
function setRem () {
  // 当前页面宽度相对于 750 宽的缩放比例,可根据自己需要修改。
  const scale = document.documentElement.clientWidth / 750
  // 设置页面根节点字体大小
  document.documentElement.style.fontSize = (baseSize * Math.min(scale, 2)) + 'px'
}
// 初始化
setRem()
// 改变窗口大小时重新设置 rem
window.addEventListener('resize', function () {
  setRem()
})

## main.js
import './rem'

Остался последний шаг. Для студентов, которые часто пишут стили, раздражает ли преобразование px в rem? Здесь я делаю это так: создаю новый файл postcss.config.js в корневом каталоге проекта. Таким образом, вам нужно только нормально написать px в соответствии со стилем проекта дизайна. Когда вы запустите проект, он автоматически преобразует его в rem.

module.exports = {
  plugins: {
    'autoprefixer': {
      browsers: ['Android >= 4.0', 'iOS >= 7']
    },
    'postcss-pxtorem': {
      rootValue: 16,
      propList: ['*']
    }
  }
}

Как быть с верхом страницы по ситуации

Как упоминалось выше, в vue-routerscrollBehaviorСюда.

## router.js
scrollBehavior (to, from, savedPosition) {
    // keep-alive 返回缓存页面后记录浏览位置
    if (savedPosition && to.meta.keepAlive) {
      return savedPosition
    }
    // 异步滚动操作
    return new Promise((resolve) => {
      setTimeout(() => {
        resolve({ x: 0, y: 1 })
      }, 0)
    })
  },

Но такое ощущение, что после добавления анимации перехода страницы. Страница восстановится. Так что я просто бросил его. Можно рассматривать без добавления анимации.
Мне не нужно беспокоиться об этой проблеме после использования здесь Better-Scroll. Прочитав введение в документацию по Better-Scroll, вы обнаружите, что Better-Scroll разработан для мобильных приложений.

Отложенная загрузка маршрута

При упаковке и создании приложений пакеты JavaScript могут стать очень большими и повлиять на загрузку страницы. Было бы более эффективно, если бы мы могли разделить компоненты, соответствующие разным маршрутам, на разные блоки кода, а затем загружать соответствующие компоненты при доступе к маршруту. Здесь важна ленивая загрузка маршрутов. Видимыйофициальная документацияКаждый должен иметь возможность использовать его, поэтому я не буду его здесь представлять.

// 路由懒加载
const _import_ = file => () => import('./views/' + file + '.vue')

routes: [
    {
      path: '/',
      name: 'home',
      component: _import_('Home/Home'),
      meta: {
        title: '首页',
        keepAlive: true
      }
    },
]

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