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: [ ... ]});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.
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.
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;};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;};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;};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";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: { ... },});driver| Parámetro | Tipo | Descripción |
|---|---|---|
showProgress | boolean | Define si se mostrará el progreso del tour |
steps | DriverSteps[] | 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 driverstate (State): Define todos los posibles estados del popoverdriver (Driver): Indica cual es el driver que se renderizará en el DOMonNextClick? (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
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 tourDe esta forma, driver.js comenzará un tour dinámico por los distintos elementos de la página que contengan las clases dictadas.
Ejemplo driver
Para resaltar un elemento específico de la página, se tiene que definir con la siguiente estructura (por defecto se ejecuta al cargar la página, pero se puede asignar a, por ejemplo, un botón):
const driverObj = driver();driverObj.highlight({ element: '#some-element', popover: { title: 'Title for the Popover', description: 'Description for it', },}) // Highlight no requiere del metodo drive() porque se ejecuta automáticamenteDe esta forma, driver.js resaltará el elemento indicado al cargar la página.
Ejemplo highlight
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 yel 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 {}//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; } }}useDriverEn 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.
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).const elements = ["#driver-1", "#driver-2", "#driver-3", "#driver-4"];const contents = ["content-1","content-2","content-3","content-4"];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}}" }}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
DriverTour y TourStepContentPara 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; };};export type TourStepContent = { title: string description: string}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()}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
// Saca las traducciones de los localesconst { data: driverLocale } = await useLocales<DriverTour>('driver');// Contenido del driver de las páginas// El contenido viene por emitsconst currentContents = ref<string[]>([]);// Contenido del driver del aside// El contenido viene por emitsconst 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>Los locales deben seguir esta estructura.
{ "driver": { "button_driver": { // Traducciones de los botones // No se les puede cambiar la "key", siempre deben ser // "next", "previous" y "done" "next": "Siguiente", "previous": "Atrás", "done": "Hecho" }, "steps": { // Traducciones de cada uno de los pasos del tour // Se puede definir la "key" que se crea conveniente "account-profile": { "title": "Información de tu cuenta", "description": "Aquí puedes visualizar y cambiar la información de tu perfil" }, "aside-profile": { "title": "Perfil", "description": "Aquí puedes cambiar la información de tu perfil" }, "aside-shipping": { "title": "Envío", "description": "Aquí puedes cambiar tu información de envío" }, "aside-orders": { "title": "Pedidos", "description": "En esta categoría puedes gestionar tus pedidos" }, "aside-subscription": { "title": "Suscripciones", "description": "Gestiona tus suscripciones" }, "aside-payment-methods": { "title": "Métodos de pago", "description": "Cambia tus métodos de pago preferidos" }, "billing-info": { "title": "Informacion de facturación", "description": "Aqui puedes visualizar y cambiar tu información de facturación" }, "billing-shipping": { "title": "Información postal", "description": "Aquí puedes visualizar y cambiar tu información postal" }, }, // Traducción del texto que indica el paso actual y los totales // No se le puede cambiar la "key", siempre debe ser // "progressText" "progressText": "Paso {{current}} de {{total}}" }}Estos son los datos que se le van a pasar al driver por emits, como se puede apreciar, son arrays de strings que corresponden a los objetos, que se situan en driver.steps del driver.json de los locales
const currentContents = [ 'account-profile', // Buscará las traducciones de driver.steps.account-profile 'billing-info', 'billing-shipping', ] const currentAside = [ 'aside-profile', // Buscará las traducciones de driver.steps.aside-profile 'aside-shipping', 'aside-orders', 'aside-subscription', 'aside-payment-methods', ]