¡Hola a los lectores del blog de Amasty! Hoy vamos a hablar sobre qué es JS Knockout , ejemplos de cómo usarlo en el comercio electrónico, por qué Magento 2 requiere la configuración de JS y las soluciones de frontend de Magento 2. Knockout (o KO) es una biblioteca de JavaScript que se usa ampliamente para crear la parte frontal de Magento 2, la página de pago en particular.
¡Oye! ¿Quiere aumentar la tasa de conversión de pago en su tienda Magento 2? Pruebe el módulo One Step Checkout . ¡Habilite Google Auto Suggest, agregue la opción de fecha de entrega, personalice el diseño de la página de pago y aumente sus ventas!
Knockout implementa el patrón de diseño Model-View-View Model (MVVM) con plantillas y permite crear páginas dinámicas, que cambian con respecto a las acciones de un usuario. La introducción de esta biblioteca trajo cambios positivos significativos al desarrollo de Magento 2 e hizo posible crear una gama mucho más amplia de componentes de interfaz receptivos, como el selector de fechas, las ventanas emergentes y otros elementos de diseño personalizados. A pesar de los beneficios, implementar las soluciones de Magento 2 con Knockout JS y la traducción de Magento 2 JS es bastante complicado para muchos desarrolladores.
Entonces, en este tutorial, veremos cómo funciona JS Knockout y cómo usarlo en sus proyectos de Magento 2. Pero KO es solo una de las bibliotecas JS que usa Magento 2, hay muchas otras, por ejemplo, jQuery, Underscore, etc.
Resumen del artículo [ ocultar ]
- Cómo funciona Knockout JS en Magento 2
- Cómo funciona Knockout JS en los componentes de la interfaz de usuario de Magento 2
- Lo bueno de Knockout es
- Knockout observables en acción
- Knockout para el intercambio de datos entre los componentes de la interfaz de usuario
- Knockout y uso de un componente de interfaz de usuario en un diseño de página
- Knockout y transferencia de datos del servidor al componente de la interfaz de usuario
- Línea de fondo
Cómo funciona Knockout JS en Magento 2
Agregado con varios cambios a Magento 2, KO ahora se usa ampliamente para enlaces de variables, utilizando el atributo de enlace de datos, agregando controladores de eventos de JavaScript con la ayuda de enlaces personalizados y rastreándolos. La documentación de Magento 2 muestra en detalle cómo funciona la biblioteca para estos fines. En general, el uso de Knockout JS en Magento 2 se refiere a la creación de componentes enriquecidos de una interfaz de página que, con KO en su lugar, contribuyen mucho a la comodidad de la interfaz de usuario.
Cómo funciona Knockout JS con los componentes de la interfaz de usuario de Magento 2
Los componentes de la interfaz de usuario de Magento 2 se utilizan para mostrar elementos particulares de la interfaz de usuario, como tablas, botones, pestañas, cuadros de diálogo y más. Los componentes de la interfaz de usuario constan de una declaración XML que especifica sus ajustes de configuración y estructura interna, una clase de JavaScript y plantillas relacionadas que utilizan los enlaces Knockout.
Para ser más específicos, un componente de la interfaz de usuario implementa una parte del patrón de diseño de MVVM o, en algunos casos, lo amplía. Un modelo aquí son los datos almacenados de su aplicación, la vista es un documento HTML relevante que describe cómo se representa el componente y un modelo de vista es una representación de código puro de los datos y las operaciones en una interfaz de usuario.
Los archivos frontend js se ubican convencionalmente de la siguiente manera:
app/code/<espacio_de_nombres_de_tu_módulo>/<nombre_de_tu_módulo>/view/<área>/web/js/
Y el área puede ser frontend, adminhtml o base.
Y los archivos frontend relacionados con las plantillas de archivos de JavaScript generalmente se encuentran a continuación:
app/code/<your_module_namespace>/<your_module_name>/view/frontend/web/template/
Para hacerlo más vívido, considere el componente de pago como ejemplo.
Primero, accedemos al modelo a través de module-checkout/view/frontend/web/js/model/quote.js y vemos la siguiente representación de código:
div.embedPastebin { text-align:left; padding: 0; color: #000; margin: 0; font-family: monospace; background: #F7F7F7; border: 1px solid ddd; border-radius:3px; } div.embedPastebin { } div.embedPastebin div.embedFooter { background: #F7F7F7; color: #333; font-size: 100%; padding: 6px 12px; border-bottom: 1px solid #ddd; text-transform:uppercase; } div.embedPastebin div.embedFooter a, div.embedPastebin div.embedFooter a:visited { color: #336699; text-decoration:none; } div.embedPastebin div.embedFooter a:hover { color: red; } .noLines ol { list-style-type: none; padding-left: 0.5em; } .embedPastebin{background-color:#F8F8F8;border:1px solid #ddd;font-size:12px;overflow:auto;margin: 0 0 0 0;padding:0 0 0 0;line-height:21px} .embedPastebin div { line-height:21px; font-family:Consolas, Menlo, Monaco, Lucida Console,’Bitstream Vera Sans Mono’,’Courier’,monospace; } ol { margin:0; padding: 0 0 0 55px} ol li { border:0; margin:0;padding:0; } li.ln-xtra .de1, li.ln-xtra .de2 {background:#F8F8CE;} .embedPastebin ol li.li1 { margin: 0; } .embedPastebin ol li.li2 { margin: 0; }
La ruta a la plantilla del componente se muestra en la sección predeterminada del componente y toma la forma de un objeto con la clave denominada plantilla . El modelo de vista contiene información sobre todas las funciones que se utilizarán en la parte de vista del componente. Además, el modelo de vista se usa para declarar variables observables .
En segundo lugar, la vista se encuentra en module-checkout/view/frontend/web/template/review/actions/default.html y tiene el siguiente aspecto:
La plantilla del componente contiene directivas Knockout especiales que se utilizan para vincular ViewModel con la plantilla.
Para obtener más información sobre las directivas y el enlace de Knockout, consulte la documentación oficial de Knockout .
Lo bueno de Knockout
Uno que use Knockout definitivamente apreciará los observables. Los observables son objetos JavaScript especiales que pueden notificar a los suscriptores sobre cambios y detectar dependencias automáticamente. Los observables obtuvieron su nombre porque se pueden observar, lo que significa que otro código puede suscribirse y reaccionar a sus cambios. De esta manera, los observables permiten crear una conexión dinámica entre las variables y los datos para actualizar los datos de la plantilla cuando cambian los datos de un componente.
Si bien los observables son perfectos para detectar y responder a los cambios de un objeto, trabajar con cambios en una colección de cosas requiere un observableArray . ObservableArray rastrea qué objetos están en la matriz, pero no su estado. En pocas palabras, observableArray notifica a los suscriptores cuando se agregan, eliminan, filtran, reorganizan, etc.
En general, los observables ayudan a los desarrolladores a crear lógica para diversos casos que requieren una reacción instantánea a los cambios de ciertos objetos.
Knockout observables en acción
Ahora, consideremos un ejemplo del uso de observables de eliminación de JS en Magento 2. Accedemos al modelo de vista a través de la ruta module-customer/view/frontend/web/js/view/authentication-popup.js y declaramos la variable isLoading como observable usando una palabra clave relevante – observable.
div.embedPastebin { text-align:left; padding: 0; color: #000; margin: 0; font-family: monospace; background: #F7F7F7; border: 1px solid ddd; border-radius:3px; } div.embedPastebin { } div.embedPastebin div.embedFooter { background: #F7F7F7; color: #333; font-size: 100%; padding: 6px 12px; border-bottom: 1px solid #ddd; text-transform:uppercase; } div.embedPastebin div.embedFooter a, div.embedPastebin div.embedFooter a:visited { color: #336699; text-decoration:none; } div.embedPastebin div.embedFooter a:hover { color: red; } .noLines ol { list-style-type: none; padding-left: 0.5em; } .embedPastebin{background-color:#F8F8F8;border:1px solid #ddd;font-size:12px;overflow:auto;margin: 0 0 0 0;padding:0 0 0 0;line-height:21px} .embedPastebin div { line-height:21px; font-family:Consolas, Menlo, Monaco, Lucida Console,’Bitstream Vera Sans Mono’,’Courier’,monospace; } ol { margin:0; padding: 0 0 0 55px} ol li { border:0; margin:0;padding:0; } li.ln-xtra .de1, li.ln-xtra .de2 {background:#F8F8CE;} .embedPastebin ol li.li1 { margin: 0; } .embedPastebin ol li.li2 { margin: 0; }
Ahora, pasemos a la parte Ver que también contiene la variable isLoading . La ruta es: module-customer/view/frontend/web/template/authentication-popup.html .
Finalmente, eche un vistazo a un ejemplo de suscripción a un evento:
div.embedPastebin { text-align:left; padding: 0; color: #000; margin: 0; font-family: monospace; background: #F7F7F7; border: 1px solid ddd; border-radius:3px; } div.embedPastebin { } div.embedPastebin div.embedFooter { background: #F7F7F7; color: #333; font-size: 100%; padding: 6px 12px; border-bottom: 1px solid #ddd; text-transform:uppercase; } div.embedPastebin div.embedFooter a, div.embedPastebin div.embedFooter a:visited { color: #336699; text-decoration:none; } div.embedPastebin div.embedFooter a:hover { color: red; } .noLines ol { list-style-type: none; padding-left: 0.5em; } .embedPastebin{background-color:#F8F8F8;border:1px solid #ddd;font-size:12px;overflow:auto;margin: 0 0 0 0;padding:0 0 0 0;line-height:21px} .embedPastebin div { line-height:21px; font-family:Consolas, Menlo, Monaco, Lucida Console,’Bitstream Vera Sans Mono’,’Courier’,monospace; } ol { margin:0; padding: 0 0 0 55px} ol li { border:0; margin:0;padding:0; } li.ln-xtra .de1, li.ln-xtra .de2 {background:#F8F8CE;} .embedPastebin ol li.li1 { margin: 0; } .embedPastebin ol li.li2 { margin: 0; }
Accedemos a module-checkout/view/frontend/web/js/view/cart/totals.js y vemos:
div.embedPastebin { text-align:left; padding: 0; color: #000; margin: 0; font-family: monospace; background: #F7F7F7; border: 1px solid ddd; border-radius:3px; } div.embedPastebin { } div.embedPastebin div.embedFooter { background: #F7F7F7; color: #333; font-size: 100%; padding: 6px 12px; border-bottom: 1px solid #ddd; text-transform:uppercase; } div.embedPastebin div.embedFooter a, div.embedPastebin div.embedFooter a:visited { color: #336699; text-decoration:none; } div.embedPastebin div.embedFooter a:hover { color: red; } .noLines ol { list-style-type: none; padding-left: 0.5em; } .embedPastebin{background-color:#F8F8F8;border:1px solid #ddd;font-size:12px;overflow:auto;margin: 0 0 0 0;padding:0 0 0 0;line-height:21px} .embedPastebin div { line-height:21px; font-family:Consolas, Menlo, Monaco, Lucida Console,’Bitstream Vera Sans Mono’,’Courier’,monospace; } ol { margin:0; padding: 0 0 0 55px} ol li { border:0; margin:0;padding:0; } li.ln-xtra .de1, li.ln-xtra .de2 {background:#F8F8CE;} .embedPastebin ol li.li1 { margin: 0; } .embedPastebin ol li.li2 { margin: 0; }
En el código, puede ver que la suscripción se refiere a los Totales observables. Ahora, cuando cambien los Totales , una función relacionada activará el evento Redimensionar .
Knockout para el intercambio de datos entre los componentes de la interfaz de usuario
En Magento 2, todas las variables definidas en un componente de UI están limitadas por el área de visibilidad de este componente. Sin embargo, los componentes aún pueden intercambiar datos y variables. Para ello, debe crear un modelo de datos especial en forma de un objeto JavaScript estándar y, utilizando la directiva de definición , incrustar este modelo de datos en el componente con el que desea intercambiar datos. Las funciones y variables de este modelo de datos también se pueden utilizar en el componente de destino.
Los objetos de JavaScript se transfieren por referencia. Entonces, si una variable observable que pertenece a un modelo de datos cambia, este cambio afectará el objeto de origen en el que se define esta variable. En pocas palabras, cuando los componentes comparten variables a través de un modelo de datos, cualquier actualización de una variable observable afectará a todos los componentes que usan esta variable y el modelo de datos compartido.
Aquí hay un ejemplo del modelo del módulo de pago al que accedemos a través de module-checkout/view/frontend/web/js/model/shipping-service.js :
div.embedPastebin { text-align:left; padding: 0; color: #000; margin: 0; font-family: monospace; background: #F7F7F7; border: 1px solid ddd; border-radius:3px; } div.embedPastebin { } div.embedPastebin div.embedFooter { background: #F7F7F7; color: #333; font-size: 100%; padding: 6px 12px; border-bottom: 1px solid #ddd; text-transform:uppercase; } div.embedPastebin div.embedFooter a, div.embedPastebin div.embedFooter a:visited { color: #336699; text-decoration:none; } div.embedPastebin div.embedFooter a:hover { color: red; } .noLines ol { list-style-type: none; padding-left: 0.5em; } .embedPastebin{background-color:#F8F8F8;border:1px solid #ddd;font-size:12px;overflow:auto;margin: 0 0 0 0;padding:0 0 0 0;line-height:21px} .embedPastebin div { line-height:21px; font-family:Consolas, Menlo, Monaco, Lucida Console,’Bitstream Vera Sans Mono’,’Courier’,monospace; } ol { margin:0; padding: 0 0 0 55px} ol li { border:0; margin:0;padding:0; } li.ln-xtra .de1, li.ln-xtra .de2 {background:#F8F8CE;} .embedPastebin ol li.li1 { margin: 0; } .embedPastebin ol li.li2 { margin: 0; }
Preste atención al método setShippingRates que afecta a una variable observable denominada shippingRates . Este método también se usa en el siguiente modelo module-checkout/view/frontend/web/js/model/shipping-rate-processor/customer-address.js :
div.embedPastebin { text-align:left; padding: 0; color: #000; margin: 0; font-family: monospace; background: #F7F7F7; border: 1px solid ddd; border-radius:3px; } div.embedPastebin { } div.embedPastebin div.embedFooter { background: #F7F7F7; color: #333; font-size: 100%; padding: 6px 12px; border-bottom: 1px solid #ddd; text-transform:uppercase; } div.embedPastebin div.embedFooter a, div.embedPastebin div.embedFooter a:visited { color: #336699; text-decoration:none; } div.embedPastebin div.embedFooter a:hover { color: red; } .noLines ol { list-style-type: none; padding-left: 0.5em; } .embedPastebin{background-color:#F8F8F8;border:1px solid #ddd;font-size:12px;overflow:auto;margin: 0 0 0 0;padding:0 0 0 0;line-height:21px} .embedPastebin div { line-height:21px; font-family:Consolas, Menlo, Monaco, Lucida Console,’Bitstream Vera Sans Mono’,’Courier’,monospace; } ol { margin:0; padding: 0 0 0 55px} ol li { border:0; margin:0;padding:0; } li.ln-xtra .de1, li.ln-xtra .de2 {background:#F8F8CE;} .embedPastebin ol li.li1 { margin: 0; } .embedPastebin ol li.li2 { margin: 0; }
En este modelo, aplicamos dependencias para transferir el modelo shippingService al modelo customerAddress y usamos el método setShippingService del modelo shippingService . Además, se actualiza la variable observable isLoading . De esta forma, conectamos el modelo de dirección de cliente con el modelo de servicio de envío y habilitamos el intercambio de datos entre los dos.
Knockout y uso de un componente de interfaz de usuario en un diseño de página
Ahora, veamos un ejemplo de implementación de un componente de interfaz de usuario en un archivo de diseño. Después de acceder al archivo XML ubicado en Amasty/Extrafee/view/frontend/layout/checkout_cart_index.xml , obtenemos:
div.embedPastebin { text-align:left; padding: 0; color: #000; margin: 0; font-family: monospace; background: #F7F7F7; border: 1px solid ddd; border-radius:3px; } div.embedPastebin { } div.embedPastebin div.embedFooter { background: #F7F7F7; color: #333; font-size: 100%; padding: 6px 12px; border-bottom: 1px solid #ddd; text-transform:uppercase; } div.embedPastebin div.embedFooter a, div.embedPastebin div.embedFooter a:visited { color: #336699; text-decoration:none; } div.embedPastebin div.embedFooter a:hover { color: red; } .noLines ol { list-style-type: none; padding-left: 0.5em; } .embedPastebin{background-color:#F8F8F8;border:1px solid #ddd;font-size:12px;overflow:auto;margin: 0 0 0 0;padding:0 0 0 0;line-height:21px} .embedPastebin div { line-height:21px; font-family:Consolas, Menlo, Monaco, Lucida Console,’Bitstream Vera Sans Mono’,’Courier’,monospace; } ol { margin:0; padding: 0 0 0 55px} ol li { border:0; margin:0;padding:0; } li.ln-xtra .de1, li.ln-xtra .de2 {background:#F8F8CE;} .embedPastebin ol li.li1 { margin: 0; } .embedPastebin ol li.li2 { margin: 0; }
En la sección de componentes, establecemos la ruta al archivo Componente responsable del código Knockout del componente. La plantilla de Vista se puede especificar en el código Knockout o en la sección de configuración del diseño de la página (es decir, checkout_cart_index en nuestro caso).
Así es como se ve en el ejemplo anterior:
div.embedPastebin { text-align:left; padding: 0; color: #000; margin: 0; font-family: monospace; background: #F7F7F7; border: 1px solid ddd; border-radius:3px; } div.embedPastebin { } div.embedPastebin div.embedFooter { background: #F7F7F7; color: #333; font-size: 100%; padding: 6px 12px; border-bottom: 1px solid #ddd; text-transform:uppercase; } div.embedPastebin div.embedFooter a, div.embedPastebin div.embedFooter a:visited { color: #336699; text-decoration:none; } div.embedPastebin div.embedFooter a:hover { color: red; } .noLines ol { list-style-type: none; padding-left: 0.5em; } .embedPastebin{background-color:#F8F8F8;border:1px solid #ddd;font-size:12px;overflow:auto;margin: 0 0 0 0;padding:0 0 0 0;line-height:21px} .embedPastebin div { line-height:21px; font-family:Consolas, Menlo, Monaco, Lucida Console,’Bitstream Vera Sans Mono’,’Courier’,monospace; } ol { margin:0; padding: 0 0 0 55px} ol li { border:0; margin:0;padding:0; } li.ln-xtra .de1, li.ln-xtra .de2 {background:#F8F8CE;} .embedPastebin ol li.li1 { margin: 0; } .embedPastebin ol li.li2 { margin: 0; }
A continuación puede ver fragmentos del código del componente Bloque en el Módulo de tarifa adicional ( Amasty_Extrafee/js/view/summary/block) .
En el Componente Amasty_Extrafee/js/view/summary/block , vemos:
div.embedPastebin { text-align:left; padding: 0; color: #000; margin: 0; font-family: monospace; background: #F7F7F7; border: 1px solid ddd; border-radius:3px; } div.embedPastebin { } div.embedPastebin div.embedFooter { background: #F7F7F7; color: #333; font-size: 100%; padding: 6px 12px; border-bottom: 1px solid #ddd; text-transform:uppercase; } div.embedPastebin div.embedFooter a, div.embedPastebin div.embedFooter a:visited { color: #336699; text-decoration:none; } div.embedPastebin div.embedFooter a:hover { color: red; } .noLines ol { list-style-type: none; padding-left: 0.5em; } .embedPastebin{background-color:#F8F8F8;border:1px solid #ddd;font-size:12px;overflow:auto;margin: 0 0 0 0;padding:0 0 0 0;line-height:21px} .embedPastebin div { line-height:21px; font-family:Consolas, Menlo, Monaco, Lucida Console,’Bitstream Vera Sans Mono’,’Courier’,monospace; } ol { margin:0; padding: 0 0 0 55px} ol li { border:0; margin:0;padding:0; } li.ln-xtra .de1, li.ln-xtra .de2 {background:#F8F8CE;} .embedPastebin ol li.li1 { margin: 0; } .embedPastebin ol li.li2 { margin: 0; }
Y la Vista ubicada en Amasty/Extrafee/view/frontend/web/template/fee/block.html se ve así:
div.embedPastebin { text-align:left; padding: 0; color: #000; margin: 0; font-family: monospace; background: #F7F7F7; border: 1px solid ddd; border-radius:3px; } div.embedPastebin { } div.embedPastebin div.embedFooter { background: #F7F7F7; color: #333; font-size: 100%; padding: 6px 12px; border-bottom: 1px solid #ddd; text-transform:uppercase; } div.embedPastebin div.embedFooter a, div.embedPastebin div.embedFooter a:visited { color: #336699; text-decoration:none; } div.embedPastebin div.embedFooter a:hover { color: red; } .noLines ol { list-style-type: none; padding-left: 0.5em; } .embedPastebin{background-color:#F8F8F8;border:1px solid #ddd;font-size:12px;overflow:auto;margin: 0 0 0 0;padding:0 0 0 0;line-height:21px} .embedPastebin div { line-height:21px; font-family:Consolas, Menlo, Monaco, Lucida Console,’Bitstream Vera Sans Mono’,’Courier’,monospace; } ol { margin:0; padding: 0 0 0 55px} ol li { border:0; margin:0;padding:0; } li.ln-xtra .de1, li.ln-xtra .de2 {background:#F8F8CE;} .embedPastebin ol li.li1 { margin: 0; } .embedPastebin ol li.li2 { margin: 0; }
Knockout y transferencia de datos del servidor al componente de la interfaz de usuario
Algunas páginas de Magento 2 incluyen un LayoutProcessor responsable de la generación de componentes. Para transmitir variables dinámicas a la interfaz, debe crear la clase LayoutProcessor en una carpeta de módulo separada , por ejemplo, denominada Block .
La clase LayoutProcessor implementa Magento/Checkout/Block/Checkout/LayoutProcessorInterface .
Luego, en la clase LayoutProcessor , implementamos el método Process que acepta la entrada de una variable jsLayout . jsLayout es más bien una variable de matriz que solo una variable, ya que contiene información sobre todos los componentes que pertenecen a esta página.
Usando esta variable de matriz, podemos referirnos a nuestro componente y cambiar/agregar cualquier variable que necesitemos usar en la interfaz del componente.
Verifique este ejemplo de realización del método Process en Amasty/Extrafee/Block/Cart/LayoutProcessor.php :
Línea de fondo
Hoy, analizamos cómo funciona Knockout JS en Magento 2. En particular, aprendimos a usar los elementos observables de Knockout en los componentes de la interfaz de usuario, agregar componentes de la interfaz de usuario a un diseño de página, habilitar el intercambio de datos entre los componentes de la interfaz de usuario y permitir la transferencia de datos de un servidor a la frontend de un componente.
Espero que este artículo te haya ayudado a comprender mejor Knockout y esperamos tus comentarios e ideas en el feed a continuación.
PD Un agradecimiento especial a Oleg Ivanov por la ayuda con esta publicación.