[譯]怎樣在Vue.js中使用jquery插件

 

原文:http://gambardella.info/2016/09/05/guide-how-to-use-vue-js-with-jquery-pluginscss

 

使用Vue真的太棒了,可是也有可能使你頭疼,當你試圖使它與jquery插件混用的時候。vue

問題的緣由是jquery與Vue是徹底不一樣的東西,Vue是經過組件與數據綁定來進行渲染的,jquery則主要是用來作簡單的單擊處理和強大的操縱DOM的能力。node

我試圖尋找一些東西來幫助本身解決這個問題,可是我發現一些組件所作的工做不是很讓我滿意,因此讓我告訴你怎樣使Vue與jquery插件混用。jquery

 

這麼作的目的是什麼?webpack

大多數狀況下你能使用jquery和一些簡單的Vue來知足你的需求,Modals, sliders等等和一些Vue組件結合起來是很快的。web

因此咱們的目標是用強大的jQuery插件與Vue快速結合。vue-cli

咱們將...npm

  • 用Vue的自定義指令來構建jquery
  • 當元素生成時初始化插件
  • 當元素撤銷時銷燬插件
  • 發送事件來通知組件
  • 從組件接收事件並將它們傳遞給插件

 

教程時間app

我選擇Fengyuan Chen’s的cropper由於它是一個很棒的jQuery插件,若是時間限制在60分鐘以內的話你確定不可能重寫這個插件在不使用Vue的狀況下。jquery插件

DEMO:https://vue-jquery-cropper-demo.firebaseapp.com/

我將從最開始來演示,若是你已經完成請跳過這個部分。

 

建立項目

# install vue-cli
$ npm install -g vue-cli
# create a new project using the "webpack" boilerplate
$ vue init webpack vue-cropper

? Project name "vue-cropper"
? Project description "A Vue.js project"
? Author "Christian Gambardella <christian@gambardella.info>"
? Use ESLint to lint your code? "Yes"
? Pick an ESLint preset "Standard"
? Setup unit tests with Karma + Mocha? "No"
? Setup e2e tests with Nightwatch? "No"

$ cd vue-cropper
$ npm install

祝賀你已經有了一個Vue的項目。

 

安裝 jQuery 和 cropper.js

# install jQuery & cropper
$ npm install jquery cropper --save

 

爲jquery和Vue自定義指令配置webpack

爲webpack配置添加jquery和Vue自定義指令的映射。

一般webpack已經引入了完整的jquery版本,但仍是建議再一次引入一下。

您能夠看到Vue的webpack模板已經添加到組件的文件夾中。我一般會添加不少其餘文件夾像自定義指令,mixin等等。在這個例子中,咱們只添加了自定義指令。

這將幫助咱們引入依賴關係而無需知道其確切的路徑。這也是有益的在你重構你的應用的時候。你也並不須要管理相對路徑。

把下面高亮部分添加到build/webpack.base.conf文件中。

resolve: {
  extensions: ['', '.js', '.vue'],
  fallback: [path.join(__dirname, '../node_modules')],
  alias: {
    'src': path.resolve(__dirname, '../src'),
    'assets': path.resolve(__dirname, '../src/assets'),
    'components': path.resolve(__dirname, '../src/components'),
    'jquery': path.resolve(__dirname, '../node_modules/jquery/src/jquery'), 'directives': path.resolve(__dirname, '../src/directives')
  }
},

不要忘了在末尾添加逗號。

 

準備應用組件

我要開始使用組件,由於我相信這是更容易理解的,漂亮和簡單的組件。若是你已經知道如何在組件中使用它們那麼就能夠當即寫這個指令來實現它們。

替換src/App.vue文件的template部分

<template>
  <div id="app">
    <img
      v-cropper="cropOptions"
      src="https://i.imgur.com/WcvkCxl.png"
      alt="jQuery Meme">
  </div>
</template>

替換src/App.vue文件的script部分

<script>
import Cropper from './directives/Cropper'

export default {
  directives: {
    Cropper
  },

  data () {
    return {
      cropOptions: {
        viewMode: 0,
        zoomable: false
      }
    }
  }
}
</script>

