Есть много вещей, которые нужно сделать при запуске продукта, и тестирование продуктов нельзя отделить друг от друга. Хью спросил, сколько жуков осталось, и круги под глазами были как лак и грязь.
как бывшийJava coder
, когда я впервые увиделjs
декоратор внутри(Decorator
), я сразу подумал оJava
Аннотации в , конечно же, по фактическому принципу и функции,Java
аннотации иjs
Декораторы совсем другие. Название этой статьиVue中使用装饰器,我是认真的
, но эта статья начнётся с разработки концепции декораторов, давайте посмотрим.
Из этой статьи вы узнаете следующее:
- Узнайте, что такое декоратор
- Использование декораторов в методах
- существует
class
использование декораторов в - существует
Vue
использование декораторов в
Эта статья была впервые опубликована на официальном аккаунте [Некоторые играют на фронтенде]. Если вы не хотите быть соленой рыбой, но хотите сменить работу, обратите внимание на официальный аккаунт и возьмите вас, чтобы почистить вопросы интервью крупных заводов каждый день.
===
Дачангoffer
.
что такое декоратор
декораторES2016
Предложенное предложение, которое в настоящее время находится вStage 2
Стадия, про опыт декоратора, можно нажатьGitHub.com/Job39/предложения…проверьте детали. Декоратор — это синтаксический сахар, связанный с классом, который используется для переноса или изменения поведения класса или метода класса.Фактически декоратор — это реализация шаблона декоратора в шаблоне проектирования. Однако приведенные выше понятия слишком сухие, переведем их человеческими словами и приведем пример.
Пишите в ежедневном развитииbug
В процессе мы часто используем анти-дрожание и дросселирование, такие как следующие
class MyClass {
follow = debounce(function() {
console.log('我是子君,关注我哦')
}, 100)
}
const myClass = new MyClass()
// 多次调用只会输出一次
myClass.follow()
myClass.follow()
Выше приведен пример анти-тряски, мы проходимdebounce
Функция обертывает другую функцию для реализации функции защиты от сотрясений.В настоящее время есть еще одно требование, например, надежда на вызовfollow
Журнал печатается до и после функции, в это время мы также можем разработать еще один.log
функционировать, а затем продолжатьfollow
собираться
/**
* 最外层是防抖,否则log会被调用多次
*/
class MyClass {
follow = debounce(
log(function() {
console.log('我是子君,关注我哦')
}),
100
)
}
в коде вышеdebounce
а такжеlog
Две функции — это, по сути, две функции-оболочки.После того, как исходная функция была обернута этими двумя функциями, поведение исходной функции изменилось, в то время какjs
Принцип декоратора таков, мы используем декоратор для преобразования приведенного выше кода
class MyClass {
@debounce(100)
@log
follow() {
console.log('我是子君,关注我哦')
}
}
Форма декоратора@ + 函数名
, если есть параметры, параметры можно передать в следующих скобках
Использование декораторов в методах
Декораторы могут быть применены кclass
на илиclass
Внутри вышеперечисленных свойств, но в целом применяются кclass
На атрибуте будет больше сцен, например, как мы говорили вышеlog
,debounce
И так далее, они обычно применяются к атрибутам класса.Далее давайте посмотрим, как реализовать декоратор и применить его к классу. Перед реализацией декоратора нам нужно понять дескриптор свойства.
Подробнее об дескрипторах свойств
Когда мы определяем атрибут в объекте, на самом деле у атрибута есть много дескрипторов атрибута.Эти дескрипторы указывают, может ли атрибут быть изменен, пронумерован, удален и т. д., и в то же времяECMAScript
Эти дескрипторы атрибутов делятся на две категории, а именно атрибуты данных и атрибуты доступа, и атрибуты данных и атрибуты доступа не могут сосуществовать.
Атрибут данных
Атрибут данных содержит расположение значения данных, где значение может быть прочитано и записано. Атрибут данных содержит четыре дескриптора, которые
-
configurable
Указывает, может ли он пройти
delete
Удалить свойство, можно изменить другие свойства дескриптора свойства или изменить свойство данных на свойство средства доступа. когда мы проходимlet obj = {name: ''}
При объявлении объекта все свойства в объектеconfigurable
Значение дескриптораtrue
-
enumerable
Указывает, может ли он пройти
for in
илиObject.keys
и другие методы для получения атрибута, значение этого дескриптора в объекте, который мы обычно объявляем, равноtrue
, но дляclass
Для свойств в классе значение равноfalse
-
writable
Указывает, можно ли изменить значение данных атрибута, изменив его на
false
, можно добиться эффекта атрибута только для чтения. -
value
Представляет значение данных текущего атрибута, при чтении значения атрибута считывается отсюда, при записи значений атрибута оно будет записано.
свойство доступа
Свойства аксессора не содержат значений данных, они содержатgetter
а такжеsetter
две функции одновременноconfigurable
а такжеenumerable
два дескриптора, совместно используемые атрибутами данных и атрибутами доступа.
-
getter
Эта функция вызывается при чтении свойств, по умолчанию эта функция
undefined
-
setter
Эта функция вызывается при записи значения свойства.По умолчанию эта функция
undefined
После понимания этих шести дескрипторов у вас может возникнуть несколько вопросов: Как определить и изменить эти дескрипторы атрибутов? Как эти дескрипторы атрибутов относятся к теме сегодняшней статьи? Тогда пришло время раскрыть ответ.
использоватьObject.defineProperty
понялvue2.0
Изучающие принцип двустороннего связывания должны знать,Vue
Двусторонняя привязка достигается с помощьюObject.defineProperty
для определения атрибутов данныхgetter
а такжеsetter
метод для реализации, например, есть объект ниже
let obj = {
name: '子君',
officialAccounts: '前端有的玩'
}
Я надеюсь, что имя пользователя в этом объекте нельзя изменить, используйтеObject.defineProperty
Как это определить?
Object.defineProperty(obj,'name', {
// 设置writable 是 false, 这个属性将不能被修改
writable: false
})
// 修改obj.name
obj.name = "君子"
// 打印依然是子君
console.log(obj.name)
пройти черезObject.defineProperty
Вы можете определить или изменить дескриптор свойства объекта, но поскольку свойства данных и свойства доступа являются взаимоисключающими, одновременно можно изменить только одно из них, что требует внимания.
Определить декоратор, препятствующий сотрясению
Оформление по сути все еще функция, но параметры функции фиксированы, как и декоратор стабилизации кода кода
/**
*@param wait 延迟时长
*/
function debounce(wait) {
return function(target, name, descriptor) {
descriptor.value = debounce(descriptor.value, wait)
}
}
// 使用方式
class MyClass {
@debounce(100)
follow() {
console.log('我是子君,我的公众号是 【前端有的玩】,关注有惊喜哦')
}
}
Разберем код построчно
- Сначала мы определяем
debounce
функция с одним параметромwait
, эта функция соответствует той, что используется при вызове декоратора ниже@debounce(100)
-
debounce
Функция возвращает новую функцию, которая является ядром декоратора, эта функция имеет три параметра, которые будут анализироваться один за другим.-
target
: Эта функция является атрибутом класса, установленным сверху, что соответствует приведенному выше примеру.MyClass
Добрый -
name
: Имя этой функции атрибута класса, соответствующее приведенному вышеfollow
-
descriptor
: это дескриптор атрибута, о котором мы упоминали ранее, непосредственноdescriptor
Вышеупомянутые свойства могут реализовывать свойства только для чтения, перезапись данных и другие функции.
-
- затем третья строка
descriptor.value = debounce(descriptor.value, wait)
, как мы видели ранее, дескриптор атрибута вышеvalue
Соответствует значению этого свойства, поэтому мы используем его, переопределяя это свойство.debounce
Функция завернута, так что в вызове функцийfollow
Когда фактический вызов является обернутой функцией
Выполнив три вышеуказанных шага, мы реализовали декоратор, который можно использовать для атрибута класса, и применили его к атрибуту класса.
существуетclass
Используйте декоратор на
Декораторы можно применять не только к атрибутам класса, но и напрямую к классам.Например, я надеюсь реализовать аналогичныйVue
Смешивание в таких функциях, смешивая некоторые атрибуты метода в класс, как это сделать?
// 这个是要混入的对象
const methods = {
logger() {
console.log('记录日志')
}
}
// 这个是一个登陆登出类
class Login{
login() {}
logout() {}
}
Как поставить вышеmethods
смешанныйLogin
, сначала мы реализуем декоратор класса
function mixins(obj) {
return function (target) {
Object.assign(target.prototype, obj)
}
}
// 然后通过装饰器混入
@mixins(methods)
class Login{
login() {}
logout() {}
}
Это реализует декоратор класса. Для декораторов классов есть только один параметр, которыйtarget
, что соответствует самому классу.
Разобравшись с декоратором, давайте посмотрим, какVue
с помощью декораторов.
существуетVue
использование декораторов в
использоватьts
развиватьVue
одноклассники должны быть правыvue-property-decorator
Это не будет незнакомо.Этот плагин предоставляет множество декораторов, которые удобно использовать при разработке каждому.Конечно, середина этой статьи не этот плагин. На самом деле, если наш проект не используетts
, вы также можете использовать декоратор, как его использовать?
Настройка базовой среды
За исключением некоторых старых проектов, сейчас мы обычно строим новые.Vue
Когда проект выберет использование строительных лесовvue-cli3/4
Заходите и создавайте новый проект.В это время вновь созданный проект уже поддерживает декоратор по умолчанию, и нет необходимости настраивать слишком много дополнительных вещей.Если ваш проект используетeslint
, то необходимо датьeslint
Настройте следующее.
parserOptions: {
ecmaFeatures:{
// 支持装饰器
legacyDecorators: true
}
}
Используйте декоратор
несмотря на то чтоVue
Компоненты, когда мы обычно пишемexport
То, что выходит, является объектом, но это не влияет на нас, используя декораторы непосредственно в компонентах, таких как в приведенном выше примере.log
Пример.
function log() {
/**
* @param target 对应 methods 这个对象
* @param name 对应属性方法的名称
* @param descriptor 对应属性方法的修饰符
*/
return function(target, name, descriptor) {
console.log(target, name, descriptor)
const fn = descriptor.value
descriptor.value = function(...rest) {
console.log(`这是调用方法【${name}】前打印的日志`)
fn.call(this, ...rest)
console.log(`这是调用方法【${name}】后打印的日志`)
}
}
}
export default {
created() {
this.getData()
},
methods: {
@log()
getData() {
console.log('获取数据')
}
}
}
Глядя на приведенный выше код, вы обнаружили, что вVue
Использование декораторов вclass
Свойства используются точно так же, как и выше, но следует отметить одну вещь:methods
Метод внутри использует декоратор, на данный момент декораторtarget
соответствуетmethods
.
кроме как вmethods
В дополнение к декораторам, описанным выше, вы также можете использовать декораторы в функциях хуков жизненного цикла.target
Соответствует всему объекту компонента.
Некоторые часто используемые декораторы
В следующем редакторе перечислены несколько декораторов, обычно используемых в проекте редактором, что удобно для использования всеми
1. Функция дросселирования и анти-тряски
Сценарии регулирования функций и защиты от сотрясений относительно широки и обычно используются черезthrottle
илиdebounce
Метод упаковывает вызываемую функцию. Теперь вы можете использовать содержимое, упомянутое выше, для инкапсуляции этих двух функций в декоратор.lodash
С помощью предоставленного метода вы также можете самостоятельно реализовать функцию дросселирования и защиты от сотрясений.
import { throttle, debounce } from 'lodash'
/**
* 函数节流装饰器
* @param {number} wait 节流的毫秒
* @param {Object} options 节流选项对象
* [options.leading=true] (boolean): 指定调用在节流开始前。
* [options.trailing=true] (boolean): 指定调用在节流结束后。
*/
export const throttle = function(wait, options = {}) {
return function(target, name, descriptor) {
descriptor.value = throttle(descriptor.value, wait, options)
}
}
/**
* 函数防抖装饰器
* @param {number} wait 需要延迟的毫秒数。
* @param {Object} options 选项对象
* [options.leading=false] (boolean): 指定在延迟开始前调用。
* [options.maxWait] (number): 设置 func 允许被延迟的最大值。
* [options.trailing=true] (boolean): 指定在延迟结束后调用。
*/
export const debounce = function(wait, options = {}) {
return function(target, name, descriptor) {
descriptor.value = debounce(descriptor.value, wait, options)
}
}
После инкапсуляции используйте его в компоненте
import {debounce} from '@/decorator'
export default {
methods:{
@debounce(100)
resize(){}
}
}
2. loading
При загрузке данных, чтобы предоставить удобную подсказку и предотвратить дальнейшую работу пользователей, перед запросом обычно отображается загрузка, а затем загрузка отключается после завершения запроса.Общий метод записи выглядит следующим образом.
export default {
methods:{
async getData() {
const loading = Toast.loading()
try{
const data = await loadData()
// 其他操作
}catch(error){
// 异常处理
Toast.fail('加载失败');
}finally{
loading.clear()
}
}
}
}
Мы можем поставить вышеloading
Логика переупакована с помощью декоратора следующим образом
import { Toast } from 'vant'
/**
* loading 装饰器
* @param {*} message 提示信息
* @param {function} errorFn 异常处理逻辑
*/
export const loading = function(message = '加载中...', errorFn = function() {}) {
return function(target, name, descriptor) {
const fn = descriptor.value
descriptor.value = async function(...rest) {
const loading = Toast.loading({
message: message,
forbidClick: true
})
try {
return await fn.call(this, ...rest)
} catch (error) {
// 在调用失败,且用户自定义失败的回调函数时,则执行
errorFn && errorFn.call(this, error, ...rest)
console.error(error)
} finally {
loading.clear()
}
}
}
}
Затем преобразуйте приведенный выше код компонента
export default {
methods:{
@loading('加载中')
async getData() {
try{
const data = await loadData()
// 其他操作
}catch(error){
// 异常处理
Toast.fail('加载失败');
}
}
}
}
3. Поле подтверждения
Когда вы нажимаете кнопку удаления, вам обычно нужно открыть окно с подсказкой, чтобы пользователь подтвердил, следует ли его удалить.В настоящее время обычный метод записи может быть таким:
import { Dialog } from 'vant'
export default {
methods: {
deleteData() {
Dialog.confirm({
title: '提示',
message: '确定要删除数据,此操作不可回退。'
}).then(() => {
console.log('在这里做删除操作')
})
}
}
}
Мы можем превратить подтвержденный выше процесс в декоратор, следующий код
import { Dialog } from 'vant'
/**
* 确认提示框装饰器
* @param {*} message 提示信息
* @param {*} title 标题
* @param {*} cancelFn 取消回调函数
*/
export function confirm(
message = '确定要删除数据,此操作不可回退。',
title = '提示',
cancelFn = function() {}
) {
return function(target, name, descriptor) {
const originFn = descriptor.value
descriptor.value = async function(...rest) {
try {
await Dialog.confirm({
message,
title: title
})
originFn.apply(this, rest)
} catch (error) {
cancelFn && cancelFn(error)
}
}
}
}
Затем, когда вы используете окно подтверждения, вы можете использовать его следующим образом.
export default {
methods: {
// 可以不传参,使用默认参数
@confirm()
deleteData() {
console.log('在这里做删除操作')
}
}
}
Легче в одно мгновение?Конечно, можно продолжать инкапсулировать много-много декораторов.Поскольку содержание статьи ограничено, эти три предоставлены временно.
Комбинация декораторов
Когда мы использовали декораторы для атрибутов класса выше, мы сказали, что декораторы можно использовать в комбинации.Vue
То же самое и с использованием компонентов, например, мы надеемся, что после подтверждения удаления интерфейс появится при вызове интерфейса.loading
, можно написать так (обязательно обратите внимание на порядок)
export default {
methods: {
@confirm()
@loading()
async deleteData() {
await delete()
}
}
}
Декораторы, определенные в этом разделе, были применены к этому проекту.GitHub.com/snow Zijun/V…, который основан на
Vant
Разработан готовый мобильный фреймворк, вам нужно толькоfork
Вниз, вы можете напрямую заниматься развитием бизнеса без какой-либо конфигурации, добро пожаловать в использование, если вы хотите беспокоить вас, чтобы датьstar
.
Меня зовут Zijun, и я сегодня так много написал.Эта статья была впервые опубликована на официальном аккаунте [Something Plays at the Front End].Добро пожаловать, обратите внимание.
Эпилог
Не истощайте свое вдохновение и воображение, не будьте рабом своих моделей. - Винсент Ван Гог