当前位置:网站首页>[day ui] alert component learning

[day ui] alert component learning

2022-06-24 12:21:00 Uncertainty

From the perspective of style function , The whole is not very complicated ,alert The components mainly include theme colors ,title, close button , Closing event , In the middle , Bold, etc

Source code

  • template<template> <!-- Show and hide have animation effect --> <!-- Not used in development , I don't quite understand why I use v-show Judgment display --> <transition name="d-alert-fade"> <div class="d-alert" :class="[typeClass, center ? 'is-center' : '', 'is-' + effect]" v-show="visible" role="alert" > <!-- Left Icon --> <i class="d-alert__icon" :class="[iconClass, isBigIcon]" v-if="showIcon" ></i> <!-- title and describe --> <div class="d-alert__content"> <span class="d-alert__title" :class="[isBoldTitle]" v-if="title || $slots.title" > <slot name="title">{{ title }}</slot> </span> <p v-if="$slots.default && !description" class="d-alert__description"> <slot></slot> </p> <p v-if="description && !$slots.default" class="d-alert__description"> {{ description }} </p> <i class="d-alert__closebtn" :class="{ 'is-customed': closeText !== '', 'd-icon-close': closeText === '' }" v-show="closable" @click="close" >{{ closeText }}</i > </div> </div> </transition> </template>

Use role Property tells the auxiliary device ( Such as screen reader ) The role of this element . In essence, it is to enhance semantics , When the existing HTML When tags cannot fully express semantics , With the help of role To illustrate .

I don't quite understand why title and description Attributes and slot Judge , There are clear friends who can help answer

  • props Properties are more general , I won't introduce it here setup(props, { emit, slots }) { // The accepted attribute is converted to a response const { description, type } = toRefs(props) // Use v-show Show hidden const visible = ref(true) // Closing event const close = () => { visible.value = false emit('close') } const typeClass = computed(() => { return `d-alert--${type.value}` }) const iconClass = computed(() => { return TYPE_CLASSES_MAP[type.value] || 'd-icon-info' }) const isBigIcon = computed(() => { return description.value || slots.default ? 'is-big' : '' }) const isBoldTitle = computed(() => { return description.value || slots.default ? 'is-bold' : '' }) return { close, visible, typeClass, iconClass, isBigIcon, isBoldTitle } }

This concludes the introduction to components , Relatively simple . To make up the words , Here is the introduction transition Components

transition

Most friends know that this is a built-in animation component for component animation . There are usually three ways to use :

  1. CSS transition
  2. CSS Animation
  3. Javascript hook

CSS transition

The method we usually use ,css To configure enter and leave

<template>
  <div class="app">
    <button @click="show = !show">
      Toggle render
    </button>
    <transition name="fade">
      <p v-if="show"> I'm testing </p>
    </transition>
  </div>
</template>
<script>
  export default {
    data() {
      return {
        show: true
      }
    }
  }
</script>
<style>
  .fade-enter-active,
  .fade-leave-active {
    transition: opacity 0.5s ease;
  }
  .fade-enter-from,
  .fade-leave-to {
    opacity: 0;
  }
</style>

CSS Animation

<template>
  <div class="app">
    <button @click="show = !show">Toggle show</button>
    <transition name="bounce">
      <p v-if="show"> I'm testing </p>
    </transition>
  </div>
</template>
<script>
  export default {
    data() {
      return {
        show: true
      }
    }
  }
</script>
<style>
  .bounce-enter-active {
    animation: bounce-in 0.5s;
  }
  .bounce-leave-active {
    // reverse  Is the key 
    animation: bounce-in 0.5s reverse;
  }
  @keyframes bounce-in {
    0% {
      transform: scale(0);
    }
    50% {
      transform: scale(1.5);
    }
    100% {
      transform: scale(1);
    }
  }
</style>

js hook

monitor transition Component's built-in methods ,js Control the animation

<template>
  <div class="app">
    <button @click="show = !show">
      Toggle render
    </button>
    <transition
      @before-enter="beforeEnter"
      @enter="enter"
      @before-leave="beforeLeave"
      @leave="leave"
      css="false"
    >
      <p v-if="show">hello</p>
    </transition>
  </div>