一些須要重點注意的地方

  • 咱們引入jQuery也不須要處理組件的初始化。
  • 把Cropper的設置選項當作原始綁定數據。
  • Cropper將在初始化時渲染,再銷燬時使其消失。
  • 組件的名字能夠在template用做標籤使用,MyCropper轉變爲my-cropper。
  • 對它進行初始化時,咱們必須添加v-my-cropper元素在組件的模板裏。

 

建立Cropper組件

這是本教程的核心。咱們要建立一個Cropper指令來處理低層代碼的DOM操做。在這種狀況下咱們要初始化Cropper。

  自定義指令是用來提供一種機制來映射數據並任意操做DOM的行爲。

建立src/directives/Cropper.js

import jQuery from 'jquery'
import 'cropper'

export default {
  deep: true,

  bind () {},

  update (options) {
    // Destroy in case it has been initialized already.
    jQuery(this.el).cropper('destroy')
    // Initializing directly after destroying
    // didn't work. Wrapping it in a setTimeout
    // seems to do the trick.
    setTimeout(() => {
      jQuery(this.el).cropper(options)
    }, 0)
  },

  unbind () {
    jQuery(this.el).cropper('destroy')
  }
}

每個Vue自定義組件的最核心部分是其提供能夠用來綁定,更新,解綁相應方法。

  • bind:當元素在文檔中生成時只觸發一次。
  • update:當bind方法觸發後和綁定數據改變時觸發,在這種狀況下cropOptions只是一個對象。Vue.js自定義指令須要知道若是它的相關屬性也是一個對象。這就是爲何咱們須要添加deep: true在這種狀況下。
  • unbind:當DOM元素被移除時觸發,在這個方法裏能夠銷燬組件而且移除監聽的事件。

在Vue 2中會有些許變化。

vm實例被做爲函數參數傳遞,不會被設置爲this。

指令的update方法只能在數據改變後觸發而不會在bind方法以後觸發。

 

第一次運行

這是咱們所能作的最小限度,讓咱們運行起來看看如何。

這是很快作出來的,因此咱們並無添加cropper的樣式,讓咱們添加並再一次運行。

先添加高亮部分在src/main.js文件中

import '../node_modules/cropper/dist/cropper.css'
import Vue from 'vue'
import App from './App'

/* eslint-disable no-new */
new Vue({
  el: 'body',
  components: { App }
})

 

啓動服務

$ npm run dev

當全部事情都作好後,你應該看到一個圖片和一個cropbox而且可使其移動。

切換 on/off

從如今起一切都會很簡單。咱們將經過這個案件。使每件事都會簡單起來。

咱們用一個按鈕來啓用和禁用cropper。頁面開始用戶選擇一個文件切換爲cropper的打開狀態。證實了cropper能夠在任什麼時候候被初始化。

編輯src/App.vue的script部分

import Cropper from './directives/Cropper'

export default {
  directives: {
    Cropper
  },

  data () {
    return {
      cropOptions: {
        viewMode: 0,
        zoomable: false
      },
      showCropper: false
    }
 }, methods: { toggleCropper () { this.showCropper = !this.showCropper } }
}
  • data中添加showCropper: false
  • 添加一個切換方法toggleCropper

編輯src/App.vue的template部分

<div id="app">
  <button id="toggle" @click="toggleCropper">Toggle Cropper</button>
  <img
    v-if="showCropper"
    v-cropper="cropOptions"
    src="https://i.imgur.com/WcvkCxl.png"
    alt="Mustache">
</div>
  • 添加一個按鈕綁定@click
  • 在img標籤上添加v-if指令

每一次圖像的顯示都會調用自定義cropper指令的bind和update方法。

當showCropper設置爲false時,cropper的unbind將被調用。

這裏不會使咱們陷入困境。

cropper將被加載在用戶須要時和卸載後。

 

改變選項

咱們已經擁有須要更新cropper的選項。若是咱們有一個現有jQuery插件,而且會接收新選項,咱們將不須要銷燬當前實例來從新建立插件實例。不幸的是cropper不容許這樣。

讓咱們添加一個開關來控制圖像縮放。

編輯src/App.vue的template部分

<div id="app">
  <button id="toggle" @click="toggleCropper">Toggle Cropper</button>
  <img
    v-if="showCropper"
    v-cropper="cropOptions"
    src="https://i.imgur.com/WcvkCxl.png"
    alt="Mustache">
  <input id="zoomable" type="checkbox" v-model="cropOptions.zoomable">
  <label for="zoomable">Zoomable?</label>
