Get 2024 Templates Mega Bundle!14 Bootstrap, Vue & React Templates + 3 Vector Sets
Get for 99$

Adding tns (tiny slider) to vue projects


HI team,

First of all ; thank you for the great work. Metronic is the best.
Without surprise, I need more component / librairies on Vue templates, as Tiny sliders for example.

scss is here, but no js or ts.

Can you help me adding it ?
Best regards


Text formatting options
Submit
Here's a how to add some HTML formatting to your comment:
  • <pre></pre> for JS codes block
  • <pre lang="html"></pre> for HTML code block
  • <pre lang="scss"></pre> for SCSS code block
  • <pre lang="php"></pre> for PHP code block
  • <code></code> for single line of code
  • <strong></strong> to make things bold
  • <em></em> to emphasize
  • <ul><li></li></ul>  to make list
  • <ol><li></li></ol>  to make ordered list
  • <h3></h3> to make headings
  • <a></a> for links
  • <img> to paste in an image
  • <blockquote></blockquote> to quote somebody
  • happy  :)
  • shocked  :|
  • sad  :(

Replies (7)


Hi,

Sorry for the late reply.

To add tiny-slider to our Vue version you can follow instructions below:


  1. Install tiny-slider dependency by running command npm install tiny-slider.

  2. Include tiny-slider styles on your component.

    <style lang="scss">
    @import "tiny-slider/dist/tiny-slider.css";
    </style>

  3. Paste a slider's html code to your component.

    <div class="py-5">
    <div class="rounded border p-5 p-lg-15">
    <div class="tns tns-default" >
    <!--begin::Slider-->
    <div

    data-tns="true"
    data-tns-loop="true"
    data-tns-swipe-angle="false"
    data-tns-speed="2000"
    data-tns-autoplay="true"
    data-tns-autoplay-timeout="18000"
    data-tns-controls="true"
    data-tns-nav="false"
    data-tns-items="3"
    data-tns-center="false"
    data-tns-dots="false"
    data-tns-prev-button="#kt_team_slider_prev1"
    data-tns-next-button="#kt_team_slider_next1"
    >
    <!--begin::Item-->
    <div class="text-center px-5 py-5">
    <img
    :src="getAssetPath("/media/stock/600x400/img-1.jpg")"
    class="card-rounded mw-100"
    alt=""
    />
    </div>
    <!--end::Item-->

    <!--begin::Item-->
    <div class="text-center px-5 py-5">
    <img
    :src="getAssetPath("/media/stock/600x400/img-1.jpg")"
    class="card-rounded mw-100"
    alt=""
    />
    </div>
    <!--end::Item-->

    <!--begin::Item-->
    <div class="text-center px-5 py-5">
    <img
    :src="getAssetPath("/media/stock/600x400/img-1.jpg")"
    class="card-rounded mw-100"
    alt=""
    />
    </div>
    <!--end::Item-->

    <!--begin::Item-->
    <div class="text-center px-5 py-5">
    <img
    :src="getAssetPath("/media/stock/600x400/img-1.jpg")"
    class="card-rounded mw-100"
    alt=""
    />
    </div>
    <!--end::Item-->

    <!--begin::Item-->
    <div class="text-center px-5 py-5">
    <img
    :src="getAssetPath("/media/stock/600x400/img-1.jpg")"
    class="card-rounded mw-100"
    alt=""
    />
    </div>
    <!--end::Item-->

    <!--begin::Item-->
    <div class="text-center px-5 py-5">
    <img
    :src="getAssetPath("/media/stock/600x400/img-1.jpg")"
    class="card-rounded mw-100"
    alt=""
    />
    </div>
    <!--end::Item-->
    </div>
    <!--end::Slider-->

    <!--begin::Slider button-->
    <button
    class="btn btn-icon btn-active-color-primary"

    >
    <span class="svg-icon svg-icon-3x">
    <inline-svg
    :src="getAssetPath("media/icons/duotune/arrows/arr074.svg")"
    />
    </span>
    </button>
    <!--end::Slider button-->

    <!--begin::Slider button-->
    <button
    class="btn btn-icon btn-active-color-primary"

    >
    <span class="svg-icon svg-icon-3x">
    <inline-svg
    :src="getAssetPath("media/icons/duotune/arrows/arr071.svg")"
    />
    </span>
    </button>
    <!--end::Slider button-->
    </div>
    </div>
    </div>


  4. Then you can reuse the slider init function from our HTML version.

    var createTinySliders = function () {
    if (typeof tns === "undefined") {
    return;
    }

    // Init Slider
    var initSlider = function (el) {
    if (!el) {
    return;
    }

    const tnsOptions = {};

    // Convert string boolean
    const checkBool = function (val) {
    if (val === "true") {
    return true;
    }
    if (val === "false") {
    return false;
    }
    return val;
    };

    // get extra options via data attributes
    el.getAttributeNames().forEach(function (attrName) {
    // more options; https://github.com/ganlanyuan/tiny-slider#options
    if (/^data-tns-.*/g.test(attrName)) {
    let optionName = attrName
    .replace("data-tns-", "")
    .toLowerCase()
    .replace(/(?:[\s-])\w/g, function (match) {
    return match.replace("-", "").toUpperCase();
    });

    if (attrName === "data-tns-responsive") {
    // fix string with a valid json
    const jsonStr = el
    .getAttribute(attrName)
    .replace(/(\w+<img alt="happy" src="https://devs.keenthemes.com/assets/media/smiles/happy.png">|(\w+ <img alt="happy" src="https://devs.keenthemes.com/assets/media/smiles/happy.png">/g, function (matched) {
    return """ + matched.substring(0, matched.length - 1) + "":";
    });
    try {
    // convert json string to object
    tnsOptions[optionName] = JSON.parse(jsonStr);
    } catch (e) {}
    } else {
    tnsOptions[optionName] = checkBool(el.getAttribute(attrName));
    }
    }
    });

    const opt = Object.assign(
    {},
    {
    container: el,
    autoplay: true,
    autoplayButtonOutput: false,
    },
    tnsOptions
    );

    if (el.closest(".tns")) {
    el.closest(".tns").classList.add("tns-initiazlied");
    }

    return tns(opt);
    };

    // Sliders
    const elements = Array.prototype.slice.call(
    document.querySelectorAll("[data-tns="true"]"),
    0
    );

    if (!elements) {
    return;
    }

    elements.forEach(function (el) {
    if (el.getAttribute("data-kt-initialized") === "1") {
    return;
    }

    initSlider(el);

    el.setAttribute("data-kt-initialized", "1");
    });
    };

    onMounted(() => {
    createTinySliders();
    });




Regards,
Lauris Stepanovs,
Keenthemes Support Team

I'm sorry Lauris, but I can't make it work,
can you describe step 4 ?

"Then you can reuse the slider init function from our HTML version."

Where did I put this code ?

Best, Wilhem



Hi Wilhem,

You can put those functions inside your components setup function.


import {
...
onMounted
} from "vue";



...
setup(){
var createTinySliders = function () {
...
}

onMounted(() => {
createTinySliders();
});
}
...


Regards,
Lauris Stepanovs,
Keenthemes Support Team



Still not working, here the component based on html =


<template>
<!--begin::Team Section-->
<div class="py-10 py-lg-20">
<!--begin::Container-->
<div class="container">
<!--begin::Heading-->
<div class="text-center mb-12">
<!--begin::Title-->
<h3
class="fs-2hx text-dark mb-5"

data-kt-scroll-offset="{default: 100, lg: 150}">
Our Great Team

<!--end::Title-->
<!--begin::Sub-title-->
<div class="fs-5 text-muted fw-bold">
It&rsquo;s no doubt that when a development takes longer to complete,
additional costs to <br />integrate and test each extra feature creeps
up and haunts most of us.
</div>
<!--end::Sub-title=-->
</div>
<!--end::Heading-->
<!--begin::Slider-->
<div class="tns tns-default" ref="sliderRef">
<!--begin::Wrapper-->
<div
data-tns="true"
data-tns-loop="true"
data-tns-swipe-angle="false"
data-tns-speed="2000"
data-tns-autoplay="true"
data-tns-autoplay-timeout="18000"
data-tns-controls="true"
data-tns-nav="false"
data-tns-items="1"
data-tns-center="false"
data-tns-dots="false"
data-tns-prev-button="#kt_team_slider_prev"
data-tns-next-button="#kt_team_slider_next"
data-tns-responsive="{1200: {items: 3}, 992: {items: 2}}">
<!--begin::Item-->
<div class="text-center">
<!--begin::Photo-->
<div
class="octagon mx-auto mb-5 d-flex w-200px h-200px bgi-no-repeat bgi-size-contain bgi-position-center"
></div>
<!--end::Photo-->
<!--begin::Person-->
<div class="mb-0">
<!--begin::Name-->
<a href="#" class="text-dark fw-bold text-hover-primary fs-3"
>Paul Miles</a
>
<!--end::Name-->
<!--begin::Position-->
<div class="text-muted fs-6 fw-semibold mt-1">
Development Lead
</div>
<!--begin::Position-->
</div>
<!--end::Person-->
</div>
<!--end::Item-->
<!--begin::Item-->
<div class="text-center">
<!--begin::Photo-->
<div
class="octagon mx-auto mb-5 d-flex w-200px h-200px bgi-no-repeat bgi-size-contain bgi-position-center"
></div>
<!--end::Photo-->
<!--begin::Person-->
<div class="mb-0">
<!--begin::Name-->
<a href="#" class="text-dark fw-bold text-hover-primary fs-3"
>Melisa Marcus</a
>
<!--end::Name-->
<!--begin::Position-->
<div class="text-muted fs-6 fw-semibold mt-1">
Creative Director
</div>
<!--begin::Position-->
</div>
<!--end::Person-->
</div>
<!--end::Item-->
<!--begin::Item-->
<div class="text-center">
<!--begin::Photo-->
<div
class="octagon mx-auto mb-5 d-flex w-200px h-200px bgi-no-repeat bgi-size-contain bgi-position-center"
></div>
<!--end::Photo-->
<!--begin::Person-->
<div class="mb-0">
<!--begin::Name-->
<a href="#" class="text-dark fw-bold text-hover-primary fs-3"
>David Nilson</a
>
<!--end::Name-->
<!--begin::Position-->
<div class="text-muted fs-6 fw-semibold mt-1">Python Expert</div>
<!--begin::Position-->
</div>
<!--end::Person-->
</div>
<!--end::Item-->
<!--begin::Item-->
<div class="text-center">
<!--begin::Photo-->
<div
class="octagon mx-auto mb-5 d-flex w-200px h-200px bgi-no-repeat bgi-size-contain bgi-position-center"
></div>
<!--end::Photo-->
<!--begin::Person-->
<div class="mb-0">
<!--begin::Name-->
<a href="#" class="text-dark fw-bold text-hover-primary fs-3"
>Anne Clarc</a
>
<!--end::Name-->
<!--begin::Position-->
<div class="text-muted fs-6 fw-semibold mt-1">
Project Manager
</div>
<!--begin::Position-->
</div>
<!--end::Person-->
</div>
<!--end::Item-->
<!--begin::Item-->
<div class="text-center">
<!--begin::Photo-->
<div
class="octagon mx-auto mb-5 d-flex w-200px h-200px bgi-no-repeat bgi-size-contain bgi-position-center"
></div>
<!--end::Photo-->
<!--begin::Person-->
<div class="mb-0">
<!--begin::Name-->
<a href="#" class="text-dark fw-bold text-hover-primary fs-3"
>Ricky Hunt</a
>
<!--end::Name-->
<!--begin::Position-->
<div class="text-muted fs-6 fw-semibold mt-1">Art Director</div>
<!--begin::Position-->
</div>
<!--end::Person-->
</div>
<!--end::Item-->
<!--begin::Item-->
<div class="text-center">
<!--begin::Photo-->
<div
class="octagon mx-auto mb-5 d-flex w-200px h-200px bgi-no-repeat bgi-size-contain bgi-position-center"
></div>
<!--end::Photo-->
<!--begin::Person-->
<div class="mb-0">
<!--begin::Name-->
<a href="#" class="text-dark fw-bold text-hover-primary fs-3"
>Alice Wayde</a
>
<!--end::Name-->
<!--begin::Position-->
<div class="text-muted fs-6 fw-semibold mt-1">
Marketing Manager
</div>
<!--begin::Position-->
</div>
<!--end::Person-->
</div>
<!--end::Item-->
<!--begin::Item-->
<div class="text-center">
<!--begin::Photo-->
<div
class="octagon mx-auto mb-5 d-flex w-200px h-200px bgi-no-repeat bgi-size-contain bgi-position-center"
></div>
<!--end::Photo-->
<!--begin::Person-->
<div class="mb-0">
<!--begin::Name-->
<a href="#" class="text-dark fw-bold text-hover-primary fs-3"
>Carles Puyol</a
>
<!--end::Name-->
<!--begin::Position-->
<div class="text-muted fs-6 fw-semibold mt-1">QA Managers</div>
<!--begin::Position-->
</div>
<!--end::Person-->
</div>
<!--end::Item-->
</div>
<!--end::Wrapper-->
<!--begin::Button-->
<button
class="btn btn-icon btn-active-color-primary"
>
<!--begin::Svg Icon | path: icons/duotune/arrows/arr074.svg-->
<span class="svg-icon svg-icon-3x">
<inline-svg
:src="getAssetPath("/media/icons/duotune/arrows/arr074.svg")" />
</span>
<!--end::Svg Icon-->
</button>
<!--end::Button-->
<!--begin::Button-->
<button
class="btn btn-icon btn-active-color-primary"
>
<!--begin::Svg Icon | path: icons/duotune/arrows/arr071.svg-->
<span class="svg-icon svg-icon-3x">
<inline-svg
:src="getAssetPath("/media/icons/duotune/arrows/arr071.svg")" />
</span>
<!--end::Svg Icon-->
</button>
<!--end::Button-->
</div>
<!--end::Slider-->
</div>
<!--end::Container-->
</div>
<!--end::Team Section-->
</template>

<script lang="ts">
import { defineComponent, onMounted, ref} from "vue";
import { getAssetPath } from "@/core/helpers/assets";
import { tns } from "tiny-slider";

export default defineComponent({
name: "team",
components: {},
props: {
variable: {
type: [Object, String, Number, Boolean],
default: false,
},
//...
},
setup(props) {
// Expose it to the template, if required
const sliderRef = ref<HTMLElement | null>(null);
var createTinySliders = function () {
if (typeof tns === "undefined") {
return;
}
if (typeof sliderRef.value === "undefined") {
return;
}

// Init Slider
var initSlider = function (el) {
if (!el) {
return;
}

const tnsOptions = {};

// Convert string boolean
const checkBool = function (val) {
if (val === "true") {
return true;
}
if (val === "false") {
return false;
}
return val;
};

// get extra options via data attributes
el.getAttributeNames().forEach(function (attrName) {
// more options; https://github.com/ganlanyuan/tiny-slider#options
if ((/^data-tns-.*/g).test(attrName)) {
let optionName = attrName.replace("data-tns-", "").toLowerCase().replace(/(?:[\s-])\w/g, function (match) {
return match.replace("-", "").toUpperCase();
});

if (attrName === "data-tns-responsive") {
// fix string with a valid json
const jsonStr = el.getAttribute(attrName).replace(/(\w+<img alt="happy" src="https://devs.keenthemes.com/assets/media/smiles/happy.png">|(\w+ <img alt="happy" src="https://devs.keenthemes.com/assets/media/smiles/happy.png">/g, function (matched) {
return """ + matched.substring(0, matched.length - 1) + "":";
});
try {
// convert json string to object
tnsOptions[optionName] = JSON.parse(jsonStr);
}
catch (e) {
}
}
else {
tnsOptions[optionName] = checkBool(el.getAttribute(attrName));
}
}
});

const opt = Object.assign({}, {
container: el,
slideBy: "page",
autoplay: true,
autoplayButtonOutput: false,
}, tnsOptions);

if (el.closest(".tns")) {
sliderRef.value?.classList.add("tns-initialized");
}

return tns(opt);
}

// Sliders
const elements = Array.prototype.slice.call(document.querySelectorAll("[data-tns="true"]"), 0);

if (!elements && elements.length === 0) {
return;
}

elements.forEach(function (el) {
if (el.getAttribute("data-kt-initialized") === "1") {
return;
}

initSlider(el);

el.setAttribute("data-kt-initialized", "1");
});
}


onMounted(() => {
createTinySliders();
});


return { getAssetPath, sliderRef };
},
});
</script>