</template>
<script>
  export default {
    data() {
      return {
        show: true
      }
    },
    methods: {
      beforeEnter(el) {
        el.style.opacity = 0
        el.style.transition = 'opacity 0.5s ease'
      },
      enter(el) {
        this.$el.offsetHeight
        el.style.opacity = 1
      },
      beforeLeave(el) {
        el.style.opacity = 1
      },
      leave(el) {
        el.style.transition = 'opacity 0.5s ease'
        el.style.opacity = 0
      }
    }
  }
</script>

If the formal parameter does not specify done , It indicates that the user does not manually control the end of the animation , And then the node transition perhaps animationEnd To mark the end of the animation , Start callback afterEnter.

The number of formal parameters of hook function is greater than 1, Indicates that the formal parameter contains done, That is, the user must manually control when the animation ends . So once you configure done Shape parameter , Then you tell the frame , When does the animation end . Need to call... At the right time done, otherwise afterEnter The interface cannot be called .

Animation triggers

  • Conditions apply colours to a drawing (v-if)
  • Condition display (v-show)
  • Dynamic components
  • Component root

Execution principle

example

<template>
  <div class="app">
    <button @click="show = !show">
      Toggle render
    </button>
    <transition name="fade">
      <p v-if="show">hello</p>
    </transition>
  </div>
</template>

Compile generated render function ( Not a template component used )

import {
  createVNode as _createVNode,
  openBlock as _openBlock,
  createBlock as _createBlock,
  createCommentVNode as _createCommentVNode,
  Transition as _Transition,
  withCtx as _withCtx,
} from "vue";
export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (
    //  Collect dynamic nodes   Such as  v-if v-for
    _openBlock(),
    _createBlock("template", null, [
      _createVNode("div", { class: "app" }, [
        _createVNode(
          "button",
          {
            onClick: ($event) => (_ctx.show = !_ctx.show),
          },
          " Toggle render ",
          8 /* PROPS */,
          ["onClick"]
        ),
        _createVNode(
          _Transition,
          { name: "fade" },
          {
            // transition  There is only one child node , Default slot . Errors reported by multiple child nodes 
            default: _withCtx(() => [
              _ctx.show
                ? (_openBlock(), _createBlock("p", { key: 0 }, "hello"))
                : _createCommentVNode("v-if", true),
            ]),
            _: 1,
          }
        ),
      ]),
    ])
  );
}

So how to execute events when a build is created and destroyed ?———— Create hook function

transition The component returns the first child node processed

  • If Transition Nested inside the component is KeepAlive Components , Then it will continue to look for KeepAlive The first child element node of the nested component , As the element node of rendering .
  • If Transition No child nodes are nested inside the component , Then it renders an empty annotation node .

trantion Component definition

const Transition = (props, { slots }) =>
  //esolveTransitionProps  The main function is , Before we give  Transition  Delivered  Props  Make a layer of packaging on the basis of , And then back to a new  Props  object , Because it contains all  Props  Handle 
  h(BaseTransition, resolveTransitionProps(props), slots);