</div>

很簡單,對嗎?

 

經過指令獲取數據

cropper有一個回調方法,當咱們觸發一個事件時將會調用這個方法。

編輯src/directives/Cropper.js

import jQuery from 'jquery'
import 'cropper'

export default {
  deep: true,

  bind () {},

  update (options) {
 options.crop = (event) => { this.vm.$emit('crop', event) } // Destroy in case it has been initialized already.
    jQuery(this.el).cropper('destroy')
    // Initializing directly after destroying
    // didn't work. Wrapping it in a setTimeout
    // seems to do the trick.
    setTimeout(() => {
      jQuery(this.el).cropper(options)
    }, 0)
  },

  unbind () {
    jQuery(this.el).cropper('destroy')
  }
}

編輯App組件的script部分來處理crop事件

import Cropper from './directives/Cropper'

export default {
  directives: {
    Cropper
  },

  data () {
    return {
      cropData: {},
      cropOptions: {
        viewMode: 0,
        zoomable: false
      },
      showCropper: false
    }
 }, events: { crop (event) { this.cropData = { x: event.x, y: event.y, width: event.width, height: event.height } } },

  methods: {
    toggleCropper () {
      this.showCropper = !this.showCropper
    }
  }
}

編輯App組件的template部分來展現crop數據

<template>
  <div id="app">
    <button id="toggle" @click="toggleCropper">Toggle Cropper</button>
    <img
      v-if="showCropper"
      v-cropper="cropOptions"
      src="https://i.imgur.com/WcvkCxl.png"
      alt="Mustache">
    <input id="zoomable" type="checkbox" v-model="cropOptions.zoomable">
    <label for="zoomable">Zoomable?</label>
    <pre id="output"> x: {{ cropData.x }} y: {{ cropData.y }} width: {{ cropData.width }} height: {{ cropData.height }} </pre>
  </div>
</template>

正如您所看到的我選擇從指令來發出事件來監聽App組件。問問本身爲何選擇這麼作。我也能夠選擇在App組件上面建立一個方法,將其綁定到cropper的監聽器中。 

反模式。options.crop = this.vm.handleCrop

 

操做其餘action

最後使事件從一個組件流向一個指令來改變顯示狀態。咱們要用它來調用cropper的action。讓我告訴你我將如何添加一個按鈕來控制圖片旋轉。

編輯App組件的temlpate部分並添加一個控制圖片旋轉的按鈕

<template>
  <div id="app">
    <button id="toggle" @click="toggleCropper">Toggle Cropper</button>
    <img
      v-if="showCropper"
      v-cropper="cropOptions"
      src="https://i.imgur.com/WcvkCxl.png"
      alt="Mustache">
    <input id="zoomable" type="checkbox" v-model="cropOptions.zoomable">
    <label for="zoomable">Zoomable?</label>
    <button @click="$emit('rotate', 90)">Rotate 90°</button>
    <pre id="output">
x: {{ cropData.x }}
y: {{ cropData.y }}
width: {{ cropData.width }}
height: {{ cropData.height }}
    </pre>
  </div>
</template>

編輯src/directives/Cropper.js添加用來監聽和解綁的事件

import jQuery from 'jquery'
import 'cropper'

export default {
  deep: true,

 bind () { this.vm.$on('rotate', (deg) => { jQuery(this.el).cropper('rotate', deg) }) },

  update (options) {
    options.crop = (event) => {
      this.vm.$emit('crop', event)
    }
    // Destroy in case it has been initialized already.
    jQuery(this.el).cropper('destroy')
    // Initializing directly after destroying
    // didn't work. Wrapping it in a setTimeout
    // seems to do the trick.
    setTimeout(() => {
      jQuery(this.el).cropper(options)
    }, 0)
  },

  unbind () {
    jQuery(this.el).cropper('destroy')
    this.vm.$off('rotate')
  }
}

 

摘要

Et voilà you’re done!

這樣作的美妙之處在於,指令是用來解耦組件並在多個組件中使用,它會自動初始化並附加到DOM元素中,在DOM被移除以前銷燬。

我但願你會喜歡這篇文章,若是你有問題和建議,可隨時給我發消息或評論文章。

Best,Christian

相關文章
相關標籤/搜索