Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

alialnaghmoush's avatar

Help Convert JavaScript to VueJS syntax

Hi, creatives how to convert it from JavaScript to Vue? https://codepen.io/knyttneve/details/LKrGBy

0 likes
4 replies
rodrigo.pedra's avatar

Component:

<template>
    <nav class="nav">
        <a
            v-for="link in links"
            :key="link.id"
            class="nav-item"
            :class="{'is-active': link.id === value}"
            :style="link.id === value ? {color: link.color} : null"
            href
            @click.prevent="$emit('input', link.id)"
            v-text="link.label" />
        <span class="nav-indicator" :style="indicatorStyle" />
    </nav>
</template>

<script>
export default {
    name: 'FancyNavbar',

    props: {
        value: {type: String, default: null},
        links: {type: Array, required: true},
    },

    data() {
        return {
            indicatorStyle: {
                width: 0,
                left: 0,
                backgroundColor: 'transparent',
            },
        };
    },

    watch: {
        value: {
            immediate: true,
            handler(value) {
                const link = this.links.find(({id}) => id === value);

                if (link) {
                    this.$nextTick(() => this.updateIndicator(link));
                }
            },
        },
    },

    mounted() {
        if (!this.value && this.links.length > 0) {
            this.$emit('input', this.links[0].id);
        }
    },

    methods: {
        updateIndicator(link) {
            const activeElement = this.$el.querySelector('.is-active');

            if (!activeElement) {
                return;
            }

            this.indicatorStyle = {
                width: `${activeElement.offsetWidth}px`,
                left: `${activeElement.offsetLeft}px`,
                backgroundColor: link.color,
            };
        },
    },
};
</script>

<style scoped>
.nav {
    display: inline-flex;
    position: relative;
    overflow: hidden;
    max-width: 100%;
    background-color: #fff;
    padding: 0 20px;
    border-radius: 40px;
    box-shadow: 0 10px 40px rgba(159, 162, 177, .8);
}

.nav-item {
    color: #83818c;
    padding: 20px;
    text-decoration: none;
    transition: .3s;
    margin: 0 6px;
    z-index: 1;
    font-family: 'DM Sans', sans-serif;
    font-weight: 500;
    position: relative;
}

.nav-item:before {
    content: "";
    position: absolute;
    bottom: -6px;
    left: 0;
    width: 100%;
    height: 5px;
    background-color: #dfe2ea;
    border-radius: 8px 8px 0 0;
    opacity: 0;
    transition: .3s;
}

.nav-item:not(.is-active):hover:before {
    opacity: 1;
    bottom: 0;
}

.nav-item:not(.is-active):hover {
    color: #333;
}

.nav-indicator {
    position: absolute;
    left: 0;
    bottom: 0;
    transition: .4s;
    height: 5px;
    z-index: 1;
    border-radius: 8px 8px 0 0;
}

@media (max-width: 580px) {
    .nav {
        overflow: auto;
    }
}
</style>

Usage in another component:

<template>
    <FancyNavbar v-model="activeLink" :links="links" />
</template>

<script>
import FancyNavbar from './FancyNavbar.vue';

export default {
    name: 'ParentComponent',

    components: {FancyNavbar},

    data() {
        return {
            activeLink: 'home',
            links: [
                {id: 'home', label: 'Home', color: 'orange'},
                {id: 'about', label: 'About', color: 'green'},
                {id: 'testimonials', label: 'Testimonials', color: 'blue'},
                {id: 'blog', label: 'Blog', color: 'red'},
                {id: 'contact', label: 'Contact', color: 'rebeccapurple'},
            ],
        };
    },

    watch: {
        activeLink(newLink, oldLink) {
            if (newLink !== oldLink) {
                const link = this.links.find(({id}) => id === newLink);

                console.log('navigate to: ' + link.label);
            }
        },
    },
};
</script>

Thanks for the codepen link. I was about to do a very similar one to a project.

EDIT: forgot to set the active link text color when I first posted. Fixed now.

1 like
rodrigo.pedra's avatar

@bvidlj

one tip: asking for help on a year old thread won't help you find somebody willing to help you =)

From the fiddle you linked above it seems it is a code straight from Google, so it seems you didn't even try to do anything, if I am mistaken, please apologize.

As it is a sample code, it is not clear what you actually want to warp as a Vue component.

And also the code is in TypeScript which I don't use.

On Vue 2 docs there is an example on how to wrap an external library as a Vue component, it might give you a guidance.

https://v2.vuejs.org/v2/examples/select2.html

There used to have a example there on wrapping a Google Maps API, but it seems to be removed, if you search in the documentation github repository you might find it, but it is probably outdated.

Other thing, original OP asked help for a very simple component, with clear goals. In your case you want to wrap a code you don't own as a component it is not clear how you expect it to work.

For further help, from others, I strongly advise you to open a new thread.

Have a nice day =)

Please or to participate in this conversation.