Эта проблема находится в реальной сцене, с которой я столкнулся в проекте Vue.Здесь я записываю свои мысли после того, как столкнулся с проблемой и как ее решить в конце (старшие программисты имеют плохую память-.-), и некоторые Vue будут вовлечены в процесс.Концепция исходного кода, такая как$mount
,render watcher
Подождите, если вы не знаете многого, вы можете взглянутьСерия статей по чтению исходного кода Vue ~
Проблема в следующем: данные, которые страница получает из фона,0
,1
например ключ, а значение, представленное этим ключом, такое как0-女
,1-男
Соответствующее отношение должно быть получено из другого интерфейса словаря данных; аналогичноТакой Апи:
{
"SEX_TYPE": [
{ "paramValue": 0, "paramDesc": "女" },
{ "paramValue": 1, "paramDesc": "男" }
]
}
Тогда, если вид получает0
, необходимо найти его описание в словаре女
И покажи это, начинается следующая история~
1. Думай
Некоторые говорят, что это не фильтрfilter
что делать, прямоVue.filterНет, но проблема в том, что этот фильтр можно получить только после ожидания возврата интерфейса асинхронного словаря данных.$mount
Если фильтр не найден, это приведет к ошибкам, которые повлияют на последующую визуализацию (белый экран и сообщение о неопределенной ошибке);
Есть два решения, о которых я могу думать:
- изменить интерфейс наСинхронизировать,существует
beforeCreate
илиcreated
Интерфейс словаря данных получается синхронно в хуке, чтобы гарантировать, что$mount
Вы можете получить зарегистрированный фильтр для обеспечения времени, но это заблокирует монтирование и продлит время белого экрана, поэтому это не рекомендуется; - Сделать регистрацию фильтра асинхронной и уведомить после получения фильтра
render watcher
Обновите себя, чтобы вы могли использовать собственное отзывчивое обновление Vue без блокировки рендеринга, поэтому этот метод изначально принят.
2. Реализация
потому что фильтр принадлежитasset_types, есть следующие выводы о цепочке доступа к assets_types в экземпляре Vue; для конкретной практики кода см.:Codepen - filter test
-
asset_types
включатьfilters
,components
,directives
, все следующиеasset_types
заменить их предыдущими элементами - в дочерних компонентах
asset_types
Не удается получить доступ к родительскому компонентуasset_types
, но может получить доступ к глобально зарегистрированным монтированиям в$root.$options.asset_types.__proto__
Вверхasset_types
, здесь соответствует исходному кодуsrc/core/util/options.js - Глобальный метод регистрации Vue.asset_types, такой как assets_types, зарегистрированные Vue.filters, будет подключен к корневому экземпляру (другие экземпляры
$root
)из$options.asset_types.__proto__
, и наследуется всеми экземплярами Vue, созданными в будущем, то есть все экземпляры Vue, созданные в будущем, могут получить к нему доступ - Область действия слота компонента ограничена местом, где он определен, то есть компонентом, в котором он определен, и не может получить доступ к родительскому компоненту.
asset_types
, но может получить доступ к глобально определенномуasset_types
- Точно так же, поскольку в main.js
new Vue()
instance — это корневой экземпляр, зарегистрированный вasset_types
будет установлен на$root.$options.asset_types
на вместо$root.$options.asset_types.__proto__
начальство
Согласно приведенным выше выводам, мы можем начать кодирование~
2.1 Использование фильтров корневого компонента
Поэтому первое, что я считаю, это смонтировать фильтр для регистрации на корневом компоненте, чтобы другие компоненты могли получить доступ к$root
Вы можете получить зарегистрированный фильтр, реализация здесь:
<template>
<div>
{{ rootFilters( sexVal )}}
</div>
</template>
<script type='text/javascript'>
import Vue from 'vue'
import { registerFilters } from 'utils/filters'
export default {
data() {
return {
sexVal: 1 // 性别
}
},
methods: {
/* 根组件上的过滤器 */
rootFilters(val, id = 'SEX_TYPE') {
const mth = this.$root.$options.filters[id]
return mth && mth(val) || val
}
},
created() {
// 把根组件中的filters响应式化
Vue.util.defineReactive(this.$root.$options, 'filters', this.$root.$options.filters)
},
mounted() {
registerFilters.call(this)
.then(data =>
// 这里获取到数据字典的data
)
}
}
</script>
js для регистрации фильтра
// utils/filters
import * as Api from 'api'
/**
* 获取并注册过滤器
* 注册在$root.$options.filters上不是$root.$options.filters.__proto__上
* 注意这里的this是vue实例,需要用call或apply调用
* @returns {Promise}
*/
export function registerFilters() {
return Api.sysParams() // 获取数据字典的Api,返回的是promise
.then(({ data }) => {
Object.keys(data).forEach(T =>
this.$set(this.$root.$options.filters, T, val => {
const tar = data[T].find(item => item['paramValue'] === val)
return tar['paramDesc'] || ''
})
)
return data
})
.catch(err => console.error(err, ' in utils/filters.js'))
}
Это делает фильтры на корневом компоненте отзывчивыми, а при рендерингеrootFilters
метод имеет доступ к созданному методу, который был сделан реактивным$root.$options.filters
, поэтому, когда асинхронно извлекаемые данные назначаются$root.$options.filters
, он вызовет повторный рендеринг наблюдателя рендеринга компонента, а затем снова получит его.rootFilters
Фильтр можно получить при использовании метода;
Так почему бы не зарегистрироваться напрямую с помощью метода Vue.filter, потому чтоObject.defineProperty
не могу контролировать__proto__
Изменения в данных и глобальный Vue.filter для регистрации фильтра в корневом компоненте$root.$options.asset_types.__proto__
, поэтому на его изменения нельзя реагировать.
Код здесь можно еще улучшить, но есть определенные проблемы с этим методом, во-первых, он используется здесьVue.util
метод, который не является стабильным, и его можно увидеть повсюду в использованииthis.$root.$options
Такой доступ к внутренним свойствам экземпляра vue является нецивилизованным и запутанным для чтения.
Поэтому, когда проект был завершен и ждал теста, я задумался.Кто бы сказал, что фильтр надо ставить в фильтры -. -, вы также можете использовать миксин для достижения этого
2.2 Использование примесей
Одна вещь, на которую следует обратить внимание при использовании миксинов, потому что vue помещает все данные в_
,$
Переменные в начале рассматриваются как внутренне зарезервированные переменные,не проксирует текущий экземпляр, так прямоthis._xx
недоступен и требуетthis.$data._xx
посетить.
// mixins/sysParamsMixin.js
import * as Api from 'api'
export default {
data() {
return {
_filterFunc: null, // 过滤器函数
_sysParams: null, // 获取数据字典
_sysParamsPromise: null // 获取sysParams之后返回的Promise
}
},
methods: {
/* 注册过滤器到_filterFunc中 */
_getSysParamsFunc() {
const { $data } = this
return $data._sysParamsPromise || ($data._sysParamsPromise = Api.sysParams()
.then(({ data }) => {
this.$data._sysParams = data
this.$data._filterFunc = {}
Object.keys(data).forEach(paramKey =>
this.$data._filterFunc[paramKey] = val => {
const tar = data[paramKey].find(item => item['paramValue'] === val)
return tar && tar['paramDesc'] || ''
})
return data
})
.catch(err => console.error(err, ' in src/mixins/sysParamsMixin.js')))
},
/* 按照键值获取单个过滤器 */
_rootFilters(val, id = 'SEX_TYPE') {
const func = this.$data._filterFunc
const mth = func && func[id]
return mth && mth(val) || val
},
/* 获取数据字典 */
_getSysParams() {
return this.$data._sysParams
}
}
}
положи сюдаApi
Обещание сохраняется, и если оно используется в другом месте, оно уже возвращается напрямуюresolved
Обещание государства, вам не нужно снова запросить данные. Кроме того, для удобного доступа в других случаях он устанавливается на корневом компоненте здесь.
что в нашемкорневой компонентКак использовать в:
// src/main.js
import sysParamsMixin from 'mixins/sysParamsMixin'
new Vue({
el: '#app',
mixins: [sysParamsMixin],
render: h => h(App),
})
В компоненте, который должен использовать фильтр:
<template>
<div>
{{ $root._rootFilters( sexVal )}}
</div>
</template>
<script type='text/javascript'>
export default {
data() {
return { sexVal: 1 }
},
mounted() {
this.$root._getSysParamsFunc()
.then(data =>
// 这里获取到数据字典的data
)
}
}
</script>
Здесь прописаны не только фильтры, но и выставлен словарь данных для облегчения отображения списков в определенных местах, ведь это частый сценарий в реальных проектах.
Конечно, лучше использовать vuex, но я лично не думаю, что vuex нужен здесь для сцены, если есть лучший способ, могу обсудить~
Большинство сообщений в Интернете имеют разную глубину и даже некоторые несоответствия. Следующие статьи являются кратким изложением процесса обучения. Если вы найдете какие-либо ошибки, пожалуйста, оставьте сообщение, чтобы указать ~
Ссылаться на:
PS: Всех приглашаю обратить внимание на мой публичный аккаунт [Front End Afternoon Tea], давайте работать вместе~
Кроме того, вы можете присоединиться к группе WeChat «Front-end Afternoon Tea Exchange Group», нажмите и удерживайте, чтобы определить QR-код ниже, чтобы добавить меня в друзья, обратите вниманиеДобавить группу, я заберу тебя в группу~