Summary of important knowledge points of Vue.js IV

overview

  • ref toRef toRefs advanced, in-depth understanding
  • vue3 setup
  • Why is Vue3 faster than Vue2?
  • How to understand Vue's one-way data flow?
  • The principle of event binding in Vue
  • vue3 mitt uses

ref toRef toRefs advanced, in-depth understanding

  1. Why is ref needed?

    1. The return value type will lose the responsiveness
    2. setup, computed, synthetic functions, all may return value types
    3. If Vue does not define ref, the user will customize ref, which will be confusing
  2. Why do you need .value?

    1. ref is an object (without loss of responsiveness), value stores the value
    2. Realize responsiveness through the get and set of the .value attribute
    3. When used in templates and reactive, .value is not required, and it is required in other cases
  3. Why do we need toRef toRefs

    1. Original intention: Decompose and diffuse object data without losing responsiveness
    2. Premise: The target object is a responsive object, not an ordinary object
    3. Note: do not create responsive, but continue responsive

For more exciting content, please search for " " on WeChat前端爱好者 , and click me to view .

vue3 setup

What does script setup do?

scrtpt setup is a grammatical sugar of vue3, which simplifies the writing of combined API and has better running performance.

Features of syntactic sugar using script setup :

  • Properties and methods do not need to be returned and can be used directly.
  • When a component is introduced, it will be automatically registered without manual registration through components.
  • Use defineProps to receive the value passed by the parent component.
  • useAttrs to get attributes, useSlots to get slots, and defineEmits to get custom events.
  • By default, no attributes will be exposed to the outside world, and defineExpose can be used if necessary.

How to get component instance in setup?

  • There is no this in setup and other Composition APIs
  • You can still use this in the Options API
  • In the Composition API, you can use the getCurrentInstance method to obtain

vue3 getCurrentInstance

In Vue2, the current component instance can be obtained through this;

In Vue3, the component instance cannot be obtained through this in the setup, and the value printed by console.log(this) is undefined.

In Vue3, getCurrentInstance() can be used to get the current component instance vue3 official document explanation

let { proxy } = getCurrentInstance();

Print the following three values ​​in the setup, and the results are as follows:

console.log(getCurrentInstance,typeof(getCurrentInstance));
console.log(getCurrentInstance(),typeof(getCurrentInstance()));
console.log(proxy,typeof(proxy));

result

can be seen:

  • getCurrentInstance is a function method,
  • getCurrentInstance() is an object, and proxy is also an object.
  • Proxy is an attribute in the getCurrentInstance() object, and the proxy is obtained by deconstructing and assigning the object.

getCurrentInstance can only be used in setupor 生命周期钩子.

print getCurrentInstance in onMunted life cycle

Define a test method that is triggered by the click event

onMounted(() => {
  console.log(getCurrentInstance(), typeof getCurrentInstance());
});
function test() {
  console.log(getCurrentInstance(), typeof getCurrentInstance());
}

It can be seen that the instance cannot be obtained in the function.

let { ctx } = getCurrentInstance();
console.log(ctx, typeof ctx);
let { proxy } = getCurrentInstance();
console.log(proxy, typeof proxy);

Both ctx and proxy are attributes in the getCurrentInstance() object, which are obtained by deconstructing and assigning. It can be seen that the two are different.

ctx is an ordinary object, and proxy is a Proxy object.

Supplement: Big pit about getCurrentInstance in Vue3

Only suitable for debugging in development! Do not use it in an online environment, otherwise there will be problems!

solution:

plan 1.

Get the method mounted in the global

const instance = getCurrentInstance()
console.log(instance.appContext.config.globalProperties)

Scenario 2.

There will be no problems using proxy online

const { proxy } = getCurrentInstance()  

