Skip to content

Driver.js

1. Descripción General


Librería de JavaScript / TypeScript liviana para recorridos de productos, aspectos destacados y ayuda contextual para guiar a los usuarios a través de la web.

2. Configuración


Driver.js está diseñado para ser altamente configurable. Puedes configurar el driver globalmente o paso a paso. También puedes configurarlo sobre la marcha, mientras se ejecuta.

2.1 Configuración driver

Puede configurar el driver globalmente pasando el objeto de configuración a la llamada del driver o usando el método setConfig(). A continuación, se muestran algunas de las opciones de configuración disponibles.

type Config = {
// Array de pasos para resaltar.
// Debes pasar esto cuando quieras configurar un tour del producto.
steps?: DriveStep[];
// Si animar el recorrido del producto. (default: true)
animate?: boolean;
// Color del overlay. (default: black)
// Esto es util cuando tienes un fondo oscuro
// y quieres resaltar elementos con un
// color de fondo claro.
overlayColor?: string;
// Si deseas realizar un desplazamiento suave hasta
// el elemento resaltado. (default: false)
smoothScroll?: boolean;
// Si se debe permitir cerrar el popover al hacer clic en el fondo. (default: true)
allowClose?: boolean;
// Opacidad del fondo. (default: 0.5)
overlayOpacity?: number;
// Qué hacer al hacer clic en el fondo superpuesto.
// Las opciones posibles son "close" y "nextStep". (default: 'close')
overlayClickBehavior?: string;
// Distancia entre el elemento resaltado y el recorte. (default: 10)
stagePadding?: number;
// Radio del recorte alrededor del elemento resaltado. (default: 5)
stageRadius?: number;
// Permitir la navegación con teclado. (default: true)
allowKeyboardControl?: boolean;
// Si se deshabilita la interacción con el elemento resaltado. (default: false)
// También se puede configurar paso a paso.
disableActiveInteraction?: boolean;
// Si quieres añadir clases personalizadas al popover
popoverClass?: string;
// Distancia entre el popover y el elemento destacado (default: 10)
popoverOffset?: number;
// Array de botones en el popover. (default: ["next", "previous", "close"])
showButtons?: AllowedButtons[];
// Array de botones deshabilitados.
// Esto es útil cuando desea mostrar algunos de los botones
// pero desea deshabilitar otros.
disableButtons?: AllowedButtons[];
// Si mostrar el texto de progreso en el popover. (default: false)
showProgress?: boolean;
// Template para el texto de progreso.
// Puede usar los siguientes marcadores de posición en el template:
// - {{current}}: Número de paso actual
// - {{total}}: Número total de pasos
progressText?: string;
// Texto a mostrar en los botones del popover.
// `doneBtnText` es usado en el último paso del tour.
nextBtnText?: string;
prevBtnText?: string;
doneBtnText?: string;
// Se llama después de renderizar el elemento emergente.
// PopoverDOM es un objeto con referencias
// a los elementos DOM del elemento emergente,
// como botones, título, descripciones, cuerpo, contenedor, etc.
onPopoverRender?: (
popover: PopoverDOM,
options: { config: Config; state: State; driver: Driver }
) => void;
// Hooks que se ejecutan antes y después de resaltar cada paso.
// Cada hook recibe los siguientes parámetros:
// - element: El elemento DOM de destino del paso
// - step: El objeto de paso configurado para el paso
// - options.config: Las opciones de configuración actuales
// - options.state: El estado actual del driver
// - options.driver: El objeto del driver actual
onHighlightStarted?: (
element?: Element,
step: DriveStep,
options: { config: Config; state: State; driver: Driver }
) => void;
onHighlighted?: (
element?: Element,
step: DriveStep,
options: { config: Config; state: State; driver: Driver }
) => void;
onDeselected?: (
element?: Element,
step: DriveStep,
options: { config: Config; state: State; driver: Driver }
) => void;
// Hooks que se ejecutan antes y después de que el driver se destruya.
// Cada hook recibe los siguientes parámetros:
// - elemento: Elemento activo
// - paso: El objeto de paso configurado para el elemento activo
// - options.config: Las opciones de configuración actuales
// - options.state: El estado actual del driver
// - options.driver: Objeto del driver actual
onDestroyStarted?: (
element?: Element,
step: DriveStep,
options: { config: Config; state: State; driver: Driver }
) => void;
onDestroyed?: (
element?: Element,
step: DriveStep,
options: { config: Config; state: State; driver: Driver }
) => void;
// Hooks que se ejecutan al hacer clic en un botón.
// Cada hook recibe los siguientes parámetros:
// - element: El elemento DOM actual del paso
// - step: El objeto de paso configurado para el paso
// - options.config: Las opciones de configuración actuales
// - options.state: El estado actual del driver
// - options.driver: El objeto del driver actual
onNextClick?: (
element?: Element,
step: DriveStep,
options: { config: Config; state: State; driver: Driver }
) => void;
onPrevClick?: (
element?: Element,
step: DriveStep,
options: { config: Config; state: State; driver: Driver }
) => void;
onCloseClick?: (
element?: Element,
step: DriveStep,
options: { config: Config; state: State; driver: Driver }
) => void;
};
2.2 Configuración del popover

