Когда внешний вид компании начинает менятьсяVueJS
, я недавно начал использовать этот фреймворк для разработки, столкнулся с некоторыми проблемами и записал их для дальнейшего использования.
в основном пишут некоторыеОфициальное руководствоВыше не написано, но проблемы, возникающие в реальной разработке, требуют определенной базы знаний.
Задействованный технологический стек
текст:
полифилл и трансформация во время выполнения
первый,vue-cli
автоматически добавлено для насbabel-plugin-transform-runtime
Этот плагин, большинство плагинов нормальный, может быть преобразован в большинствоES6
грамматика.
Однако есть две проблемы:
- Когда компонент загружается асинхронно, он будет производить
polyfill
избыточность кода - Глобальные функции и методы экземпляра не поддерживаются
polyfill
Причины обеих проблем связаны сbabel-plugin-transform-runtime
Для компиляции нашего кода используется механизм песочницы (т. е. без изменения встроенных объектов хост-среды).
Поскольку асинхронные компоненты в конечном итоге компилируются в один файл, даже если одна и та же новая функция используется в нескольких компонентах (например:Object.keys()
), то в каждом скомпилированном файле будет копия новой фичиpolyfill
копировать. Если проект небольшой, вы можете не использовать асинхронную загрузку, но нагрузка на первый экран будет относительно большой.
Глобальные функции не поддерживаются(Такие как:Promise
,Set
,Map
),Set
а такжеMap
Эти две структуры данных не должны широко использоваться всеми, и их влияние невелико. ноPromise
Воздействие может быть больше.
Методы экземпляра не поддерживаются(Такие как:'abc'.includes('b')
,['1', '2', '3'].find((n) => n < 2)
и т. д.), это ограничение в значительной степени устарело для большинства новых функций строк и половины или около того для массивов.
В основном
babel-plugin-transform-runtime
Он может удовлетворить большинство потребностей.Когда потребности не удовлетворены, рекомендуется использовать полныйbabel-polyfill
.
Заменить babel-polyfill
Во-первых, удалить из проектаbabel-plugin-transform-runtime
Удалите эту зависимость:
npm un babel-plugin-transform-runtime -D
Исправлятьbabel
конфигурационный файл
// .babelrc
{
//...
"plugins": [
// - "transform-runtime"
]
//...
}
Затем установитеbabel-polyfill
полагаться:
npm i babel-polyfill -D
Наконец, импортируйте в файл ввода
// src/main.js
import 'babel-polyfill'
Проблема со ссылкой на импорт ES6
существуетES6
, импорт и экспорт модульной системы принимает ссылочный экспорт и импорт (непростой тип данных), то есть, если объект определен в модуле и экспортируется, при импорте и использовании в других модулях импорт фактически Ссылка на переменную (указатель), если свойство в объекте изменено, это повлияет на использование других модулей.
Обычно, когда объем системы невелик, мы можем использоватьJSON.parse(JSON.stringify(str))
Просто и грубо создать новую глубокую копиюобъект данных. Однако, когда имеется много компонентов и высокая степень повторного использования объектов данных, очевидно, будут возникать проблемы с производительностью.В настоящее время мы можем рассмотреть возможность использованияImmutable.js.
По этой причине при экспорте сложных типов данных необходимо обращать внимание на проблемы, которые могут возникнуть при изменении данных, когда несколько компонентов импортируют один и тот же объект данных.
Кроме того, когда модуль определяет переменную или функцию, даже если он используетlet
вместоconst
, станет доступным только для чтения при импорте и использовании и не может быть переназначено, эффект эквивалентен использованиюconst
утверждение.
Использование Pug и Less с Vue
Установить зависимости
Vue
используется вvue-loader
согласно сlang
Атрибуты автоматически определяют, что нужноloader
, так что дополнительная настройка не требуетсяLoader
, но вам нужно вручную установить связанные зависимости:
npm i pug -D
npm i less-loader -D
Это достаточно удобно, никаких ручных доработок не требуетсяwebpack
конфигурационный файл добавитьloader
готов использовать
использовать
pug
ещеpug-loader
?sass
оба грамматическихloader
Как это настроить?
--- Пожалуйста, обратитесь кПрепроцессор vue-loader
использовать
<!-- xxx.vue -->
<style lang="less">
.action {
color: #ddd;
ul {
overflow: hidden;
li {
float: left;
}
}
}
</style>
<template lang="pug">
.action(v-if='hasRight')
ul
li 编辑
li 删除
</template>
<script>
export default {
data () {
return {
hasRight: true
}
}
}
</script>
Определить глобальную функцию или переменную
Много раз нам нужно определить некоторые глобальные функции или переменные для обработки некоторых частых операций (здесь возьмемAJAX
пример обработки исключений). Но когдаVue
, каждый однофайловый компонент имеет отдельный контекст (this
). Обычно при обработке исключений это должно быть отражено в представлении.На данный момент нам нужно получить доступthis
объект, но контекст глобальной функции обычноwindow
, то требуется особая обработка.
просто и грубо
Самый простой способ — напрямуюwindow
Для объекта определен глобальный метод, который используется при использовании в компоненте.bind
,call
илиapply
изменить контекст.
Определите глобальный метод обработки исключений:
// errHandler.js
window.errHandler = function () { // 不能使用箭头函数
if (err.code && err.code !== 200) {
this.$store.commit('err', true)
} else {
// ...
}
}
Импорт в файл записи:
// src/main.js
import 'errHandler.js'
В компоненте используйте:
// xxx.vue
export default {
created () {
this.errHandler = window.errHandler.bind(this)
},
method: {
getXXX () {
this.$http.get('xxx/xx').then(({ body: result }) => {
if (result.code === 200) {
// ...
} else {
this.errHandler(result)
}
}).catch(this.errHandler)
}
}
}
Элегантный и безопасный
В крупных совместных проектах с участием нескольких человек загрязнениеwindow
Объект по-прежнему не подходит. В частности, некоторые глобальные методы, которые являются более личными (могут использоваться почти везде в компонентах, которые вы пишете, но могут не понадобиться для других). В настоящее время рекомендуется написать модуль, который является более элегантным, безопасным и естественным.Единственным недостатком является то, что каждый компонент, который должен использовать эту функцию или метод, необходимо импортировать.
Метод использования аналогичен предыдущему, поэтому я не буду вводить его дальше.  ̄ω ̄=
Момент.JS и Webpack
В использованииMoment.js
Я столкнулся с некоторыми проблемами и обнаружил, что окончательный упакованный файл будетMoment.js
Все языковые пакеты для . Я проверил и обнаружил, что это может бытьwebpack
упаковать илиMoment.js
Проблема ссылки на ресурс (?), эта проблема в настоящее время не решена должным образомtrick
Для решения этой проблемы.
существуетwebpack
в производственном профилеplugins
Добавьте плагин в поле, используя встроенный метод классаContextReplacementPluginОтфильтрованоMoment.js
Языковые пакеты, которые не используются в:
// build/webpack.prod.conf.js
new webpack.ContextReplacementPlugin(/moment[\\/]locale$/, /^\.\/(zh-cn)$/)
Решения взяты изoleg-nogin@webpack/webpack#3128.
См. GitHub Issue для обсуждения проблемы:moment/moment#2373,webpack/webpack#3128.
пользовательский псевдоним пути
Некоторые люди могли заметить, что вvue-cli
Сгенерированный шаблон использует этот синтаксис при импорте компонентов:
import Index from '@/components/Index'
это@
Что это такое? Позже, когда я изменил файл конфигурации, я обнаружил, что этоwebpack
Один из вариантов конфигурации: псевдонимы путей.
Мы также можем добавить наши собственные псевдонимы пути в базовый файл конфигурации, такие как следующие~
установить путьsrc/components
псевдоним:
// build/webpack.base.js
{
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src'),
'~': resolve('src/components')
}
}
}
Затем мы можем написать это при импорте компонента:
// import YourComponent from 'YourComponent'
// import YourComponent from './YourComponent'
// import YourComponent from '../YourComponent'
// import YourComponent from '/src/components/YourComponent'
import YourComponent from '~/YourComponent'
Это не только решает проблему слишком длинных путей, но и решает проблемы относительных путей, что намного удобнее!ヾ(゚∀゚ゞ)
CSS-области и модули
Компонентные стили
Как правило, компонент<style></style>
Стили в тегах являются глобальными и могут использоваться при использовании сторонних UI-библиотек (таких как:Element
), глобальные стили, скорее всего, повлияют на стили библиотеки пользовательского интерфейса.
Мы можем добавитьscoped
свойство делатьstyle
Стили применяются только к текущему компоненту:
<style lang="less" scoped>
@import 'other.less';
.title {
font-size: 1.2rem;
}
</style>
Там
scoped
атрибутstyle
Импорт других стилей в теги также будет ограничен областью действия и станет стилями в компонентах. Это не рекомендуется для стилей с высокой степенью повторного использования.Кроме того, избегайте использования селекторов элементов во встроенных стилях, поскольку селекторы элементов могут значительно снизить производительность в сочетании с селекторами атрибутов.
--- Тесты для двух комбинаций селекторов:classes selector,elements selector
стиль импорта
в сравнении сstyle
использоватьscoped
Стиль в компоненте, когда атрибут используется, и иногда нам также нужно добавить некоторые глобальные стили. Конечно, мы можем использоватьscoped
атрибутstyle
писать глобальные стили.
Однако для сравнения более рекомендуется следующее:
/* 单独的全局样式文件 */
/* style-global.less */
body {
font-size: 10px;
}
.title {
font-size: 1.4rem;
font-weight: bolder;
}
Затем импортируйте глобальный стиль в файл записи:
// src/main.js
import 'style-global.less'
Получить значение элемента управления формы
Обычно мы можем напрямую использоватьv-model
Привяжите элементы управления формы к данным, но иногда нам также необходимо получить текущее значение при вводе данных пользователем (например: проверить достоверность текущего содержимого элемента управления вводом в режиме реального времени).
В этот момент мы можем использовать@input
или@change
События связывают наши собственные обработчики и передаются$event
объект для получения входного значения текущего элемента управления:
<input type='text' @change='change($event)'>
change (e) {
let curVal = e.target.value
if (/^\d+$/.test(curVal)) {
this.num = +curVal
} else {
console.error('%s is not a number!', curVal)
}
}
Конечно, если UI-фреймворк примет
Element
Это будет проще, и его обратный вызов события будет напрямую передавать текущее значение.
Советы по использованию v-for
v-for
Директивы мощные, их можно использовать не только для обхода массивов, объектов, но даже числа или строки.
Не буду рассказывать об основах грамматики, вот небольшой совет:
значение индекса
В использованииv-for
Создать из объекта или массиваDOM
Иногда вам нужно знать текущий индекс. Мы можем это сделать:
<ul>
<li v-for='(item, key) in items' :key='key'> {{ key }} - {{ item }}
</ul>
но, вам нужно обратить внимание при обходе чисел, количествоvalue
начинается с 1 иkey
от 0:
<ul>
<li v-for='(v, k) in 3' :key='k'> {{ k }}-{{ v }}
<!-- output to be 0-1, 1-2, 2-3 -->
</ul>
2.2.0+
версия, при использовании в компонентеv-for
час,key
Это обязательно сейчас.
Уникальный корневой узел шаблона
а такжеJSX
Точно так же шаблон в компоненте может иметь только один корневой узел, то есть следующая записьошибкаиз:
<template>
<h1>Title</h1>
<article>Balabala...</article>
</template>
Нам нужно обернуть его в элемент блочного уровня:
<template>
<div>
<h1>Title</h1>
<article>Balabala...</article>
</div>
</template>
Ссылка на причину:React-Notes: Заметки о разработке компонентов#Уникальный корневой узел
конфигурация пути к проекту
из-заvue-cli
Сконфигурированный проект предоставляет встроенный статический сервер, что в принципе не представляет проблемы на этапе разработки. Однако когда мы размещаем код на сервере, мы часто сталкиваемся с ошибками ссылок на статические ресурсы, что приводит к пустому интерфейсу.
Это потому чтоvue-cli
настроен по умолчаниюwebpack
Это файл, указанный в корневом каталоге сайта, однако иногда нам может потребоваться развернуть проект в подкаталоге.
мы можем пройтиconfig/index.js
Чтобы изменить относительный путь ссылки на файл:
build.assetsSubDirectory: 'static'
build.assetsPublicPath: '/'
dev.assetsSubDirectory: 'static'
dev.assetsPublicPath: '/'
Мы видим, что в объекте экспортаbuild
а такжеdev
обеassetsSubDirectory
,assetsPublicPath
эти два свойства.
вassetsSubDirectoryОтносится к папке статического ресурса, т. е. упакованномуjs
,css
, картинки и другие файлы помещаются в папку, по умолчанию это вообще не проблема.
assetsPublicPathОтносится к эталонному пути статических ресурсов, конфигурация по умолчанию/
, который является корневым каталогом веб-сайта, сassetsSubDirectoryКомбинация представляет собой полный путь ссылки на статический ресурс./static
.
Написанное здесь решение очевидно, просто измените корневой каталог на относительный:
build.assetsSubDirectory: 'static'
build.assetsPublicPath: './'
Точно! только один.
Эта проблема. ㄟ( ▔, ▔ )ㄏ
Меньшие накладные расходы полифилла
во введенииPolyfill
После этого вы можете.babelrc
открыть в файлеuseBulitIns
Атрибуты. Когда это свойство включено, компиляция проекта завершитpolyfill
Разделить на последовательность независимых модулей.
включитьuseBuiltIns
Атрибуты:
// .babelrc
{
"presets": [
["env", {
"modules": false,
"useBuiltIns": true
}],
"es2015",
"stage-2"
]
// ...
}
Импорт после установкиbabel-polyfill
:
// src/main.js
import 'babel-polyfill'
[1, 2, 3].find((v => v > 2))
включитьuseBulitIns
автоматическое разделениеbabel-polyfill
import 'core-js/modules/es6.array.find'
[1, 2, 3].find((v => v > 2))
Протестировано, чтобы уменьшить максимум примерно наполовину
polyfill
объем
Я не изучал его глубоко, думаю, это могло быть добавленоcore-js
С некоторыми основнымиpolyfill
Использование функции класса ESnext
В сравнении
По умолчанию,Vue
Однофайловые компоненты используют объект для описания реализации внутри компонента:
const App = {
// initialized data
data () {
return {
init: false
}
}
// lifecycle hook
created () {}
mounted () {}
// ...
}
export default App
Мы можем поддерживать последнюю версию, установив некоторые зависимостиclass
Пишу:
import Vue from 'vue'
import Component from 'vue-class-component'
@Component
class App extends Vue {
init = false;
created () {}
mounted () {}
}
export default App
Бесспорно, кода действительно больше, но я все же больше склоняюсь к написанию новых синтаксических возможностей, ведь стандарт — это маяк
P.S используется здесь все еще вStage 3
изField declarationsобъявить первоначальныйdata
использовать
Давайте посмотрим, какие изменения необходимо внести для поддержки использованияclass
записывается как:
- Во-первых, и это наиболее очевидно, нам нужно
vue-class-component
Это зависимо. - Тогда эта зависимость требует
babel
изtransform-decorators-legacy
Поддержка плагинов. - Наконец, если вы также хотите использовать объявления полей объявлений полей, добавьте
transform-class-properties
Достаточно.
Установите зависимости:
npm i vue-class-component -D
npm i babel-plugin-transform-decorators-legacy -D
npm i babel-plugin-transform-class-properties -D
конфигурацияbabel
// .babelrc
{
// ...
"plugins": [
"transform-runtime",
"transform-decorators-legacy",
"transform-class-properties"
]
// ...
}
Уведомление:
transform-decorators-legacy
быть размещеннымtransform-class-properties
До
Недействительность адаптивных данных
множество
из-заVue.js
Реактивные данные зависят отметод объекта Object.defineProperty
. Но очевидно, что у специального "объекта" массива нет этого метода, и, естественно, он не может задавать свойства объекта.descriptor
, чтобы не былоgetter()
а такжеsetter()
метод. Таким образом, при изменении данных элемента в виде индекса массива index (arr[index] = newVal
), представления, как правило, не обновляются в ответ.
Для решения этой проблемы,Vue.js
предоставлено в$set()
метод:
vm.arr.$set(0, 'newVal')
// vm.arr[0] = 'newVal'
объект
с учетом современных
JavaScript
ограничения (и устаревшиеObject.observe
),Vue
Не удается обнаружить добавление или удаление свойств объекта. из-заVue
будет выполняться для свойств при инициализации экземпляраgetter/setter
процесс преобразования, поэтому атрибут должен быть вdata
существуют на объекте, чтобы позволитьVue
Преобразуйте его, чтобы он был отзывчивым.
Ref: Углубленные принципы реактивного взаимодействия — Vue.js
var vm = new Vue({
data: {
a: 1
}
})
// `vm.a` 是响应的
vm.b = 2
// `vm.b` 是非响应的
Выявление статического типа
Рекомендуется при разработке более сложных компонентовprops
Статическое обнаружение типов повышает надежность компонентов.В большинстве случаев ошибки можно обнаружить заранее на этапе перекодирования.
// before
prop: [
'id',
'multiple',
'callback',
]
// after
props: {
id: {
type: [ Number, Array ],
required: true,
},
multiple: {
type: Boolean,
default: false,
},
callback : Function,
}
Асинхронные компоненты
использовать вStage.3
Динамически импортируемые функции для этаповimport()
, при использованииwebpack
Функция сегментации кода, вVue.js
Мы можем легко реализовать асинхронный компонент.
Компонент асинхронной маршрутизации
const AsyncComponent = () => import('./AsyncComponent')
Фабрика асинхронных компонентов
Vue.component(
'async-webpack-example',
() => import('./my-async-component')
)
По сравнению с асинхронными компонентами маршрутизации, асинхронные фабрики компонентов обычно подходят для дальнейшей мелкозернистой раздельной обработки в компонентах, таких как: второстепенные компоненты (всплывающие компоненты, вложенные в компоненты или
Popover
компоненты и др.).
To be continue...
Статья еще дорабатывается, приглашаю всех к обсуждению некоторых проблем, возникших при разработке Vue.JS (゚▽゚)/
Взгляните на свой список избранного, уверены ли вы, что не забудете посмотреть его после того, как соберете?