Vue.js: hacer que las funciones auxiliares estén disponibles globalmente para componentes de un solo archivo

101

Tengo un proyecto de Vue 2 que tiene muchos (50+) componentes de un solo archivo . Utilizo Vue-Router para enrutamiento y Vuex para estado.

Hay un archivo, llamado helpers.js , que contiene un montón de funciones de propósito general , como poner en mayúscula la primera letra de una cadena. Este archivo tiene este aspecto:

export default {
    capitalizeFirstLetter(str) {
        return str.charAt(0).toUpperCase() + str.slice(1);
    }
}

Mi archivo main.js inicializa la aplicación:

import Vue from 'vue'
import VueResource from "vue-resource"
import store from "./store"
import Router from "./router"
import App from "./components/App.vue"

Vue.use(VueResource)

const app = new Vue({
    router: Router,
    store,
    template: '<app></app>',
    components: { App }
}).$mount('#app')

Mi archivo App.vue contiene la plantilla:

<template>
    <navbar></navbar>
    <div class="container">
        <router-view></router-view>
    </div>
</template>

<script>
export default {
    data() {
        return {
            //stuff
        }
    }
}
</script>

Luego tengo un montón de componentes de un solo archivo, que Vue-Router maneja navegando dentro de la <router-view>etiqueta en la plantilla App.vue.

Ahora digamos que necesito usar la capitalizeFirstLetter()función dentro de un componente que está definido en SomeComponent.vue . Para hacer esto, primero necesito importarlo:

<template>Some Component</template>

<script>
import {capitalizeFirstLetter} from '../helpers.js'
export default {
    data() {
        return {
            myString = "test"
        }
    },
    created() {
         var newString = this.capitalizeFirstLetter(this.myString)
    }
}
</script>

Esto se convierte en un problema rápidamente porque termino importando la función en muchos componentes diferentes, si no en todos. Esto parece repetitivo y también hace que el proyecto sea más difícil de mantener. Por ejemplo, si quiero cambiar el nombre de helpers.js, o las funciones dentro de él, entonces necesito ir a cada componente que lo importa y modificar la declaración de importación.

En pocas palabras: ¿cómo puedo hacer que las funciones dentro de helpers.js estén disponibles globalmente para poder llamarlas dentro de cualquier componente sin tener que importarlas primero y luego anteponerlas thisal nombre de la función? Básicamente quiero poder hacer esto:

<script>
export default {
    data() {
        return {
            myString = "test"
        }
    },
    created() {
         var newString = capitalizeFirstLetter(this.myString)
    }
}
</script>
Ege Ersoz
fuente
Podrías usar un mixin global, pero tendrías que usar this.
Bert
2
¿Ha considerado exponer sus ayudantes como filtros para que puedan usarse directamente en sus plantillas sin necesidad de importarlos? Esa es la estrategia que estoy tomando y hasta ahora está funcionando bien.
David Weldon

Respuestas:

155

dentro de cualquier componente sin tener que importarlos primero y luego anteponer esto al nombre de la función

Lo que describiste es mixin .

Vue.mixin({
  methods: {
    capitalizeFirstLetter: str => str.charAt(0).toUpperCase() + str.slice(1)
  }
})

Este es un mixin global. con esto TODOS sus componentes tendrán un capitalizeFirstLettermétodo, por lo que puede llamar this.capitalizeFirstLetter(...)desde métodos de componentes o puede llamarlo directamente como capitalizeFirstLetter(...)en la plantilla de componentes.

Ejemplo de trabajo: http://codepen.io/CodinCat/pen/LWRVGQ?editors=1010

Consulte la documentación aquí: https://vuejs.org/v2/guide/mixins.html

CodinCat
fuente
¡Buena esa! ¡Gracias!
Alexey Shabramov
20
Sería bueno tener más detalles en esta respuesta, por ejemplo, ¿cómo almacena la función mixin en su propio archivo dedicado y cómo lo importa en main.js?
Alexis.Rolland
¿Cómo puedo usar capitalizeFirstLetterdesde una const vm = new Vue()instancia? Porque vm.capitalizeFirstLetterno funciona.
Marcelo Rodovalho
¿Todos los componentes harán referencia a la capitalizeFirstLetterfunción en el mixin o tendrán su propia copia? Estoy buscando un lugar para almacenar una función que debería ser accesible para todos los componentes, pero que de lo contrario no estaría relacionada con ellos (obtener datos de un servidor para almacenarlos en un almacenamiento vuex)
Daniel F
Gracias ! Funciona bien en componentes pero no en "store.js". Tengo un mixin que personaliza "console.log": "log: str => console.log ('% c' + str + '', 'background: #aaa; color: #fff; padding: 5px; border- radio: 5px ') ". ¿Cómo puedo usarlo en store.js por favor?
bArraxas
66

