Знание подготовки проекта --- краткое изложение методов коммуникации компонентов vue3

Операционная платформа выбора Силиконовой долины

Стек технологий этого проекта включает в себя: vue3+TypeScript+vue-router+pinia+element-plus+axios+echarts и т. д.

заказ товара адрес
Метод связи компонента Vue3 https://blog.csdn.net/m0_55644132/article/details/130711542

1. Метод связи компонента Vue3

Метод связи компонента Vue2 :

props : могут передаваться компоненты «родитель-потомок», «потомок-родитель» и даже одноуровневые компоненты.

Пользовательские события : может быть достигнута связь между дочерними и родительскими компонентами.

Глобальная шина событий $bus : может реализовать связь между произвольными компонентами.

pubsub : режим публикации-подписки для произвольного взаимодействия компонентов

vuex : Контейнер централизованного управления состоянием, обеспечивающий связь между произвольными компонентами.

ref : родительский компонент получает VC экземпляра дочернего компонента и получает ответные данные и методы дочернего компонента.

slot : Слоты (слоты по умолчанию, именованные слоты, слоты с ограниченной областью действия) реализуют связь между родительскими и дочерними компонентами...

1.1 реквизит

props может реализовать связь между родительскими и дочерними компонентами.В vue3 мы можем получить данные, переданные родительским компонентом, через defineProps. И нет необходимости вводить метод defineProps внутри компонента , и его можно использовать напрямую!

Передать данные от родительского компонента к дочернему компоненту

// 父组件中给子组件 Child 传数据--静态/动态数据
<Child info="我爱祖国" :money="money"></Child>

Дочерний компонент получает данные, переданные родительским компонентом: метод 1: запись объекта

let props = defineProps({
    
    
  info:{
    
    
   type:String,//接受的数据类型
   default:'默认参数',//接受默认数据
  },
  money:{
    
    
   type:Number,
   default:0
}})

Дочерний компонент получает данные, переданные родительским компонентом: метод 2: запись массива

let props = defineProps(["info",'money']);

Подкомпоненты могут использовать данные пропсов в шаблоне после получения данных пропсов, но помните, что пропсы доступны только для чтения (можно только читать, нельзя изменять)

1.2 Пользовательские события

В среде Vue есть два типа событий: одно — собственное событие DOM, а другое — пользовательское событие. (нужно добавить .native в vue2)

Собственные события DOM позволяют пользователям взаимодействовать с веб-страницами, например, click, dbclick, change, mouseenter, mouseleave...

Пользовательские события могут реализовывать дочерние компоненты для передачи данных родительским компонентам.

1.2.1 Собственные события DOM

код показывает, как показано ниже:

 <pre @click="handler">
      我是祖国的老花骨朵
 </pre>

На текущем уровне кода собственное событие щелчка события DOM привязано к предварительному тегу, а объект события события по умолчанию вводится в обратный вызов события. Конечно, если вы хотите внедрить несколько параметров в событие щелчка, вы можете действовать, как показано на рисунке ниже. Но помните, что внедренный объект события должен называться $event

  <div @click="handler1(1,2,3,$event)">我要传递多个参数</div>

В среде vue3 click, dbclick и change (такие собственные события DOM), будь то теги или пользовательские теги (теги компонентов), являются собственными событиями DOM .

Это не относится к vue 2. В vue 2 теги компонентов должны передавать нативные модификаторы , чтобы стать нативными событиями DOM.

1.2.2 Пользовательские события

Пользовательские события могут позволить дочерним компонентам передавать данные родительским компонентам, что чаще используется в проектах.

Например, привяжите пользовательское событие к дочернему компоненту (Event2) внутри родительского компонента.

<Event2  @xxx="handler3"></Event2>

Запустите это пользовательское событие внутри подкомпонента Event2

<template>
  <div>
    <h1>我是子组件2</h1>
    <button @click="handler">点击我触发xxx自定义事件</button>
  </div>
</template>

<script setup lang="ts">
let $emit = defineEmits(["xxx"]);
const handler = () => {
    
    
  $emit("xxx", "法拉利", "茅台");
};
</script>
<style scoped>
</style>

Мы обнаружим, что внутри тега script используется метод defineEmits Этот метод предоставляется vue3, и его не нужно вводить и использовать напрямую. Выполняется метод defineEmits и передается массив. Элементы массива — это типы пользовательских событий, которые компонент должен инициировать в будущем. Этот метод вернет метод $emit для запуска пользовательских событий .

Когда кнопка нажата, обратный вызов события внутренне вызывает метод $emit для запуска пользовательского события.Первый параметр — это тип триггерного события, а второй, третий и N параметры — это данные, передаваемые родительскому компоненту.

Примечание: код выглядит следующим образом