<style lang="scss">
@import "tiny-slider/dist/tiny-slider.css";
</style>



Hi,

The example above should work, here is the gist with a full component code.
https://gist.github.com/laurisstepanovs/dca0824c8cf2889ebb959762ed39a358

Could you please try it in your version?

Regards,
Lauris Stepanovs,
Keenthemes Support Team



Thanks a lot Lauris, it's working now.
You forgot : data-tns="true"

And I replaced tns-initiazlied to tns-initialized in scss source .
Best regards,
Wilhem



Hi,

Glad to hear that. All the best with your project!

Regards,
Lauris Stepanovs,
Keenthemes Support Team


Text formatting options
Submit
Here's a how to add some HTML formatting to your comment:
  • <pre></pre> for JS codes block
  • <pre lang="html"></pre> for HTML code block
  • <pre lang="scss"></pre> for SCSS code block
  • <pre lang="php"></pre> for PHP code block
  • <code></code> for single line of code
  • <strong></strong> to make things bold
  • <em></em> to emphasize
  • <ul><li></li></ul>  to make list
  • <ol><li></li></ol>  to make ordered list
  • <h3></h3> to make headings
  • <a></a> for links
  • <img> to paste in an image
  • <blockquote></blockquote> to quote somebody
  • happy  :)
  • shocked  :|
  • sad  :(
Text formatting options
Submit
Here's a how to add some HTML formatting to your comment:
  • <pre></pre> for JS codes block
  • <pre lang="html"></pre> for HTML code block
  • <pre lang="scss"></pre> for SCSS code block
  • <pre lang="php"></pre> for PHP code block
  • <code></code> for single line of code
  • <strong></strong> to make things bold
  • <em></em> to emphasize
  • <ul><li></li></ul>  to make list
  • <ol><li></li></ol>  to make ordered list
  • <h3></h3> to make headings
  • <a></a> for links
  • <img> to paste in an image
  • <blockquote></blockquote> to quote somebody
  • happy  :)
  • shocked  :|
  • sad  :(