/ Gists / Vue.js

Gists - Vue.js

On gists

Input validation composable

Vue.js

validation.js #

/*
vylepseny priklad o nazev pro v-model 
*/


import { ref, watch } from 'vue'

export function useFormValidation(initialValue, propName = 'value') {
  const value = ref(initialValue)
  const error = ref('')

  watch(value, (newValue) => {
    if (newValue.length < 3) {
      error.value = 'Value must be at least 3 characters'
    } else {
      error.value = ''
    }
  })

  function validate() {
    if (value.value.length < 3) {
      error.value = 'Value must be at least 3 characters'
    } else {
      error.value = ''
    }
  }

  return { [propName]: value, error, validate }
}

On gists

Sledování změn na $refs prvku

Popular ⭐ Vue.js

Foo.vue #

<template>
    <div ref="el" style="height: 70px" :style="computedStyles">
        <slot />
    </div>

    <hr />
    height {{ height }}
    <br />
    Computed {{ computedHeight }}
    <hr />

    <button @click="changeHeight(150)">150</button>
    <button @click="changeHeight(200)">200</button>
    <button @click="changeHeight(250)">250</button>
</template>

<script>
export default {
    data() {
        return {
            height: null,
            isMounted: false,
        };
    },
    computed: {
        computedStyles() {
            if (this.isMounted && this.height) return { height: this.computedHeight, background: 'limegreen' };
            return { background: 'pink' };
        },
        computedHeight() {
            if (this.isMounted && this.height) return this.height + 'px';

            return null;
        },
    },
    methods: {
        changeHeight(h) {
            //console.log('BEFORE', this.height);
            this.height = h;
            //console.log('AFTER', this.height);
        },

        observeElement() {
            const el = this.$refs.el;
            const observer = new MutationObserver(mutationsList => {
                for (const mutation of mutationsList) {
                    if (mutation.type === 'attributes' && mutation.attributeName === 'style') {
                        console.log('Element style changed:', el.style.height);
                    }
                }
            });

            observer.observe(el, { attributes: true });
        },
    },
    mounted() {
        this.isMounted = true;
        this.height = this.$refs.el.style.height;
        this.observeElement(); // Spustíme sledování změn výšky elementu
    },
};
</script>

On gists

Globální funkce / proměnná + instalace do Vue 3

Vue.js

AnyFile.js #

export const filter = {
  install: (vue) => {
    vue.config.globalProperties.$f = (name) => {
      console.log('CUSSS ' + name);
    };
  },
};

On gists

Access to instance

Vue.js

any-composable-hook.js #

import { getCurrentInstance } from 'vue'
const instance = getCurrentInstance()
const $t = instance.appContext.app.config.globalProperties.$t

const availableFromFormatter = n => {
  if (n > 30) return $t('více jak měsíc do naskladnění')
  if (n <= 3) return $t('méně jak 3 dny do naskladnění')
  if (n <= 7) return $t('méně jak 7 dnů do naskladnění')
  if (n <= 14) return $t('méně jak 14 dnů do naskladnění')
  if (n <= 30) return $t('méně jak měsíc do naskladnění')

  return $t('neznámá doba do naskladnění')
}

export { availableFromFormatter }

On gists

Expose Slots From a Child Component

Vue.js

ThirdPartyComponent.vue #

<template>
    <slot name="header" :header="header"> header {{ header }}</slot>
    <slot :default="default"> default {{  default }}</slot>
    <slot name="footer" :footer="footer"> footer {{ footer }}</slot>
</template>

<script>
export default {
    data() {
        return {
            header: 'Header value',
            default: 'Default value',
            footer: 'Footer value',
        };
    },
};
</script>

On gists

Watchefffect (Oldvalues & NewValues at the same time ;-))

Vue.js

watchEffect.js #

// onInvalidate

import { watchEffect, ref } from 'vue'

export default {
  setup() {
    const count = ref(0)

    watchEffect((onInvalidate) => {
      const oldValue = count.value // Store the current value as the old value
      onInvalidate(() => {
        const newValue = count.value // Get the new value when the effect is invalidated
        console.log(`Count changed from ${oldValue} to ${newValue}`)
      })
    })

    return { count }
  }
}

On gists

toRefs (props, reaktivita)

Vue.js

FooComponen.vue #

  const props = defineProps({
    category: String,
    data: Array,
  })
  
  // kvuli reaktivite, destructions neni reaktivni ...
  const { data, category } = toRefs(props)
  
  

On gists

Detect click outside or inside

Vue.js

foo.js #

window.addEventListener('mousedown', e => {
  // Get the element that was clicked
  const clickedEl = e.target;

  // `el` is the element you're detecting clicks outside of
  if (el.contains(clickedEl)) {
    // Clicked inside of `el`
  } else {
    // Clicked outside of `el`
  }
});

On gists

useElementSize - own composable

Vue.js

useElementSize.js #

import { ref, watch } from 'vue';

function useElementSize(element) {
  const width = ref(0);
  const height = ref(0);

  let observer = null;
   
  function disconnect() {
    if (observer !== null) {
      observer.disconnect();
      observer = null;
    }
  }

  function connect(element) {
    disconnect();
    observer = new ResizeObserver((entries) => {
      const rect = entries[0]?.contentRect;
      if (rect) {
        width.value = rect.width;
        height.value = rect.height;
      }
    });

    observer.observe(element);
  }

  watch(
    element,
    (el) => {
      if (el) connect(el);
      else disconnect();
    }
  )
  
  return {
    width,
    height,
  };
}

On gists

CloneContent

Vue.js

CloneContent.vue #

<template>
  <slot />
</template>

<script>
export default {
  props: {
    target: {
      type: String
    }
  },
  mounted() {
    let target = document.querySelector(this.target)
    if (target) {
      let cloneContent = this.$slots.default()[0].el.cloneNode(true)
      target.replaceChildren(cloneContent)
    }
  }
}
</script>

<style lang="scss" scoped></style>