Why is Vue3 faster than Vue2?

  1. Proxy implements responsiveness
  2. patchFlag https://vue-next-template-explorer.netlify.app/
    1. When compiling templates, dynamic nodes are marked
    2. Markup, divided into different types, such as TEXT, PROPS
    3. When diffing, distinguish between static nodes and different types of dynamic nodes
  3. hoistStatic
    1. Promote the definition of static nodes to the parent scope, cache them, and exchange space for time
    2. Multiple adjacent static nodes will be merged and compiled for optimization
  4. cacheHandler
    cache event
  5. SSR optimization
    Static nodes are directly output as dom, bypassing vdom

  6. When compiling tree-shaking , import API on demand

How to understand Vue's one-way data flow?

All props form a单向下行 binding between their parent and child props:

Updates to parent props flow down to child components, but not the other way around. This prevents accidental changes to the parent component's state from child components, which can make your app's data flow difficult to understand.

In addition, every time the parent component is updated, all props in the child component will be refreshed with the latest values. This means you should not change props inside a child component.

If you do this, Vue will issue a warning in the browser's console. When the child component wants to modify, it can only send a custom event through $emit , and the parent component will modify it after receiving it.

There are two common situations when trying to mutate a prop:

This prop is used 传递一个初始值; this subcomponent comes next 希望将其作为一个本地的 prop 数据来使用.

In this case it is better to define a local data property and use this prop as its initial value:

props: ['initialCounter'],
data: function () {
  return {
    counter: this.initialCounter
  }
}

This prop takes a type 原始的值传入且需要进行转换.

In this case it is better to use the value of this prop to define a computed property

props: ['size'],
computed: {
  normalizedSize: function () {
    return this.size.trim().toLowerCase()
  }
}

The principle of event binding in Vue

$emit

vm.$emit('事件名称', 可选参数)

Trigger an event on the current instance, and the data to be passed will be passed to the listener;

$on

vm.$on('事件名称', callback) callback回调emit要传送的数据

Listen to custom events on the current instance;

$off

vm.$off( [event, callback] )

Remove custom event listeners.

  • If no arguments are provided, removes all event listeners;
  • If only an event is provided, remove all listeners for that event;
  • If both an event and a callback are provided, only the listener for this callback is removed.

vue2 usage example

//父组件
<template>
  <ratingselect @select-type="onSelectType"></ratingselect>