const BaseTransition = {
  name: `BaseTransition`,
  props: {
    mode: String,
    appear: Boolean,
    persisted: Boolean,
    // enter
    onBeforeEnter: TransitionHookValidator,
    onEnter: TransitionHookValidator,
    onAfterEnter: TransitionHookValidator,
    onEnterCancelled: TransitionHookValidator,
    // leave
    onBeforeLeave: TransitionHookValidator,
    onLeave: TransitionHookValidator,
    onAfterLeave: TransitionHookValidator,
    onLeaveCancelled: TransitionHookValidator,
    // appear
    onBeforeAppear: TransitionHookValidator,
    onAppear: TransitionHookValidator,
    onAfterAppear: TransitionHookValidator,
    onAppearCancelled: TransitionHookValidator,
  },
  setup(props, { slots }) {
    const instance = getCurrentInstance();
    const state = useTransitionState();
    let prevTransitionKey;
    return () => {
      const children =
        slots.default && getTransitionRawChildren(slots.default(), true);
      if (!children || !children.length) {
        return;
      }
      // Transition  Components only allow one child element node , Multiple warnings , Prompt use  TransitionGroup  Components 
      if (process.env.NODE_ENV !== "production" && children.length > 1) {
        warn(
          "<transition> can only be used on a single element or component. Use " +
            "<transition-group> for lists."
        );
      }
      //  There is no need to track the response , So change to the original value , Lifting performance 
      const rawProps = toRaw(props);
      const { mode } = rawProps;
      //  Check  mode  Is it legal 
      if (
        process.env.NODE_ENV !== "production" &&
        mode &&
        !["in-out", "out-in", "default"].includes(mode)
      ) {
        warn(`invalid <transition> mode: ${mode}`);
      }
      //  Get the first child element node 
      const child = children[0];
      if (state.isLeaving) {
        return emptyPlaceholder(child);
      }
      //  Handle  <transition><keep-alive/></transition>  The situation of 
      const innerChild = getKeepAliveChild(child);
      if (!innerChild) {
        return emptyPlaceholder(child);
      }
      const enterHooks = resolveTransitionHooks(
        innerChild,
        rawProps,
        state,
        instance
      );
      setTransitionHooks(innerChild, enterHooks);
      const oldChild = instance.subTree;
      const oldInnerChild = oldChild && getKeepAliveChild(oldChild);
      let transitionKeyChanged = false;
      const { getTransitionKey } = innerChild.type;
      if (getTransitionKey) {
        const key = getTransitionKey();
        if (prevTransitionKey === undefined) {
          prevTransitionKey = key;
        } else if (key !== prevTransitionKey) {
          prevTransitionKey = key;
          transitionKeyChanged = true;
        }
      }
      if (
        oldInnerChild &&
        oldInnerChild.type !== Comment &&
        (!isSameVNodeType(innerChild, oldInnerChild) || transitionKeyChanged)
      ) {
        const leavingHooks = resolveTransitionHooks(
          oldInnerChild,
          rawProps,
          state,
          instance
        );
        //  Update the hook function of the old tree 
        setTransitionHooks(oldInnerChild, leavingHooks);
        //  Switch between two views 
        if (mode === "out-in") {
          state.isLeaving = true;
          //  Returns an empty placeholder node , When the transition is over , Rerender component 
          leavingHooks.afterLeave = () => {
            state.isLeaving = false;
            instance.update();
          };
          return emptyPlaceholder(child);
        } else if (mode === "in-out") {
          leavingHooks.delayLeave = (el, earlyRemove, delayedLeave) => {
            const leavingVNodesCache = getLeavingNodesForType(
              state,
              oldInnerChild
            );
            leavingVNodesCache[String(oldInnerChild.key)] = oldInnerChild;
            // early removal callback
            el._leaveCb = () => {
              earlyRemove();
              el._leaveCb = undefined;
              delete enterHooks.delayedLeave;
            };
            enterHooks.delayedLeave = delayedLeave;
          };
        }
      }
      return child;
    };
  },
};

In the process of rendering ,Transition Components will also pass through resolveTransitionHooks To define the hook function object in the component creation and deletion stage , And then through setTransitionHooks Function to set the hook function object to vnode.transition On .

hooks Definition

