Краткое изложение проблем, требующих внимания в vue

задняя часть внешний интерфейс Vue.js Vuex

Статья впервые опубликована вличный блог

предисловие

При использовании 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 и данных Установлен: завершите гору

title

打开命令行在命令行中输入vm.a = 'change';查看效果

title

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Когда сработают эти две функции?

  • Откройте страницу, появится следующее

1

Используйте setTimeout для имитации сценария запроса внутреннего интерфейса.

  • нажмитеtitle2, происходит следующее

2

  • нажмите еще разtitle1, в следующих случаях вы обнаружите, что данные, запрошенные из бэкэнда, будут отображаться быстро, но если вы не используете их в это время

3

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;

vue серия статей