El popover es el elemento principal de la interfaz de usuario de Driver.js. Resalta el elemento de destino y muestra el contenido del paso. Puedes configurarlo globalmente o por pasos. A continuación, se muestran algunas de las opciones de configuración disponibles.

type Popover = {
// EL titulo y la descripción que se mostrarán en el popover
// Se puede usar HTML.
title?: string;
description?: string;
// La posición y alineamito del popover
// relativo al elemento a destacar
side?: "top" | "right" | "bottom" | "left";
align?: "start" | "center" | "end";
// Array de botones que se mostrarán en el popover.
// Al resaltar un solo elemento, no hay botones por defecto.
// Al mostrar un tour, los botones predeterminados son
// "next", "previous" y "close".
showButtons?: ("next" | "previous" | "close")[];
// Array de botones deshabilitados.
// Util si se quiere mostrar algún botón
// sin que sea usable
disableButtons?: ("next" | "previous" | "close")[];
// Texto que se mostrará en el respectivo botón.
// `doneBtnText` es usando en el último paso del tour.
// Útil para incluir traducciones en los botones
nextBtnText?: string;
prevBtnText?: string;
doneBtnText?: string;
// Si mostrar la barra de progreso en el popover.
showProgress?: boolean;
// Plantilla para el texto de progreso.
// Puede usar los siguientes placeholders en la plantilla:
// - {{current}}: Número de paso actual
// - {{total}}: Número total de pasos
// Si `showProgress` es true, el valor predeterminado es el siguiente:
// - "{{current}} of {{total}}"
progressText?: string;
// Clase personalizada para agregar al popover.
// Esto se puede usar para estilar al popover.
popoverClass?: string;
// Hooks que se ejecutan después de renderizar el popover.
// Puedes modificar el popover aquí.
// El parámetro es un objeto con referencias a los elementos DOM del popover,
// como sus botones, título, descripciones, cuerpo, etc.
onPopoverRender?: (
popover: PopoverDOM,
options: { config: Config; state: State; driver: Driver }
) => void;
// Callbacks para los clics de los botones.
// Puedes usarlos para personalizar el comportamiento de los botones.
// Cada callback recibe los siguientes parámetros:
// - element: El elemento DOM actual del paso
// - step: El objeto de paso configurado para el paso
// - options.config: Las opciones de configuración actuales
// - options.state: El estado actual del driver
// - options.driver: El objeto de driver actual
onNextClick?: (
element?: Element,
step: DriveStep,
options: { config: Config; state: State; driver: Driver }
) => void;
onPrevClick?: (
element?: Element,
step: DriveStep,
options: { config: Config; state: State; driver: Driver }
) => void;
onCloseClick?: (
element?: Element,
step: DriveStep,
options: { config: Config; state: State; driver: Driver }
) => void;
};
2.3 Configuracion del state

Puedes acceder al estado actual del driver llamando al método getState. Este estado también se transmite a los hooks y los callbacks.