const hooks = {
    mode,
    persisted,
    beforeEnter(el) {
      let hook = onBeforeEnter;
      if (!state.isMounted) {
        if (appear) {
          hook = onBeforeAppear || onBeforeEnter;
        } else {
          return;
        }
      }
      if (el._leaveCb) {
        el._leaveCb(true /* cancelled */);
      }
      const leavingVNode = leavingVNodesCache[key];
      if (
        leavingVNode &&
        isSameVNodeType(vnode, leavingVNode) &&
        leavingVNode.el._leaveCb
      ) {
        leavingVNode.el._leaveCb();
      }
      callHook(hook, [el]);
    },
    enter(el) {
      let hook = onEnter;
      let afterHook = onAfterEnter;
      let cancelHook = onEnterCancelled;
      if (!state.isMounted) {
        if (appear) {
          hook = onAppear || onEnter;
          afterHook = onAfterAppear || onAfterEnter;
          cancelHook = onAppearCancelled || onEnterCancelled;
        } else {
          return;
        }
      }
      let called = false;
      const done = (el._enterCb = (cancelled) => {
        if (called) return;
        called = true;
        if (cancelled) {
          callHook(cancelHook, [el]);
        } else {
          callHook(afterHook, [el]);
        }
        if (hooks.delayedLeave) {
          hooks.delayedLeave();
        }
        el._enterCb = undefined;
      });
      if (hook) {
        hook(el, done);
        if (hook.length <= 1) {
          done();
        }
      } else {
        done();
      }
    },
    leave(el, remove) {
      const key = String(vnode.key);
      if (el._enterCb) {
        el._enterCb(true /* cancelled */);
      }
      if (state.isUnmounting) {
        return remove();
      }
      callHook(onBeforeLeave, [el]);
      let called = false;
      const done = (el._leaveCb = (cancelled) => {
        if (called) return;
        called = true;
        remove();
        if (cancelled) {
          callHook(onLeaveCancelled, [el]);
        } else {
          callHook(onAfterLeave, [el]);
        }
        el._leaveCb = undefined;
        if (leavingVNodesCache[key] === vnode) {
          delete leavingVNodesCache[key];
        }
      });
      leavingVNodesCache[key] = vnode;
      if (onLeave) {
        onLeave(el, done);
        if (onLeave.length <= 1) {
          done();
        }
      } else {
        done();
      }
    },
    clone(vnode) {
      return resolveTransitionHooks(vnode, props, state, instance);
    },
  };

The hook function object defines 4 A hook function , Namely beforeEnter,enter,leave and clone. At the node patch Stage mountElement Function , Before the node is inserted and there is an excess, it will execute vnode.transition Medium beforeEnter function

//beforeEnter  The main thing hook functions do is based on  appear  The value of and  DOM  Whether to mount , To execute  onBeforeEnter  Function or  onBeforeAppear  function .appear  Whether to execute animation when the node is realistic 
beforeEnter(el) {
  let hook = onBeforeEnter
  if (!state.isMounted) {
    if (appear) {
      hook = onBeforeAppear || onBeforeEnter
    }
    else {
      return
    }
  }
  if (el._leaveCb) {
    el._leaveCb(true /* cancelled */)
  }
  const leavingVNode = leavingVNodesCache[key]
  if (leavingVNode &&
    isSameVNodeType(vnode, leavingVNode) &&
    leavingVNode.el._leaveCb) {
    leavingVNode.el._leaveCb()
  }
  callHook(hook, [el])
}

resolveTransitionProps function

