Статья впервые опубликована вличный блог
предисловие
При использовании Vue вы часто сталкиваетесь с некоторыми проблемами.На самом деле, если вы внимательно прочитаете официальные документы, вы обнаружите, что в документах упоминаются некоторые моменты, требующие особого внимания, чтобы понять объяснения этих проблем в официальном документы, некоторые материалы консультируются., в сочетании с моим собственным пониманием, я разобрался в некоторых общих проблемах, если какой-либо аспект объяснения не является разумным, я надеюсь, что все великие боги укажут на это;
Статья длинная, но очень практичная;
содержание
- Внутри компонента данные должны быть функцией
- Сценарии использования $set в vue
- Подробное объяснение жизненного цикла vue
- связь компонентов vue
- поддержка компонентов vue
- Функции/методы/часы жизненного цикла не должны использоваться внутри функциональной стрелки
- methods/computed/watch
1. В компоненте данные должны быть функцией
Аналоговый тип опорных данных Объект — это ссылочный тип данных, данные каждого компонента — это один и тот же адрес в памяти, одни данные меняются, другие тоже меняются;
Итак, какой метод можно использовать, чтобы сделать данные каждого компонента независимыми и незатронутыми?
Когда компонент определен, данные должны быть объявлены как функция, которая возвращает исходный объект данных, поскольку компонент может использоваться для создания нескольких экземпляров. Если бы данные по-прежнему были чистым объектом, все экземпляры имели бы общую ссылку на один и тот же объект данных! Предоставляя функцию данных, каждый раз, когда создается новый экземпляр, мы можем вызывать функцию данных, которая возвращает новую копию исходного объекта данных.
2. Сценарий использования $set в vue
Сцена 1:
Чтобы изменить значение массива через индекс массива, данные были изменены, но обновленная функция не срабатывает, а представление не обновляется.
export default {
data () {
return {
items: ['a', 'b', 'c']
};
},
updated () {
console.log('数据更新', this.items[0]);
},
methods: {
changeItem1 () {
this.items[0] = 'x';
console.log(111, this.items[0]);
},
changeItem2 () {
this.$set(this.items, 0, 'x');
console.log(222, this.items[0]);
},
}
};
Выполните changeItem1, консоль выводит 111 'x', обновление не запускается, и представление не обновляется. Выполнить changeItem2, вывести в консоль 222 'x', обновить данные 'x', триггер обновлен, просмотреть обновление
Сценарий 2: добавление и удаление свойств объекта не обнаруживаются в vue.
data() {
userProfile: {
name: '小明',
}
}
Хотите добавить атрибут возраста в профиль пользователя
addProperty () {
this.userProfile.age = '12';
console.log(555, this.userProfile);
}
Когда функция addProperty выполняется, печать выглядит следующим образом
555 { name: '小明', age: '12'}
Но обновление не срабатывает, вид не обновляется Измените его на следующее
addProperty () {
this.$set(this.userProfile, 'age', '12');
console.log(666, this.userProfile);
}
Выполните снова, данные изменятся, триггер обновится, и представление обновится;
Иногда вы хотите добавить несколько свойств к существующему объекту, например, используя методы Object.assign() или _.extend() для добавления свойств. Однако новые свойства, добавленные к объекту, не вызывают обновления. В этом случае может быть создан новый объект, который содержит свойства исходного объекта и новые свойства:
// 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
Это очень типичная проблема в Vue, вы должны быть внимательны при ее использовании!
Кратко объясните принцип:
Vue глубоко просматривает все атрибуты данных при создании экземпляра и используетObject.definePropertyПревратите все эти свойства в геттеры/сеттеры. Позвольте Vue отслеживать зависимости и уведомлять об изменениях при доступе к свойствам и их изменении. Таким образом, свойство должно существовать в объекте данных, чтобы Vue преобразовал его, чтобы он мог реагировать.
Когда вы добавляете новое свойство newProperty к объекту, новое добавленное свойство не имеет механизма для vue для обнаружения обновлений данных (поскольку оно добавляется после инициализации), vue.$set должен сообщить vue, что вы добавили свойство , он сделает обработку для вас
3. Подробное объяснение жизненного цикла vue
1. Жизненный цикл vue
- beforeCreate: экземпляр компонента был только что создан, прежде чем будут вычислены свойства компонента, такие как свойство данных
- created: Экземпляр компонента создан, свойства привязаны, но DOM не завершен, а свойство $el еще не существует.
- beforeMount: перед компиляцией/монтированием шаблона
- смонтирован: после того, как шаблон скомпилирован/смонтирован
- beforeUpdate: перед обновлением компонента
- обновлено: после обновления компонента
- activated: for
keep-alive
, вызывается при активации компонента - deactivated: for
keep-alive
, вызывается при удалении компонента - beforeDestroy: вызывается перед уничтожением компонента
- уничтожено: вызывается после уничтожения компонента
ps: следующий код можно напрямую скопировать и выполнить
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<script type="text/javascript" src="https://cdn.jsdelivr.net/vue/2.1.3/vue.js"></script>
<body>
<div id="app">{{a}}</div>
<script>
var vm = new Vue({
el: '#app',
data: {
a: 'vuejs',
},
beforeCreate: function() {
console.log('创建前');
console.log(this.a);
console.log(this.$el);
},
created: function() {
console.log('创建之后');
console.log(this.a);
console.log(this.$el);
},
beforeMount: function() {
console.log('mount之前');
console.log(this.a);
console.log(this.$el);
},
mounted: function() {
console.log('mount之后');
console.log(this.a);
console.log(this.$el);
},
beforeUpdate: function() {
console.log('更新之前');
console.log(this.a);
console.log(this.$el);
},
updated: function() {
console.log('更新完成');
console.log(this.a);
console.log(this.$el);
},
beforeDestroy: function() {
console.log('组件销毁之前');
console.log(this.a);
console.log(this.$el);
},
destroyed: function() {
console.log('组件销毁之后');
console.log(this.a);
console.log(this.$el);
},
})
</script>
</body>
</html>
beforeCreated: el и данные не инициализированы
Создано: завершить инициализацию данных данных, EL не BeForemount: завершен инициализация EL и данных Установлен: завершите гору
打开命令行在命令行中输入vm.a = 'change';查看效果
4. Коммуникация компонентов Vue
1. Родительский компонент передает данные дочернему компоненту
Vue использует свойства для передачи данных дочерним компонентам. 1): дочерний компонент создает свойство в свойствах для получения значения, переданного родительским компонентом. 2): Зарегистрируйте дочерний компонент в родительском компоненте 3): Добавьте свойства, созданные в свойствах подкомпонента, в теге подкомпонента. 4): Назначьте этому свойству значение, которое необходимо передать дочернему компоненту.
2. Дочерний компонент передает данные родительскому компоненту
Дочерние компоненты в основном передают данные родительским компонентам через события. 1), дочерний компонент должен каким-то образом инициировать пользовательское событие, например, метод события клика. 2), принять значение, которое будет передано, как второй параметр $emit, и значение будет передано как реальный параметр в метод соответствующего пользовательского события. 3), зарегистрируйте дочерний компонент в родительском компоненте и привяжите пользовательские прослушиватели событий к метке дочернего компонента.
3. Подкомпоненты передают данные подкомпонентам
Vue ищет метод, который не имеет прямых подкомпонентов для передачи параметров в подкомпоненты.Рекомендуется объединить компоненты, которые должны передавать данные в один компонент.Если вы должны передать параметры в подкомпоненты, вы можете передать их сначала в родительский компонент, а затем передать в подкомпоненты, чтобы облегчить разработку, vue запустил инструмент управления состоянием vuex, который может легко реализовать передачу параметров между компонентами
Конкретный пример кода выглядит следующим образом: вы можете обратиться к соответствующему коду и попробовать его в редакторе. Родительский компонент передает данные дочернему компоненту
// 父组件向子组件传递数据
<!--
msg 是在data中(父组件)定义的变量
如果需要从父组件中获取logo的值,就需要使用props['msg'], 如30行
在props中添加了元素以后,就不需要在data中(子组件)中再添加变量了
-->
<template>
<div>
<child @transferuser="getUser" :msg="msg"></child>
<p>用户名为:{{user}}(我是子组件传递给父组件的数据)</p>
</div>
</template>
<script>
import child from './child.vue';
export default {
components: {
child,
},
data() {
return {
user: '',
msg: '我是父组件传给子组件的信息',
};
},
methods: {
getUser(msg) {
this.user = msg;
console.log(msg);
},
},
};
</script>
Дочерний компонент передает данные родительскому компоненту
// 子组件向父组件传递数据
<!--
1.@ : 是 v-on的简写
2.子组件主要通过事件传递数据给父组件
3.当input的值发生变化时,将username传递给parent.vue,首先声明了一个setUser,用change事件来调用setUser
4.在setUser中,使用了$emit来遍历transferUser事件,并返回this.username,其中transferuser是一个自定义事件,功能类似一个中转,this.username通过这个事件传递给父组件
-->
<template>
<div>
<div>{{msg}}</div>
<span>用户名</span>
<input v-model="username" @change='setUser'>向父组件传值</button>
</div>
</template>
<script>
export default {
data() {
return {
username: '测试',
};
},
props: {
msg: {
type: String,
},
},
methods: {
setUser() {
this.$emit('transferuser', this.username);
},
},
};
</script>
5. поддержка компонентов vue
Я не заметил, когда написал vue в проекте<keep-alive></keep-alive>
Этот компонент недавно подробно изучил функции жизненного цикла компонентов vue, что делает каждая функция, а затемactivated
а такжеdeactivated
Эти две функции<keep-alive></keep-alive>
Этот компонент относится к
-
activated
: Вызывается при активации компонента поддержки активности. -
deactivated
: вызывается, когда компонент проверки активности отключен.
постоянное использование
-
<keep-alive>
При обертывании динамических компонентов неактивные экземпляры компонентов кэшируются, а не уничтожаются. -
<keep-alive>
является абстрактным компонентом: он не отображает элемент DOM сам по себе и не появляется в цепочке родительских компонентов. - когда компонент находится в
<keep-alive>
переключается внутри, егоactivated
а такжеdeactivated
Эти две функции ловушки жизненного цикла будут выполняться соответственно
Конкретные примеры следующие
- это простой переключатель вкладок, вы можете попробовать поставить
<keep-alive>
Сняв его, сравните его, и тогда вы найдете его преимущества
test.vue
<template>
<div class="test">
<div class="testNav">
<div :class="{'selected':tab === 1,'testTitle':true}" @click="toTab(1)">标题一</div>
<div :class="{'selected':tab === 2,'testTitle':true}" @click="toTab(2)">标题二</div>
</div>
<div class="container">
<keep-alive>
<Test1 v-if="tab === 1">
</Test1>
<Test2 v-else>
</Test2>
</keep-alive>
</div>
</div>
</template>
<script>
import Test1 from './test1.vue';
import Test2 from './test2.vue';
export default {
data() {
return {
tab: 1,
};
},
components: {
Test1,
Test2,
},
methods: {
toTab(index) {
this.tab = index;
},
},
}
</script>
<style lang="less">
.test {
width: 100%;
.testNav {
height: 60px;
line-height: 60px;
display: flex;
border-bottom: 1px solid #e5e5e5;
.testTitle {
flex: 1;
text-align: center;
}
.selected {
color: red;
}
}
}
</style>
Результаты теста следующие:
Обратите внимание на информацию на странице и выводе в консоль, вы сможете заметить ее более интуитивно<keep-alive>
роль иactivated
а такжеdeactivated
Когда сработают эти две функции?
- Откройте страницу, появится следующее
Используйте setTimeout для имитации сценария запроса внутреннего интерфейса.
- нажмите
title2
, происходит следующее
- нажмите еще раз
title1
, в следующих случаях вы обнаружите, что данные, запрошенные из бэкэнда, будут отображаться быстро, но если вы не используете их в это время
test1.vue
а такжеtest2.vue
Соответствующий код выглядит следующим образом:
test1.vue
<template>
<div class="test1">
test1
{{testInfo1}}
</div>
</template>
<script>
export default {
data() {
return {
testInfo1: '',
};
},
activated() {
console.log('测试1被激活');
},
deactivated() {
console.log('测试1被缓存');
},
created() {
setTimeout(() => {
this.testInfo1 = '这是测试一的数据';
}, 2000);
},
}
</script>
test2.vue
<template>
<div>
test2
{{testInfo2}}
</div>
</template>
<script>
export default {
data() {
return {
testInfo2: '',
}
},
activated() {
console.log('测试2被激活');
},
deactivated() {
console.log('测试2被缓存');
},
created() {
setTimeout(() => {
this.testInfo2 = '这是测试二的数据';
}, 2000);
},
}
</script>
6. Стрелочные функции не должны использоваться в функциях/методах/часах жизненного цикла.
Стрелка появляется функции ES6 - это то, что мы можем использовать меньше кода для достижения функции, следует отметить функцию стрелки и нормальную функцию самой большой разницы указывает на проблему: эта функция стрелки, указывающая на функцию, которая находится с доменом, эта общая функция, указывающая вызывающий абонент функции;
На это указывали специальные напоминания в официальной документации:
В vue функции жизненного цикла, методы и контроль автоматически связывают этот контекст с экземпляром, чтобы вы могли получать доступ к данным и выполнять операции со свойствами и методами. Это означает, что вы не можете использовать стрелочную функцию для определения метода жизненного цикла, потому что стрелочная функция привязана к родительскому контексту, поэтому это не то же самое, что ожидаемый экземпляр Vue.
7.methods/computed/watch
methods VS computed
Мы можем определить одну и ту же функцию как методы или вычисляемые.В этих двух случаях результат один и тот же, разница в том, что вычисляемые свойства кэшируются на основе их зависимостей, а вычисляемые свойства используются только при изменении их связанных зависимостей.
Применимая сцена:
Если пересчет дорог, выберите вычисляемый; если вы не хотите иметь кеш, выберите методы
computed vs watch
watch имеет два параметра, старые и новые значения, вычисляемые свойства — нет, но вычисляемые свойства могут получать новые значения от сеттеров
О вычисляемых
Особое примечание о вычисляемых свойствах: вычисляемое свойство Vue по умолчанию имеет только геттеры.Когда вам нужно использовать геттеры, вам нужно добавить сеттер самостоятельно.
export default {
data () {
return {
firstName: '张',
lastName: '三',
};
},
computed: {
fullName() {
return this.firstName + ' ' + this.lastName
},
},
methods: {
changeFullName () {
this.fullName = '李 四';
}
},
};
其中computed里的代码完整写法是
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
}
},
Выполнить changeFullName и найти ошибку[Vue warn]: Computed property "fullame" was assigned to but it has no setter.
Нам нужно добавить сеттер к вычисляемому свойству fullName
computed: {
fullName: {
// getter
get: function () {
return this.firstName + ' ' + this.lastName
},
// setter
set: function (newValue) {
var names = newValue.split(' ')
this.firstName = names[0]
this.lastName = names[names.length - 1]
}
}
},
Суммировать
Вышеуказанные проблемы исходят изvue официальная документацияКонечно, если вы хотите понять, почему, вам нужно начать сАнализ исходного кода VueНачало;
В следующей статье предполагается начать с исходного кода, чтобы объяснить эти проблемы и понять общее программирование vue;