type State = {
// Si el driver esta activo o no
isInitialized?: boolean;
// Índice del paso activo actual si se utiliza
// como recorrido del producto y se ha configurado el array de pasos.
activeIndex?: number;
// Elemento DOM del paso actualmente activo
activeElement?: Element;
// Objeto del paso actualmente activo
activeStep?: DriveStep;
// Elemento DOM previamente resaltado
previousElement?: Element;
// Objeto del paso previamente activo
previousStep?: DriveStep;
// Elementos DOM del popover p.e. including
// container, title, description, buttons, etc.
popover?: PopoverDOM;
};

3. Uso de la librería


3.1 Preparación

Para comenzar a usar la librería, tendremos que importar el método driver proporcionado por driver.js, así como su archivo de estilado con ruta driver.js/dist/driver.css.

import { driver } from "driver.js";
import "driver.js/dist/driver.css";

3.2 Funciones principales de resaltado

A continuación se listarán las funciones principales de driver.js

Función - driver

Define el objeto del driver y, si se le pasan parámetros, ofrece un tour guiado paso a paso con animaciones.

const driverObj = driver({
showProgress: true,
steps: [
...
]
});

Función - highlight

Permite resaltar un elemento concreto al cargar la página, para usarse, se debe dejar vacía la función driver().

const driverObj = driver();
driverObj.highlight({
element: ... ,
popover: {
...
},
});

3.3 Atributos de driver

ParámetroTipoDescripción
showProgressbooleanDefine si se mostrará el progreso del tour
stepsDriverSteps[]Array de elementos que conforman el tour

