Vue Revisited II 2025: Difference between revisions

From bibbleWiki
Jump to navigation Jump to search
Line 99: Line 99:
     </div>
     </div>
   </div>
   </div>
</template>
</syntaxhighlight>
So for refs this is referring to when you assign a ref to template element.
<syntaxhighlight lang="vue">
<template>
    <div ref="parentRef" class="w-[35%] flex flex-col text-secondary gap-2">
      <div
        v-for="(menuItem, index) in menuItems"
        :key="index"
        :ref="(el) => setMenuItemRef(el as HTMLDivElement, index)"
        :class="[
          'w-full',
          'flex',
          'px-8',
          'py-4',
          index === selectedMenuIndex ? 'bg-[#2F2F2F]' : '',
        ]"
        @click="handleMenuSelected(index)"
      >
        <Menu :menuItem="menuItem" :isActive="index === selectedMenuIndex" />
      </div>
    </div>
</template>
</syntaxhighlight>
And in the script we have
<syntaxhighlight lang="vue">
<script setup lang="ts">
import { useScreenSizeDetector } from '@/composables/use-screen-size-detector'
import type { GeneralLinkItem } from '@/types/general-link-item'
import type { ISubMenus } from '@/types/menu-item'
import { ref, computed, watch } from 'vue'
import GeneralSmallMenu from '@/components/GeneralSmallMenu.vue'
import Menu from '@/components/TheMenu.vue'
import SubMenu from '@/components/SubMenu.vue'
defineOptions({
  name: 'GeneralMenu',
})
<script setup lang="ts">
const props = defineProps<{
  menuItems: ISubMenus[]
  generalLinkItems: GeneralLinkItem[]
}>()
// Create refs to hold the DOM elements
const parentRef = ref<HTMLDivElement | null>(null)
const menuItemsRefs = ref<HTMLDivElement[]>([])
const selectedMenuIndex = ref(-1)
const activeMenuY = ref(0)
// Function to set refs for menu items
const setMenuItemRef = (el: HTMLDivElement | null, index: number) => {
  if (el) {
    menuItemsRefs.value[index] = el
  }
}
// Watch for changes to get the active menu ref
watch(selectedMenuIndex, (newIndex) => {
  const activeMenuRef = newIndex >= 0 ? menuItemsRefs.value[newIndex] : null
  // Your menu position logic here
  if (parentRef.value && activeMenuRef) {
    const parentRect = parentRef.value.getBoundingClientRect()
    const childRect = activeMenuRef.getBoundingClientRect()
    const relativeY = childRect.bottom - parentRect.top
    activeMenuY.value = relativeY
    // Scroll into view if needed
    activeMenuRef.scrollIntoView({
      behavior: 'smooth',
      block: 'nearest',
    })
  }
})
</template>
</template>
</syntaxhighlight>
</syntaxhighlight>

Revision as of 04:08, 22 June 2025

Introduction

The changes to Vue are so big I needed to give these changes their own page. First what I will be talking about.

  • Composition API
  • Data
  • Methods
  • LifeCycle hooks
  • Directives
  • Vue Router
  • Lists, Teleport, Template Refs, next Tick
  • Child Components
  • Composables
  • State with Pinia
  • Bulma

Composition API

So I had forgotten how awful the options API is and since doing my stuff in composition API
Here is the old approach

Here is the new approach

The composables allows better code sharing than the mixins approach. This was done so well I just used it and it worked.

Data

Was much here aside from the reactive method for store non primative refs

<scripts>
const counterData = reactive({
    counter:0,
    title: 'My Counter'
})
</scripts>
Now you can use v-model to bind to it
<template>
<div>
  <h4>Edit Counter Title:</h4>
  <input v-model="counterData.title" type="text">
</div>
</template>

Methods

LifeCycle hooks

Directives

So a directive is like v-show, v-if etc. And of course you can make you own.
Old way

<scripts>
{
  {
...
   directives: {
     autofocus: {
        mounted(el) {
          el.focus()
        }
     } 
   }
 }
}
</scripts>
<template>
  <div>
    <input v-model="counterData.title" type="text" v-autofocus>
  </div>
</template>

In the new approach you need to create a directive in CamelCase

<scripts>
  const vAutofocus = {
    mounted(el) {
     el.focus()
    }
  }
</scripts>

It did seem to be a bit silly to even mention this approach but I guess people like continuity. The right apporach is to make a directives directory and export it.

export const vAutofocus = {
    mounted(el) {
     el.focus()
    }
  }
</scripts>

Vue Router

Lists, Teleport, Template Refs, next Tick

Not sure why lists were on the list. There is not change really

<template>
  <div
    v-for="(menuItem, index) in menuItems"
    :key="index"
    class="pl-4 flex flex-row gap-2 items-center justify-start"
  >
    <div class="flex font-bold hover:text-headerHover underline">
      {{ menuItem.title }}
    </div>
  </div>
</template>

So for refs this is referring to when you assign a ref to template element.

<template>
    <div ref="parentRef" class="w-[35%] flex flex-col text-secondary gap-2">
      <div
        v-for="(menuItem, index) in menuItems"
        :key="index"
        :ref="(el) => setMenuItemRef(el as HTMLDivElement, index)"
        :class="[
          'w-full',
          'flex',
          'px-8',
          'py-4',
          index === selectedMenuIndex ? 'bg-[#2F2F2F]' : '',
        ]"
        @click="handleMenuSelected(index)"
      >
        <Menu :menuItem="menuItem" :isActive="index === selectedMenuIndex" />
      </div>
    </div>
</template>

And in the script we have

<script setup lang="ts">
import { useScreenSizeDetector } from '@/composables/use-screen-size-detector'
import type { GeneralLinkItem } from '@/types/general-link-item'
import type { ISubMenus } from '@/types/menu-item'
import { ref, computed, watch } from 'vue'

import GeneralSmallMenu from '@/components/GeneralSmallMenu.vue'
import Menu from '@/components/TheMenu.vue'
import SubMenu from '@/components/SubMenu.vue'

defineOptions({
  name: 'GeneralMenu',
})

<script setup lang="ts">

const props = defineProps<{
  menuItems: ISubMenus[]
  generalLinkItems: GeneralLinkItem[]
}>()

// Create refs to hold the DOM elements
const parentRef = ref<HTMLDivElement | null>(null)
const menuItemsRefs = ref<HTMLDivElement[]>([])
const selectedMenuIndex = ref(-1)
const activeMenuY = ref(0)

// Function to set refs for menu items
const setMenuItemRef = (el: HTMLDivElement | null, index: number) => {
  if (el) {
    menuItemsRefs.value[index] = el
  }
}

// Watch for changes to get the active menu ref
watch(selectedMenuIndex, (newIndex) => {
  const activeMenuRef = newIndex >= 0 ? menuItemsRefs.value[newIndex] : null

  // Your menu position logic here
  if (parentRef.value && activeMenuRef) {
    const parentRect = parentRef.value.getBoundingClientRect()
    const childRect = activeMenuRef.getBoundingClientRect()

    const relativeY = childRect.bottom - parentRect.top
    activeMenuY.value = relativeY

    // Scroll into view if needed
    activeMenuRef.scrollIntoView({
      behavior: 'smooth',
      block: 'nearest',
    })
  }
})
</template>

Child Components

Composables

State with Pinia

Bulma