</template>
<script>
  data () {
   return {
    selectType: 0,
  },
  methods: {
   onSelectType (type) {
    this.selectType = type
   }
  }
</script>

The parent component uses @select-type="onSelectType" @ which is shorthand for v-on, listens to events triggered by the child component vm.$emit, accepts the data passed from the child component through onSelectType(), and notifies the parent component that the data has changed.

// 子组件
<template>
 <div>
  <span @click="select(0, $event)" :class="{'active': selectType===0}"></span>
  <span @click="select(1, $event)" :class="{'active': selectType===1}"></span>
  <span @click="select(2, $event)" :class="{'active': selectType===2}"></span>
 </div>
</template>
<script>
  data () {
   return {
    selectType: 0,
  },
  methods: {
    select (type, event) {
      this.selectType = type
      this.$emit('select-type', type)
   }
  }
</script>

Subcomponents trigger events through $emit and pass parameters out.

vue3 usage example – Vue3.x recommends using the external library mitt instead of $on $emit $off

The mitt source code is written in typescript. The source code plus comments are less than 90 lines in total, making it easier to read.

Typescript is not the focus of this time, so the mitt source code is displayed in the form of js as follows.

/**
 * 向外暴露的默认函数
 * @param 入参为 EventHandlerMap 对象 (ts真香,我们能清楚的知道参数的类型是什么,返回值是什么)
 * @returns 返回一个对象,对象包含属性 all,方法 on,off,emit
 */
export default function mitt (all) {
  /*
    此处实参可传一个EventHandlerMap对象,实现多个 mitt 的合并。例如:
    const m1 = mitt();
    m1.on('hi', () => { console.log('Hi, I am belongs to m1.'); });

    const m2 = mitt(m1.all);
    m2.emit('hi') // Hi, I am belongs to m1.
    m2.on('hello', () => { console.log('Hello, I am belongs to m2.'); });

    m1.emit('hello'); // Hello, I am belongs to m2.

    m1.all === m2.all // true
  */
  all = all || new Map();

  return {
    // 事件键值对映射对象
    all,

    /**
     * 注册一个命名的事件处理
     * @param type 事件名,官方表示事件名如是 *,用来标记为通用事件,调用任何事件,都会触发命名为 * 的事件
     * @param handler 事件处理函数
     */
    on (type, handler) {
      // 根据type去查找事件
      const handlers = all.get(type);
      // 如果找到有相同的事件,则继续添加,Array.prototype.push 返回值为添加后的新长度,
      const added = handlers && handlers.push(handler);
      // 如果已添加了type事件,则不再执行set操作
      if (!added) {
        all.set(type, [handler]); // 注意此处值是数组类型,可以添加多个相同的事件
      }
    },

    /**
     * 移除指定的事件处理
     * @param type 事件名,和第二个参数一起用来移除指定的事件,
     * @param handler 事件处理函数
     */
    off (type, handler) {
      // 根据type去查找事件
      const handlers = all.get(type);
      // 如果找到则进行删除操作
      if (handlers) {
        // 这里用了个骚操作,其实就是找到了,则删除(多个相同的只会删除找到的第一个),没找到则不会对原数组有任何影响
        handlers.splice(handlers.indexOf(handler) >>> 0, 1);
      }
    },

    /**
     * 触发所有 type 事件,如果有type为 * 的事件,则最后会执行。
     * @param type 事件名
     * @param evt 传递给处理函数的参数
     */
    emit (type, evt) {
      // 找到type的事件循环执行
      (all.get(type) || []).slice().map((handler) => { handler(evt); });
      // 然后找到所有为*的事件,循环执行
      (all.get('*') || []).slice().map((handler) => { handler(type, evt); });
    }
  };
}

vue3 mitt uses

mitt advantage

  • First of all it is small enough, only 200bytes.
  • Secondly, it supports monitoring and batch removal of all events.
  • It also does not depend on the Vue instance and can be used across frameworks, React or Vue, and even jQuery projects can use the same set of libraries.

API

// 创建mitt实例
mitt()

// 事件名称到注册处理程序函数的映射。
all

//触发事件,两个参数:name:触发的方法名,data:需要传递的参数
emit(name,data) 

// 绑定事件,两个参数:name:绑定的方法名,callback:触发后执行的回调函数
on(name,callback) 

// 解绑事件,一个参数:name:需要解绑的方法名
off(name)  

Install mitt:

npm install mitt -save

New EventBus.jsfile:

// 事件总线第三方库:
import mitt from 'mitt';
const bus = mitt();
export default bus;

case use

The page that sends the event: send.vue

<template>
    <div class="box">
        <h2>send页面视图</h2>
        <button @click="sendData">局部事件总线:点击之后给cc页面传递一个值</button>
    </div>
    
</template>
 
<script setup>
import bus from "../utils/EventBus" 
const sendData = () => {
  bus.emit("data",18)
}
</script> 

The page that receives the event: response.vue

<template>
    <div>
        <h2>response页面视图</h2>
    </div>
</template>
 
<script setup>
import bus from "../utils/EventBus"
import { ref ,onMounted} from "vue";
onMounted(()=>{
    bus.on("data",(info)=>{
      // info 就是emit传过来的数据
      console.log("dd页面接收到的值:",info)
    })
}) 
</script>

Remove listener event

Bus.off('Event');

Reference address:

  • https://tangjiusheng.com/web/4935.html
  • https://blog.csdn.net/weixin_41759744/article/details/125305021
  • https://www.jb51.net/article/263720.htm

Front-End Enthusiast

Guess you like

Origin blog.csdn.net/BradenHan/article/details/131058548