El parámetro steps es un array de objetos de tipo DriverSteps[]. Estos objetos vienen definidos de la siguiente forma:

  • element (string): Representa la clase (.ejemplo) o identificador (#ejemplo) del elemento que va a formar parte del tour

  • popover (Popover): Objeto que contiene los parámetros relacionados al popover de los elementos del tour, que a su vez se define de la siguiente forma:

    • title (string): Define el título del mensaje del popover

    • description (string): Define la descripción del mensaje del popover

    • side? (Step): Define en que posición aparecerá el popover, valores permitidos: (“top” | “right” | “bottom” | “left” | “over”)

    • align? (Alignment): Define que tipo de alineamiento tendrá el popover, valores permitidos: (“start” | “center” | “end”)

    • showButtons? (AllowedButtons[]): Dicta que botones aparecerán en el popover, valores permitidos: (“next” | “previous” | “close”)

    • disableButtons? (AllowedButtons[]): Dicta que bonotes estarán deshabilitados en el popover, valores permitidos: (“next” | “previous” | “close”)

    • popoverClass? (string): Define una clase exclusiva de dicho popover, mas adelante veremos como se utiliza

    • progressText? (string): Define el texto que aparecerá para indicar el progreso

    • doneBtnText? (string): Define el texto que aparecerá en el botón Done

    • nextBtnText? (string): Define el texto que aparecerá en el botón Next

    • prevBtnText? (string): Define el texto que aparecerá en el botón Prev

    • onPopoverRender? (popover: PopoverDOM, opts: Object): Dicta una serie de opciones y estados que el driver puede tener a la hora de renderizarse, opts se define de la siguiente forma:

      • config (Config): Contiene toda la configuración del driver
      • state (State): Define todos los posibles estados del popover
      • driver (Driver): Indica cual es el driver que se renderizará en el DOM
    • onNextClick? (DriverHook): Acción que se ejecutará después de clickar en el botón Next

    • onPrevClick? (DriverHook): Acción que se ejecutará después de clickar en el botón Prev

    • onCloseClick? (DriverHook): Acción que se ejecutará después de clickar en el botón Close

3.4 Ejemplo de uso básico

A continuación, aparecerán algunos ejemplos para poder comenzar a usar driver.js

Para realizar el tour guiado paso a paso y con animaciones, se tiene que definir con la siguiente estructura:

const driverObj = driver({
showProgress: true,
steps: [
{ element: ".page-header", popover: { title: "Title", description: "Description" } },
{ element: ".top-nav", popover: { title: "Title", description: "Description" } },
{ element: ".sidebar", popover: { title: "Title", description: "Description" } },
{ element: ".footer", popover: { title: "Title", description: "Description" } },
],
})
driverObj.drive() // Para iniciar el tour

De esta forma, driver.js comenzará un tour dinámico por los distintos elementos de la página que contengan las clases dictadas.

Ejemplo driver

4. Estilado


Para estilar el popover, debemos crear un archivo de estilos en @/assets/styles. Aquí definiremos todos los estilos relacionados al popover.

Previamente, deberemos de haberle otorgado al popover su clase personalizada con popoverClass como vimos anteriormente.

Aquí está la lista de clases aplicadas al popover, que puede usarse junto con la opción popoverClass para aplicar estilos personalizados.

/* Clase asignada al wrapper del popover */
.driver-popover {
}
/* Flecha que apunta al elemento resaltado */
.driver-popover-arrow {
}
/* Tìtulo y descripcion */
.driver-popover-title {
}
.driver-popover-description {
}
/* Botón de cerrado situado arriba a la derecha */
.driver-popover-close-btn {
}
/* Footer del popover que contiene los botones y
el texto de progreso */
.driver-popover-footer {
}
.driver-popover-progress-text {
}
.driver-popover-prev-btn {
}
.driver-popover-next-btn {
}

También se pueden añadir estilos para el overlay p.e. el lightbox que se muestra encima de la página

.driver-overlay {
}

También se le pueden aplicar estilos al elemento que está siendo resaltado

.driver-active-element {
}

4.1 Ejemplo de estilado

//En este ejemplo, .driver-example es la clase
// personalizada que se asignó con popoverClass
.driver-popover.driver-example {
background-color: var(--c-graphite);
border: 0.1em solid var(--c-white);
color: #000;
& .driver-popover {
&-title {
color: var(--c-primary);
font-family: var(--f-font-regular);
}
&-description {
color: var(--c-white);
font-family: var(--f-font-regular);
}
&-prev-btn {
background-color: var(--c-primary);
color: var(--c-black);
border: 0.125em solid transparent;
text-shadow: none;
padding: 0.6em;
font-family: var(--f-font-regular);
&:hover {
background-color: transparent;
text-shadow: none;
border: 0.125em solid var(--c-primary);
color: var(--c-white);
transition: all 0.3s ease-out;
}
}
&-next-btn {
background-color: var(--c-primary);
color: var(--c-black);
border: 0.125em solid transparent;
text-shadow: none;
font-family: var(--f-font-regular);
&:hover {
background-color: transparent;
text-shadow: none;
border: 0.125em solid var(--c-primary);
color: var(--c-white);
transition: all 0.3s ease-in-out;
}
}
&-progress-text {
color: var(--c-white);
font-family: var(--f-font-regular);
}
&-close-btn {
color: var(--c-white);
scale: 1.5;
margin-top: 0.6em;
}
}
}

5. Composable useDriver

En el proyecto hay un composable useDriver el cual permite usar driver.js de forma mas sencilla, que devuelve un objeto de driverObj que, a su vez, será el encargado de realizar el tour.

5.1 Parámetros

El composable tiene los siguientes parámetros:

  • elementDrivers ( string[] ): Lista de los elementos que serán recorridos por el driver, se le debe pasar un array de identificadores.
  • contents ( string[] ): Índices correspondientes a los contenidos que se van a mostrar en el driver.
  • driverLocale ( DriverTour ): Contenidos que se mostrarán en el driver traducidos.
  • ...onDestroyedCallback ( (() => void)[] ): Array de funciones que se ejecutarán cuando el drive activo se destruya (útil para encadenar tours).

5.2 Ejemplos de parámetros

elementDrivers
const elements = ["#driver-1", "#driver-2", "#driver-3", "#driver-4"];
contents
const contents = [
"content-1",
"content-2",
"content-3",
"content-4"
];
driverLocale
const { data: driverLocale } = await useLocales<DriverTour>("driver");

Y luego dentro de driver.json

{
//JSON español
"driver": {
"button_driver": {
// Traducciones para los botones
"next": "Siguiente",
"previous": "Atrás",
"done": "Hecho"
},
"steps": {
// Traducciones de los contenidos del driver
// Los objetos deben ser nombrados de la misma forma que se hizo
// en el parámetro contents
"content-1": {
"title": "Titulo contenido 1",
"description": "Descripcion contenido 1"
},
"content-2": {
"title": "Titulo contenido 2",
"description": "Descripcion contenido 2"
},
"content-3": {
"title": "Titulo contenido 3",
"description": "Descripcion contenido 3"
}
}, //Traduccion para el texto de los pasos
"progressText": "Paso {{current}} de {{total}}"
}
}
…onDestroyedCallback
const nextTour = () => {
const { driverObj } =
useDriver(
...
) ?? {}
driverObj?.drive()
}

Y a la hora de usarlo:

const { driverObj } =
useDriver(
...,
nextTour(),
) ?? {}

Tambien se puede definir la función directamente en el parámetro

5.3 Tipos DriverTour y TourStepContent

Para definir la estructura que tendrán las traducciones, hay un tipo llamado DriverTour y otro llamado TourStepContent, los cuales, están definidos de esta forma:

export type DriverTour = {
driver: {
button_driver: {
next: string;
previous: string;
done: string;
};
steps: { [key: string]: TourStepContent };
progressText: string;
};
};

Estructura del driver

  • button_driver: Contiene las traducciones de los botones Next, Previous y Done
  • steps: Define la estructura de las traducciones que tendran los pasos, su llave es un string y sus pasos son de tipo TourStepContent
  • progressText: Contiene la traducción del texto que indica el progreso del tour

5.4 Utilización

A la hora de usar el composable, hay que tener en cuenta que el driver se crea en base a los elementos actualmente cargados en el DOM, es decir, no es reactivo, por ello, hay que asegurarse de que, cada vez que se haga el llamado a la función .drive() para iniciar el tour, los elementos de los que se quiera hacerlo deben estar previamente cargados.

Esto podemos garantizarlo definiendo el objeto driverObj dentro de una función asíncrona, en la cual se espere a la próxima actualización del DOM, es decir, await nextTick()

const startTour = async () => {
await nextTick() // Espera a la próxima vez que se actualice el DOM
// para que de tiempo de cargar los elementos
const { driverObj } =
useDriver(
...
) ?? {}
driverObj?.drive()
}

5.5 Ejemplo completo de uso

A continuación veremos un ejemplo de uso, en este tenemos el supuesto caso de querer meter un tour que, segun la pestaña del aside en la que se encuentre el usuario se le muestre el contenido correspondiente del tour

@/components/example.vue
// Saca las traducciones de los locales
const { data: driverLocale } = await useLocales<DriverTour>('driver');
// Contenido del driver de las páginas
// El contenido viene por emits
const currentContents = ref<string[]>([]);
// Contenido del driver del aside
// El contenido viene por emits
const currentAside = ref<string[]>([]);
const startTour = async () => {
// Si el tour no se ha completado
if (localStorage.getItem("tour") !== "false") {
await nextTick();
// Si no le llega el contenido del aside,
// se pone por defecto el que haya activo
if (currentAside.value.length <= 0) {
currentAside.value = [localStorage.getItem('currentSection')]
}
const { driverObj } =
useDriver(
// Clase del aside que será resaltado y tendrá su tour
[".sidebar__buttons-section--active"],
// Contenido que viene de los emits
currentAside.value,
driverLocale,
// Función que se ejecuta cuando se termine el tour
// en este caso, concatena el tour de la página
() => {
const { driverObj: driverObj1 } =
useDriver(
// IDs de los elementos de la página de los
// que se hará el tour
[
"#driver__profile",
"#driver__billing",
"#driver__mailing",
],
// Contenido que viene de los emits
currentContents.value,
driverLocale,
() => {}
) ?? {};
// Ejecuta el tour de la página
driverObj1?.drive();
},
() => {
// Cuando termina el tour, se pone en false
localStorage.setItem("tour", "false");
}
) ?? {};
// Ejecuta el tour del aside
driverObj?.drive();
}
};
</ script>
<template>
...
</template>