Адаптация мобильного терминала
По сравнению со стороной ПК разрешение мобильных устройств полно цветов и странно Для каждого разработчика адаптация мобильного терминала является первой проблемой, с которой нам приходится сталкиваться при разработке мобильных терминалов.
На мобильных устройствах мы часто видим этот код в теге head:
<meta name='viewport' content='width=device-width,initial-scale=1,user-scale=no' />
Настройка вьюпорта через метатег определяет коэффициент масштабирования страницы, чтобы понять значение этих параметров, нам нужно знать значение нескольких ширин вьюпорта.
-
layoutviewport
Ширина макета — это ширина веб-страницы. -
visualviewport
Однако ширина — это ширина окна браузера, и это значение определяет то, что мы можем видеть на одном экране нашего мобильного телефона;visualviewport
а такжеlayoutviewport
Отношение размера определяет, будет ли отображаться полоса прокрутки.visualviewport
больше или точно равноlayoutviewport
полоса прокрутки не появится. -
idealviewport
Область просмотра, определенная для браузера, которая может быть идеально адаптирована к мобильному терминалу, является фиксированной и может рассматриваться как ширина области просмотра устройства.device-width
.
Настройка мета на самом деле правильнаяlayoutviewport
а такжеvisualviewport
Сделайте настройки.
-
width=device-width
Указывает ширину страницыlayoutviewport
с шириной области просмотра устройстваidealviewport
последовательный -
initial-scale=1
Указывает начальное масштабирование ширины страницы и ширины веб-страницы до ширины области просмотра устройства,visualviewport
определяется этим соотношением, но дляlayoutviewport
Например, на него влияют два свойства одновременно, а затем принимает большее значение. -
user-scale=no
Отключить масштабирование
Итак, теперь мы знаем, что значение этого кода, распространенного на мобильной стороне, вот-вот исчезнет.visualviewport
а такжеlayoutviewport
Установить какidealviewport
Таким образом, у нас не будет полос прокрутки на мобильном терминале, а содержимое веб-страницы может быть лучше отображено.Исходя из этого, мы будем рассматривать адаптацию страницы.
При отрисовке пользовательского интерфейса, как правило, имеется фиксированная ширина, но ширина наших реальных мобильных устройств не одинакова.Однако, если коэффициент масштабирования элементов страницы совпадает с коэффициентом масштабирования ширины страницы, на устройствах с разными размеры Эффект наших веб-страниц также будет таким же.
Используйте относительные единицы
rem
rem вычисляется относительно размера шрифта корневого элемента html. Обычно это достигается установкой document.documentElement.style.fontSize при инициализации и загрузке страницы. Как правило, мы устанавливаем размер шрифта корневого элемента html равным 1/10 ширины.Ширина разных устройств отличается, но соотношение rem одного и того же значения согласуется с соотношением ширины устройства.
document.documentElement.style.fontSize = document.documentElement.clientWidth / 10 + 'px';
В реальных проектах нам не нужно конвертировать себя в разработку, мы можем использоватьpxtoremПреобразуйте px в rem на выходе.
Единицы области просмотра
ширина области просмотраwindow.innerWidth
и высота области просмотраwindow.innerHeight
(которыйlayoutviewport
) на 100 равных частей.
vw : 1vw составляет 1% от ширины области просмотра. vh : 1vh составляет 1% от высоты окна просмотра. vmin : меньшее из vw и vh vmax : выберите большее из vw и vh
По сравнению с rem, блоку просмотра не нужно использовать js для установки корневого элемента, а совместимость немного плохая, но большинство устройств уже поддерживает его, точно так же нет необходимости выполнять преобразование единиц во время разработки и использовать соответствующие плагины напрямую.postcss-px-to-viewportКонвертировать на выходе.
Изменить область просмотра
Ранее мы упоминалиlayoutviewport
Ширина макета на самом деле не является фиксированным значением, а задается через мета-атрибут, черезidealviewport
Вычисленное значение, мы можем контролировать атрибут мета дляlayoutviewport
фиксируется на определенном значении. Ширина чертежа общего дизайна 750px, и теперь наша цельlayoutviewport
установите 750 пикселей;layoutviewport
Затронутые двумя свойствами, мы устанавливаем свойство ширины на 750, а коэффициент масштабирования начального масштаба должен бытьidealviewport
ширина/750; когда мы не меняли атрибут метатега,layoutviewport
Значение на самом делеidealviewport
значение, поэтому можно пройтиdocument.body.clientWidth
илиwindow.innerWidth
чтобы получить.
;(function () {
const width = document.body.clientWidth || window.innerWidth
const scale = width / 750
const content = 'width=750, initial-scale=' + scale + ', minimum-scale=' + scale + ', maximum-scale=' + scale + ', viewport-fit=cover'
document.querySelector('meta[name="viewport"]').content = content
})()
После завершения настройкиlayoutviewport
На разных устройствах он всегда будет 750 пикселей, и мы можем напрямую использовать размер проекта при разработке.
стиль макета
Могут быть различные способы компоновки, но из соображений совместимости некоторых стилей лучше избегать, а также не стоит сталкиваться с трудными для решения проблемами.
исправлено, к которому нужно относиться с осторожностью
position:fixed
Он очень часто используется в ежедневных макетах страниц и играет ключевую роль во многих макетах. Что он делает:position:fixed
Элемент будет указывать свое положение относительно положения окна просмотра экрана. И положение элемента не меняется при прокрутке экрана.
Однако во многих конкретных ситуацияхposition:fixed
Спектакль сильно отличается от того, что мы себе представляли.
- iOS выводит клавиатуру; после вызова программной клавиатуры фиксированный элемент страницы будет недействителен (iOS считает, что пользователь предпочитает, чтобы элемент перемещался при прокрутке, то есть абсолютное позиционирование), так как он стал абсолютным, поэтому, когда страница превышает единицу. Когда экран прокручивается, недопустимый фиксированный элемент будет следовать за прокруткой.
- Когда свойство преобразования предка элемента не равно none, контейнер позиционирования изменяется с области просмотра на этого предка. Проще говоря, это
position:fixed
Элемент будет расположен относительно ближайшего предка, к которому было применено преобразование, а не окна. Причина этого в том, что элементы, использующие преобразование, создадут новый контекст стека. Контекст стекирования: контекст стекирования — это трехмерная концепция HTML-элементов, которые простираются по воображаемой оси Z по отношению к пользователю, обращенному к окну (экрану компьютера) или веб-странице. HTML-элементы имеют приоритет в соответствии с их собственными атрибутами. порядок занимает место в контексте стека. Порядок показан на рисунке ниже.Короче говоря, контекст стека будет влиять на отношение позиционирования. Хотите увидеть дальшеНеуправляемое положение: фиксированное.
Всплывающие окна клавиатуры и использование атрибута преобразования очень распространены на мобильных устройствах, поэтому их следует использовать с осторожностью.position:fixed
.
рекомендуется гибкий
flex-direction: column;
И эластичный бокс, занимающий все окно, и тогда макет внутри должен быть фиксированной высоты в начале и в конце, а область содержимого посередине —flex: 1;
.
html, body {
padding: 0;
margin: 0;
}
.page {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
display: flex;
flex-direction: column;
.page-content {
flex: 1;
overflow-y: auto;
}
}
Затем создайте нижнюю строку заголовка.Нижняя строка заголовка обычно состоит из расположенного по центру заголовка и левой и правой рабочих областей; чтобы добиться центрирования заголовка в средней области, левая и правая части должны иметь одинаковую ширину.
<template>
<div class="header">
<div class="header__left">
左
</div>
<div class="header__main">
<slot>Title</slot>
</div>
<div class="header__right">
<div>右</div>
</div>
</div>
</template>
<script>
export default {
name: 'HeadBar'
}
</script>
<style lang="scss" scoped>
.header {
display: flex;
width: 100%;
line-height: 88px;
height: 88px;
font-size: 36px;
background-color: #42b983;
z-index: 999;
color: #fff;
transition: background-color .5s ease;
.header__main {
flex: 1;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
.header__left, .header__right {
padding: 0 16px;
width: 120px;
}
.header__left {
text-align: left;
}
.header__right {
text-align: right;
}
}
</style>
Основная часть нижней панели навигации фактически представляет собой один параметр навигации, который делит панель навигации пополам, а каждый параметр навигации является направлением движения.flex-direction: column;
Горизонтальное расположение естьalign-items: center;
, вертикаль естьjustify-content: space-around;
<template>
<div class="taber">
<div class="taber-item">
<div class="icon"></div>
<span>选项1</span>
</div>
<div class="taber-item">
<div class="icon"></div>
<span>选项2</span>
</div>
<div class="taber-item">
<div class="icon"></div>
<span>选项3</span>
</div>
<div class="taber-item">
<div class="icon"></div>
<span>选项4</span>
</div>
</div>
</template>
<script>
export default {
name: 'BottomTaber',
data () {
return {
}
}
}
</script>
<style lang="scss" scoped>
.taber {
background-color: #42b983;
color: #fff;
height: 88px;
display: flex;
.taber-item {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
}
.icon {
width: 36px;
height: 36px;
background-color: #fff;
}
}
</style>
прыжок страницы
анимация перехода
В vue мы управляем маршрутизацией через vue-router.Каждый переход маршрутизации аналогичен переключению между разными страницами.С точки зрения удобства пользователя лучше всего добавлять эффект перехода каждый раз при переключении страниц. Если анимация перехода не различает, открывает ли маршрут новую страницу или возвращается на предыдущую страницу, нам нужно только<router-view>
внешнее использование<transition>
Достаточно добавить анимационный эффект, но обычно к открытию и возврату применяются разные анимационные эффекты, поэтому при переключении маршрутов нам нужно различать, идет ли маршрут вперед или назад. Чтобы различать действия маршрутизации, мы устанавливаем мета как число в файле маршрутизации, мета представляет глубину его маршрутизации, а затем слушаем $route и устанавливаем различные анимации перехода в соответствии с мета-значениями «куда» и «из». Если он применяется к нескольким анимационным прыжкам, его можно применять в соответствии с деталями и конкретными обстоятельствами.
<template>
<transition :name="transitionName">
<router-view></router-view>
</transition>
</template>
<script>
export default {
name: 'app',
data () {
return {
transitionName: 'fade'
}
},
watch: {
'$route' (to, from) {
let toDepth = to.meta
let fromDepth = from.meta
if (fromDepth > toDepth) {
this.transitionName = 'fade-left'
} else if (fromDepth < toDepth) {
this.transitionName = 'fade-right'
} else {
this.transitionName = 'fade'
}
}
}
}
</script>
vue-navigation
Добиться этого удобнее, и нет необходимости выполнять избыточные настройки на роутере.npm i -S vue-navigation
Установить, импортировать в main.js:
import Navigation from 'vue-navigation'
Vue.use(Navigation, {router}) // router为路由文件
Установите в App.vue:
this.$navigation.on('forward', (to, from) => {
this.transitionName = 'fade-right'
})
this.$navigation.on('back', (to, from) => {
this.transitionName = 'fade-left'
})
this.$navigation.on('replace', (to, from) => {
this.transitionName = 'fade'
})
Другой важной функцией плагина vue-navigation является сохранение состояния страницы, аналогичное сохранению активности, но состояние сохранения активности не может идентифицировать прямой и обратный маршрут.В практических приложениях наше требование состоит в возврате на страницу и надеюсь, что состояние страницы Сохранить, когда вы входите на страницу, вы хотите получить новые данные.Использование vue-навигации может хорошо добиться этого эффекта. Для конкретного использования см.vue-navigationЕсть подробные инструкции и кейсы. Также попробуйтеvue-page-stack, оба проекта могут добиться нужного нам эффекта,vue-page-stack
заимствованныйvue-navigation
, также реализовало больше функций и недавно было обновлено.
PS: Эффект анимации здесь взят из animate.scss;
Нижняя панель навигации
Мы реализовали базовый стиль нижней панели навигации ранее, здесь мы сделаем некоторые пояснения. Если путь маршрутизации страницы совпадает сrouter-link
Когда маршрут совпадает,router-link
будет установлен в активное состояние, мы можем установитьactive-class
Чтобы установить имя класса, применяемое при активации пути, по умолчанию используетсяrouter-link-active
, а имя активированного класса также имеетrouter-link-exact-active
, имя класса задаетсяexact-active-class
Чтобы установить, это также имя класса, применяемое при активации пути настройки;active-class
а такжеexact-active-class
Фактически он определяется методом сопоставления маршрута.
Общий метод сопоставления маршрутов — сопоставление включений. Например, если текущий путь начинается с /a, также будет установлено имя класса CSS. Согласно этому правилу каждый маршрут будет активирован, при использованииexact
Атрибуты могут использовать «шаблон точного соответствия». Точное сопоставление активируется только в том случае, если маршруты идентичны.
охранник маршрута
Защита маршрутизации на мобильном терминале, как правило, не слишком сложна, в основном это оценка разрешений на вход.Мы настраиваем белый список маршрутизации и помещаем в него все маршруты, не требующие разрешений на вход, для входа в систему без входа в систему. Страница требует, чтобы пользователь вошел в систему, а затем получил к ней доступ. Если пользователю необходимо вернуться к исходному маршруту после входа в систему, передайте маршрут целевой страницы в качестве параметра на страницу входа, а затем примите решение после входа в систему. Если есть параметр целевой страницы, перейдите на целевую страницу. Просто перейдите на домашнюю страницу.
Если ваше приложение связано с разрешениями, вам нужно отметить разрешения, требуемые каждым маршрутом, и установить роли в мета.Роли — это массив для сохранения необходимых разрешений, вы можете судить, сравнивая разрешения, принадлежащие пользователю, и роли из интерфейса в фон имеет соответствующие разрешения.
const whiteList = ['/login']
router.beforeEach((to, from, next) => {
const hasToken = store.getters.auth
if (hasToken) {
if (to.path === '/login') {
next({ path: '/' })
} else {
const needRoles = to.meta && to.meta.roles && to.meta.roles.length > 0
if (needRoles) {
const hasRoles = store.state.user.roles.some(role => to.meta.roles.includes(role))
if (hasRoles) {
next()
} else {
next('/403')
}
} else {
next()
}
}
} else {
if (whiteList.includes(to.path)) {
next()
} else {
next('/login')
}
}
})
компоненты
автозагрузка
В нашем проекте часто используется много компонентов, как правило, компоненты с высокой частотой используются в проекте как глобальные компоненты, чтобы избежать утомительного повторного импорта. Чтобы зарегистрировать глобальные компоненты, нам сначала нужно ввести компоненты, а затем использоватьVue.component
Зарегистрируйтесь; это повторяющаяся работа, которую мы делаем каждый раз, когда создаем компонент, если наш проект собран с помощью веб-пакета (vue-cli также использует веб-пакет), мы можем передатьrequire.context
Автоматически регистрировать компоненты в файле global. Создайтеcomponents/index.js
документ:
export default function registerComponent (Vue) {
/**
* 参数说明:
* 1. 其组件目录的相对路径
* 2. 是否查询其子目录
* 3. 匹配基础组件文件名的正则表达式
**/
const modules = require.context('./', false, /\w+.vue$/)
modules.keys().forEach(fileName => {
// 获取组件配置
const component = modules(fileName)
// 获取组件名称,去除文件名开头的 `./` 和结尾的扩展名
const name = fileName.replace(/^\.\/(.*)\.\w+$/, '$1')
// 注册全局组件
// 如果这个组件选项是通过 `export default` 导出的,
// 那么就会优先使用 `.default`,
// 否则回退到使用模块的根。
Vue.component(name, component.default || component)
})
}
позжеmain.js
Импортируйте модуль регистрации для регистрации, используйтеrequire.context
Мы также можем реализовать импорт плагинов vue и глобальных фильтров.
import registerComponent from './components'
registerComponent(Vue)
Связывание данных через v-модель
v-model
Это синтаксический сахар, суть его в отслеживании событий компонентов и обновлении данных, это аббревиатура от props и $on Monitoring events.v-model
доставка по умолчаниюvalue
, мониторinput
мероприятие. Теперь мы используемv-model
Чтобы реализовать поле ввода числа, это поле ввода может вводить только числа.В компоненте нам нужно только определить значение, чтобы принять переданное значение, а затем использовать его, когда входное значение соответствует нашим условиям ввода (ввод - это число) .$emit
вызыватьinput
мероприятие.
<template>
<div>
<input type="text" :value="value" @input="onInput">
</div>
</template>
<script>
export default {
name: 'NumberInput',
props: {
value: String
},
methods: {
onInput (event) {
if (/^\d+$/.test(event.target.value)) {
this.$emit('input', event.target.value)
} else {
event.target.value = this.value
}
}
}
}
</script>
При использовании нам нужно использовать толькоv-model
Просто привяжите значение.v-model
По умолчанию будет использоватьсяvalue
изprop
и назвалinput
событие, но много раз мы хотим использовать другойprop
и прослушивание различных событий, мы можем использоватьmodel
опции для модификации.
Vue.component('my-checkbox', {
model: {
prop: 'checked',
event: 'change'
},
props: {
// this allows using the `value` prop for a different purpose
value: String,
// use `checked` as the prop which take the place of `value`
checked: {
type: Number,
default: 0
}
},
// ...
})
<my-checkbox v-model="foo" value="some value"></my-checkbox>
Приведенный выше код эквивалентен:
<my-checkbox
:checked="foo"
@change="val => { foo = val }"
value="some value">
</my-checkbox>
Используйте компоненты в качестве плагинов
Во многих сторонних библиотеках компонентов мы часто видим способ прямого вызова компонентов с помощью плагинов, таких какVantUIКомпонент диалогового всплывающего окна, мы можем не только использовать его в виде компонента, но и вызывать в виде плагина.
this.$dialog.alert({
message: '弹窗内容'
});
Принцип использования компонентов в качестве плагинов на самом деле не сложен, то есть использовать ручное монтирование экземпляров компонента Vue.
import Vue from 'vue';
export default function create(Component, props) {
// 先创建实例
const vm = new Vue({
render(h) {
// h就是createElement,它返回VNode
return h(Component, {props})
}
}).$mount();
// 手动挂载
document.body.appendChild(vm.$el);
// 销毁方法
const comp = vm.$children[0];
comp.remove = function() {
document.body.removeChild(vm.$el);
vm.$destroy();
}
return comp;
}
передачаcreate
входящий компонент иprops
Параметр может получить экземпляр компонента, и через экземпляр компонента мы можем вызывать различные функции компонента.
<template>
<div class="loading-wrapper" v-show="visible">
加载中
</div>
</template>
<script>
export default {
name: 'Loading',
data () {
return {
visible: false
}
},
methods: {
show () {
this.visible = true
},
hide () {
this.visible = false
}
}
}
</script>
<style lang="css" scoped>
.loading-wrapper {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
background-color: rgba(0, 0, 0, .4);
z-index: 999;
}
</style>
<!--使用-->
const loading = create(Loading, {})
loading.show() // 显示
loading.hide() // 关闭
сторонние компоненты
Различные компоненты и плагины на мобильном терминале относительно завершены, и повторять создание колес во время разработки проекта неразумно, при разработке проектов мы можем использовать сторонние компоненты и плагины для повышения эффективности нашей разработки.
Общая библиотека компонентов
VantUIЭто набор легкой и надежной библиотеки мобильных компонентов Vue с открытым исходным кодом Youzan; он поддерживает импорт по запросу, настройку темы и SSR.Помимо обычных компонентов, существуют специальные бизнес-компоненты для сценариев электронной коммерции. разработка проекта электронной коммерции. Если это так, рекомендуется использовать его. Официальная документация по настройке темы находится по адресуwebpack.config.js
установить в:
// webpack.config.js
module.exports = {
rules: [
{
test: /\.less$/,
use: [
// ...其他 loader 配置
{
loader: 'less-loader',
options: {
modifyVars: {
// 直接覆盖变量
'text-color': '#111',
'border-color': '#eee'
// 或者可以通过 less 文件覆盖(文件路径为绝对路径)
'hack': `true; @import "your-less-file-path.less";`
}
}
}
]
}
]
};
Но наш проект может быть собран с использованием vue-cli, тогда нам нужноvue.config.js
установить в:
module.exports = {
css: {
loaderOptions: {
less: {
modifyVars: {
'hack': `true; @import "~@/assets/less/vars.less";`
}
}
}
}
}
Кроме тогоvux,mint-uiТоже хороший выбор.
Общие плагины
better-scrollЭто плагин, который обеспечивает эффекты плавной прокрутки для различных сценариев прокрутки на мобильной стороне.Если вы используете его в vue, вы можете обратиться к статье автораКогда лучшая прокрутка встречается с Vue.
swiperЭто карусельный плагин, если он используется в vue, его можно использовать напрямую.vue-awesome-swiper,vue-awesome-swiper
на основеSwiper4
и поддерживает SSR.