<Event2  @xxx="handler3" @click="handler"></Event2>

Примечание . Обычно говорят, что запись метки компонента @click должна быть собственным событием DOM, но если подкомпонент определен внутри через defineEmits, он становится настраиваемым событием.

let $emit = defineEmits(["xxx",'click']);

1.3 Глобальная шина событий

Глобальная шина событий может реализовать любую компонентную связь.В vue2 глобальная шина событий может быть запущена в соответствии с отношениями между VM и VC. Но в vue3 нет конструктора Vue, поэтому нет Vue.prototype, а в комбинированном API этого нет, поэтому реализовать функцию шины глобальных событий во Vue3 немного нереально. функция шины событий в Vue3. Этого можно добиться с помощью плагина mitt .

рукавица: официальный адрес сайта:https://www.npmjs.com/package/mitt

источник/автобус/index.ts

//引入mitt插件:mitt一个方法,方法执行会返回bus对象
import mitt from 'mitt';
const $bus = mitt();
export default $bus;

В подкомпоненте 1 — получение данных

import $bus from "../../bus";
//组合式API函数
import {
    
     onMounted } from "vue";
//组件挂载完毕的时候,当前组件绑定一个事件,接受将来兄弟组件传递的数据
onMounted(() => {
    
    
  //第一个参数:即为事件类型  第二个参数:即为事件回调
  $bus.on("car", (car) => {
    
    
    console.log(car);
  });

В подкомпоненте 2 — отправка данных (связь с братским компонентом)

<button @click="handler">点击我给兄弟送一台法拉利</button>

//引入$bus对象
import $bus from '../../bus';
//点击按钮回调
const handler = ()=>{
    
    
  $bus.emit('car',{
    
    car:"法拉利"});
}

1.4 v-модель

Команда v-model может собирать данные формы (двусторонняя привязка данных), а также осуществлять синхронизацию данных родительского и дочернего компонентов.

И v-model на самом деле относится к реализации использования props[modelValue] и пользовательского события [update:modelValue].

Код ниже: эквивалентен передаче реквизита (modelValue) дочернему компоненту и привязке пользовательского события update:modelValue.

Реализовать синхронизацию данных родительского и дочернего компонентов

// 父组件中
<Child v-model="msg"></Child>

В vue3 компонент может использовать несколько v-моделей для синхронизации нескольких данных между родительским и дочерним компонентами.Приведенный ниже код эквивалентен передаче двух реквизитов дочернему компоненту, а именно pageNo и pageSize, и привязке двух пользовательских событий update:pageNo Synchronize parent -дочерние данные с обновлением: pageSize

<Child v-model:pageNo="msg" v-model:pageSize="msg1"></Child>

Примечание. Если параметры дочернего компонента не используются в родительском компоненте, нет необходимости готовить функцию обратного вызова (дочернему компоненту не нужно передавать данные родительскому компоненту), а дочерний компонент может запускаться напрямую

А если использовать v-model, то это равносильно тому, что родительский компонент готовит callback-функцию (на самом деле она не прописана, имя дочернего компонента при ее получении определяется нами самими, типа update:pageNo), и затем передается дочернему компоненту, дочерний компонент может быть запущен (обратите внимание, что это эквивалентно!)

1.5 использование атрибутов

В Vue3 вы можете использовать метод useAttrs для получения атрибутов и событий компонента (в том числе: собственных событий DOM или пользовательских событий), а функции вторичных функций аналогичны атрибутам и методам $attrsво $listenersфреймворке Vue2.

Например: используйте my-button дочернего компонента внутри родительского компонента.

<my-button type="success" size="small" title='标题' @click="handler"></my-button>

Атрибуты и события компонента можно получить с помощью метода useAttrs внутри подкомпонента. Итак, вы также обнаружили, что он похож на props и может принимать свойства и значения свойств, передаваемые родительским компонентом. **Следует отметить, что если defineProps принимает определенный атрибут, объект, возвращаемый методом useAttrs, не будет иметь соответствующего атрибута и значения атрибута.

// 子组件使用useAttrs接收父组件传的东西
<script setup lang="ts">
import {
    
    useAttrs} from 'vue';
let $attrs = useAttrs();
</script>

useAttrs — это восходящая операция. Если реквизиты получены, то useAttrs исчезает. реквизиты имеют более высокий приоритет

1.6 ссылка и $parent

ref, когда дело доходит до ref, вы можете подумать, что он может получить DOM элемента или VC экземпляра подкомпонента. Поскольку VC экземпляра дочернего компонента может быть получен через ref внутри родительского компонента, методы и ответные данные внутри дочернего компонента могут использоваться родительским компонентом.

Например: получить экземпляр компонента после монтирования родительского компонента.

Внутренний код родительского компонента:

<template>
  <div>
    <h1>ref与$parent</h1>
    <Son ref="son"></Son>
  </div>
</template>
<script setup lang="ts">
import Son from "./Son.vue";
import {
    
     onMounted, ref } from "vue";
const son = ref();
onMounted(() => {
    
    
  console.log(son.value);
});
</script>

Однако следует отметить, что если вы хотите, чтобы родительский компонент получал данные или методы дочернего компонента, вам необходимо выставить его во внешний мир через defineExpose, потому что данные внутри компонента в vue3 «закрыты» для внешний мир и не может быть доступен извне. (Получить экземпляр компонента, но не данные компонента)

<script setup lang="ts">
import {
    
     ref } from "vue";
//数据
let money = ref(1000);
//方法
const handler = ()=>{
    
    
}
defineExpose({
    
    
  money,
   handler
})
</script>

$parent может получить VC экземпляра родительского компонента определенного компонента, поэтому вы можете использовать данные и методы внутри родительского компонента. Внутри дочернего компонента должна быть кнопка для получения экземпляра родительского компонента при нажатии.Конечно, данные и методы родительского компонента должны быть доступны для внешнего мира через метод defineExpose.

// 子组件中---注入$parent,必须叫这个;同时父组件的数据也要对外暴露
<button @click="handler($parent)">点击我获取父组件实例</button>

1.7 предоставлять и вводить

предоставить [обеспечить]

впрыснуть [ впрыснуть ]

Vue3 предоставляет два метода: обеспечить и внедрить, которые могут реализовать передачу параметров между компонентами . Компоненты-предки передают данные компонентам-потомкам.

Компоненты-предки предоставляют данные:

Для предоставления данных используется метод Provide , который должен передавать два параметра, предоставляя ключ данных и значение данных соответственно.

<script setup lang="ts">
import {
    
    provide} from 'vue'
provide('token','admin_token');// 后代都可以通过inject方法去使用这个数据
</script>

Компоненты-потомки могут получать данные через метод inject и получать хранимое значение через ключ

<script setup lang="ts">
import {
    
    inject} from 'vue'
let token = inject('token');
</script>

Примечание : компоненты-потомки могут изменять данные, и компоненты-предки также изменяются соответствующим образом. Это одно из отличий от реквизита

1.8пиния

официальный сайт пинии:https://pinia.web3doc.top/

pinia также является контейнером состояния централизованного управления, похожим на vuex. Но основная концепция не имеет мутаций и модулей, а метод использования относится к официальному сайту.

Недостатки: Как и в vuex, сохраненные данные не являются постоянными.

Метод записи API опции pinia

источник/магазин/index.ts

//创建大仓库
import {
    
     createPinia } from 'pinia';
//createPinia方法可以用于创建大仓库
let store = createPinia();
//对外暴露,安装仓库
export default store;

Входной файл main.ts

//引入仓库
import store from './store'
app.use(store)

Создайте небольшой склад

источник/магазин/модули/info.ts

//定义info小仓库
import {
    
     defineStore } from "pinia";
//第一个仓库:小仓库名字  第二个参数:小仓库配置对象
//defineStore方法执行会返回一个函数,函数作用就是让组件可以获取到仓库数据
let useInfoStore = defineStore("info", {
    
    
    //存储数据:state
    state: () => {
    
    
        return {
    
    
            count: 99,
            arr: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        }
    },
    actions: {
    
    
        //注意:函数没有context上下文对象
        //没有commit、没有mutations去修改数据
        updateNum(a: number, b: number) {
    
    
            this.count += a;
        }
    },
    getters: {
    
    
        total() {
    
    
            let result:any = this.arr.reduce((prev: number, next: number) => {
    
    
                return prev + next;
            }, 0);
            return result;
        }
    }
});
//对外暴露方法
export default useInfoStore;

Компоненты хотят использовать данные, дочерние компоненты (другие компоненты также могут использоваться)

import useInfoStore from "../../store/modules/info";
//获取小仓库对象
let infoStore = useInfoStore();

// 使用
<h1>{
    
    {
    
     infoStore.count }}---{
    
    {
    
    infoStore.total}}</h1>

Измените данные в хранилище непосредственно в компоненте, или используйте **$patch** для изменения в хранилище, или используйте метод записи, аналогичный vuex (напишите метод изменения данных хранилища в действии, тогда компонент может вызвать метод модификации на складе )

Примечание: функция не имеет объекта контекста, фиксации и мутаций для изменения данных; используйте это для изменения

// 组件中
//1 直接修改
const updateCount = ()=> {
    
    
    infoStore.count++;
}

//2 通过 仓库方法$patch 修改
const updateCount = ()=> {
    
    
    infoStore.$patch({
    
    
        count:1111;//新数据替换旧的
    })
}

//3 actions中修改,组件中可以传参数过来的
updateNum(a: number, b: number) {
    
    
    this.count += a;
}

Использование геттеров на складе

getters: {
    
    
    total() {
    
    
        let result:any = this.arr.reduce((prev: number, next: number) => {
    
    
            return prev + next;
        }, 0);
        return result;
    }
}

Как написать комбинированный API pinia

//定义组合式API仓库
import {
    
     defineStore } from "pinia";
import {
    
     ref, computed,watch} from 'vue';
//创建小仓库,第二个参数是箭头函数
let useTodoStore = defineStore('todo', () => {
    
    
    let todos = ref([{
    
     id: 1, title: '吃饭' }, {
    
     id: 2, title: '睡觉' }, {
    
     id: 3, title: '打豆豆' }]);
    let arr = ref([1,2,3,4,5]);

    // 实现getters
    const total = computed(() => {
    
    
        return arr.value.reduce((prev, next) => {
    
    
            return prev + next;
        }, 0)
    })
    //务必要返回一个对象:属性与方法可以提供给组件使用
    return {
    
    
        todos,
        arr,
        total,
        updateTodo() {
    
    
            todos.value.push({
    
     id: 4, title: '组合式API方法' });
        }
    }
});

export default useTodoStore;

Геттеры в комбинированном API могут быть реализованы через вычисляемые свойства, можно использовать даже мониторинг Vue и т. д.

1.9 слот

Слоты: слоты по умолчанию, именованные слоты и слоты с заданной областью действия могут реализовывать связь между родительскими и дочерними компонентами.

Слот по умолчанию:

Напишите глобальный тег компонента слота в шаблоне внутри подкомпонента

// 子组件
<template>
  <div>
    <slot></slot>
  </div>
</template>
<script setup lang="ts">
</script>
<style scoped>
</style>

Предоставьте структуру внутри родительского компонента: Todo является дочерним компонентом. При использовании внутри родительского компонента напишите структуру внутри двойного тега и передайте ее дочернему компоненту.

Обратите внимание, что при разработке проекта обычно используется только один слот по умолчанию.

<Todo>
  <h1>我是默认插槽填充的结构</h1>
</Todo>

Именованные слоты:

Как следует из названия, этот слот с именем оставляет внутри компонента несколько слотов с указанным именем.

Следующее находится внутри подкомпонента, оставляя два слота в шаблоне

<template>
  <div>
    <h1>todo</h1>
    <slot name="a"></slot>
    <slot name="b"></slot>
  </div>
</template>
<script setup lang="ts">
</script>

<style scoped>
</style>

Родительский компонент внутренне передает структуру в указанный именованный слот. Нужно обратить внимание на v-слот: можно заменить на #

<template>
  <div>
    <h1>slot</h1>
    <Todo>
      <template v-slot:a>  //可以用#a替换
        <div>填入组件A部分的结构</div>
      </template>
      <template v-slot:b>//可以用#b替换
        <div>填入组件B部分的结构</div>
      </template>
    </Todo>
  </div>
</template>

<script setup lang="ts">
import Todo from "./Todo.vue";
</script>
<style scoped>
</style>

Слоты с ограниченной областью действия

Слот Scope: можно понять, что данные дочернего компонента предоставляются родительским компонентом, но структура и внешний вид (стиль) дочернего компонента не могут быть определены внутренне

Код подкомпонента Todo выглядит следующим образом:

<template>
  <div>
    <h1>todo</h1>
    <ul>
     <!--组件内部遍历数组-->
      <li v-for="(item,index) in todos" :key="item.id">
         <!--作用域插槽将数据回传给父组件-->
         <slot :$row="item" :$index="index"></slot>
      </li>
    </ul>
  </div>
</template>
<script setup lang="ts">
defineProps(['todos']);//接受父组件传递过来的数据
</script>
<style scoped>
</style>

Внутренний код родительского компонента выглядит следующим образом:

<template>
  <div>
    <h1>slot</h1>
    <Todo :todos="todos">
      <template v-slot="{$row,$index}">
         <!--父组件决定子组件的结构与外观-->
         <span :style="{color:$row.done?'green':'red'}">{
   
   {$row.title}}</span>
      </template>
    </Todo>
  </div>
</template>

<script setup lang="ts">
import Todo from "./Todo.vue";
import {
      
       ref } from "vue";
//父组件内部数据
let todos = ref([
  {
      
       id: 1, title: "吃饭", done: true },
  {
      
       id: 2, title: "睡觉", done: false },
  {
      
       id: 3, title: "打豆豆", done: true },
]);
</script>
<style scoped>
</style>

Supongo que te gusta

Origin blog.csdn.net/m0_55644132/article/details/130711542
Recomendado
Clasificación