function resolveTransitionProps(rawProps) {
  let {
    name = "v",
    type,
    css = true,
    duration,
    enterFromClass = `${name}-enter-from`,
    enterActiveClass = `${name}-enter-active`,
    enterToClass = `${name}-enter-to`,
    appearFromClass = enterFromClass,
    appearActiveClass = enterActiveClass,
    appearToClass = enterToClass,
    leaveFromClass = `${name}-leave-from`,
    leaveActiveClass = `${name}-leave-active`,
    leaveToClass = `${name}-leave-to`,
  } = rawProps;
  const baseProps = {};
  for (const key in rawProps) {
    if (!(key in DOMTransitionPropsValidators)) {
      baseProps[key] = rawProps[key];
    }
  }
  if (!css) {
    return baseProps;
  }
  const durations = normalizeDuration(duration);
  const enterDuration = durations && durations[0];
  const leaveDuration = durations && durations[1];
  const {
    onBeforeEnter,
    onEnter,
    onEnterCancelled,
    onLeave,
    onLeaveCancelled,
    onBeforeAppear = onBeforeEnter,
    onAppear = onEnter,
    onAppearCancelled = onEnterCancelled,
  } = baseProps;
  const finishEnter = (el, isAppear, done) => {
    removeTransitionClass(el, isAppear ? appearToClass : enterToClass);
    removeTransitionClass(el, isAppear ? appearActiveClass : enterActiveClass);
    done && done();
  };
  const finishLeave = (el, done) => {
    removeTransitionClass(el, leaveToClass);
    removeTransitionClass(el, leaveActiveClass);
    done && done();
  };
  const makeEnterHook = (isAppear) => {
    return (el, done) => {
      const hook = isAppear ? onAppear : onEnter;
      const resolve = () => finishEnter(el, isAppear, done);
      hook && hook(el, resolve);
      nextFrame(() => {
        removeTransitionClass(el, isAppear ? appearFromClass : enterFromClass);
        addTransitionClass(el, isAppear ? appearToClass : enterToClass);
        if (!(hook && hook.length > 1)) {
          if (enterDuration) {
            setTimeout(resolve, enterDuration);
          } else {
            whenTransitionEnds(el, type, resolve);
          }
        }
      });
    };
  };
  return extend(baseProps, {
    onBeforeEnter(el) {
      onBeforeEnter && onBeforeEnter(el);
      addTransitionClass(el, enterActiveClass);
      addTransitionClass(el, enterFromClass);
    },
    onBeforeAppear(el) {
      onBeforeAppear && onBeforeAppear(el);
      addTransitionClass(el, appearActiveClass);
      addTransitionClass(el, appearFromClass);
    },
    onEnter: makeEnterHook(false),
    onAppear: makeEnterHook(true),
    onLeave(el, done) {
      const resolve = () => finishLeave(el, done);
      addTransitionClass(el, leaveActiveClass);
      addTransitionClass(el, leaveFromClass);
      nextFrame(() => {
        removeTransitionClass(el, leaveFromClass);
        addTransitionClass(el, leaveToClass);
        if (!(onLeave && onLeave.length > 1)) {
          if (leaveDuration) {
            setTimeout(resolve, leaveDuration);
          } else {
            whenTransitionEnds(el, type, resolve);
          }
        }
      });
      onLeave && onLeave(el, resolve);
    },
    onEnterCancelled(el) {
      finishEnter(el, false);
      onEnterCancelled && onEnterCancelled(el);
    },
    onAppearCancelled(el) {
      finishEnter(el, true);
      onAppearCancelled && onAppearCancelled(el);
    },
    onLeaveCancelled(el) {
      finishLeave(el);
      onLeaveCancelled && onLeaveCancelled(el);
    },
  });
}

Let's see onBeforeEnter function , Its internal implementation of the foundation props Incoming onBeforeEnter Hook function , And give DOM Elements el Added enterActiveClass and enterFromClass style .

among ,props Incoming onBeforeEnter The function is that we write Transition Component is added beforeEnter Hook function .enterActiveClass The default value is v-enter-active,enterFromClass The default value is v-enter-from, If Transition Component passed in name Of prop, such as fade, that enterActiveClass The value is fade-enter-active,enterFromClass The value is fade-enter-from.(onBeforeAppear and onBeforeEnter The logic of is similar to , I won't go into that , It is before we give Transition Component in appear Of Prop, And is executed during the first mount . After execution beforeEnter Hook function , Then insert the element into the page , And then it will execute vnode.transition Medium enter Hook function , above hooks in )

stay enter Internal function , First, execute the basic props Incoming onEnter Hook function , Then give... At the next frame DOM Elements el Removed enterFromClass, At the same time, added enterToClass style ( Animation is the so-called alternation of styles )

Transition Component allows us to pass in enterDuration This prop, It specifies the animation duration for entering the transition , Of course, if you don't specify ,Vue.js The internal will monitor the animation end event , Then at the end of the animation , perform finishEnter function

Look at its implementation

const finishEnter = (el, isAppear, done) => {
  removeTransitionClass(el, isAppear ? appearToClass : enterToClass);
  removeTransitionClass(el, isAppear ? appearActiveClass : enterActiveClass);
  done && done();
};

In fact, it's for DOM Element removal enterToClass as well as enterActiveClass, At the same time done function , And then perform onAfterEnter Hook function

leave The main functions of the hook are enter contrary . You can check it by yourself .

That's right alert Component learning , If there is any mistake, please correct it .

原网站

版权声明
本文为[Uncertainty]所创,转载请带上原文链接,感谢
https://yzsam.com/2021/06/20210602203912779J.html