De lo contrario, podría intentar hacer que sus ayudantes funcionen como un complemento:

import Vue from 'vue'
import helpers from './helpers'

const plugin = {
  install () {
    Vue.helpers = helpers
    Vue.prototype.$helpers = helpers
  }
}

Vue.use(plugin)

En su helper.jsexportación sus funciones, de esta manera:

const capFirstLetter = (val) => val.charAt(0).toUpperCase() + val.slice(1);
const img2xUrl = (val) => `${val.replace(/(\.[\w\d_-]+)$/i, '@2x$1')} 2x`;

export default { capFirstLetter, img2xUrl };

o

export default { 
  capFirstLetter(val) {
    return val.charAt(0).toUpperCase() + val.slice(1);
  },
  img2xUrl(val) {
    return `${val.replace(/(\.[\w\d_-]+)$/i, '@2x$1')} 2x`;
  },
};

Entonces debería poder usarlos en cualquier lugar de sus componentes usando:

this.$helpers.capitalizeFirstLetter()

o en cualquier lugar de su aplicación usando:

Vue.helpers.capitalizeFirstLetter()

Puede obtener más información sobre esto en la documentación: https://vuejs.org/v2/guide/plugins.html

Hammerbot
fuente
Enumere el contenido de helpers.vue
Marius
¿Podría incluir un ejemplo sobre cómo acceder a la tienda Vue? this. $ store funciona en componentes, pero no en un mixin.
Marius
1
El contenido de helpers.js está en cuestión
Hammerbot
9

Crea un nuevo mixin:

"src / mixins / generalMixin.js"

Vue.mixin({
  methods: {
    capitalizeFirstLetter(str) {
        return str.charAt(0).toUpperCase() + str.slice(1);
    }    
  }
})

Luego impórtelo en su main.js como:

import '@/mixins/generalMixin'

A partir de ahora, podrá utilizar la función como this.capitalizeFirstLetter(str)dentro de su script de componente o sin ella thisen una plantilla.

Debe usarlo thisporque mezcló un método en la instancia principal de Vue. Si hay formas de eliminarlo this, probablemente implique algo poco convencional, al menos esta es una forma documentada de compartir funciones que será fácil de entender para cualquier futuro desarrollador de Vue de su proyecto.

cavar
fuente
1

Usando Webpack v4

Cree un archivo separado para facilitar la lectura (simplemente colocó el mío en la carpeta de complementos). Reproducido de las respuestas de @CodinCat y @digout

//resources/js/plugins/mixin.js
import Vue from 'vue'

Vue.mixin({
    methods: {
      capitalizeFirstLetter: str => str.charAt(0).toUpperCase() + str.slice(1),
      sampleFunction(){
        alert('Global Functions')
      }
    }
  })

Luego importe en su archivo main.js o app.js

//app.js
import mixin from './plugins/mixin' 

USO:

Llamar this.sampleFunction()othis.capitalizeFirstLetter()

DAVID AJAYI
fuente
1

Utilice un filtro global si solo se refiere a cómo se formatean los datos cuando se procesan. Este es el primer ejemplo en los documentos :

{{ message | capitalize }}
Vue.filter('capitalize', function (value) {
  if (!value) return ''
  value = value.toString()
  return value.charAt(0).toUpperCase() + value.slice(1)
})
ellisdod
fuente
0

Gran pregunta. En mi investigación, descubrí que vue-inject puede manejar esto de la mejor manera. Tengo muchas bibliotecas de funciones (servicios) que se mantienen separadas de los métodos estándar de manejo de lógica de componentes vue. Mi elección es que los métodos de componentes sean simplemente delegadores que llamen a las funciones de servicio.

https://github.com/jackmellis/vue-inject

usuario3525949
fuente
-5

Impórtelo en el archivo main.js como 'tienda' y puede acceder a él en todos los componentes.

import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  store,
  router,
  render: h => h(App)
})
usuario2090357
fuente
11
¿Puede completar la respuesta mostrando cómo usarlo en un componente?
JeanValjean