[vue]用component來包裝jquery的plugin

[vue]用component來包裝jquery的plugin

前言

因為有同事剛開始學習vue,原有網站都是一些jquery或一些jquery的元件,在不想改變很大的外觀之外,又想要達成vue.js的功能,然後我就發現因為不懂vue,所以會用很奇怪的方式來想辦法達成這樣的需求,接下來首先我想說明一下如何讓vue和jquery互動起來。

首先我使用到的是jquery ui的datepicker來示例,其實vue可以很容易的跟jquery配合在一起,我們可以把vue包在document.ready裡面,以確保jquery已經開始運作了

<body>
<link href="https://code.jquery.com/ui/jquery-ui-git.css" rel="stylesheet" type="text/css" />
<script src="https://code.jquery.com/jquery-git.js"></script>
<script src="https://code.jquery.com/ui/jquery-ui-git.js"></script>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div id="app">
  <input id="date1" type="test" v-model="model.date" />
  <input type="button" value="add"  @click="submit"/>
</div>
  
  <script>
   $(function(){
      let vue=new Vue({
      el:'#app',
      data:{
        model:{
          date:''
        }
      },
      methods:{
         submit:function(){
           console.log(this.model.date)
         }
      },
      created:function(){
        $('#date1').datepicker()
      }
    })
   })
  </script>
</body>

但其實我們只要在created裡面就可以使用jquery了,並不需要使用document.ready包起來,因為vue總會是比原生的生命週期晚一點點

<body>
  <link href="https://code.jquery.com/ui/jquery-ui-git.css" rel="stylesheet" type="text/css" />
  <script src="https://code.jquery.com/jquery-git.js"></script>
  <script src="https://code.jquery.com/ui/jquery-ui-git.js"></script>
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <div id="app">
    <input id="date1" type="test" v-model="model.date" />
    <input type="button" value="add" @click="submit" />
  </div>

  <script>
    let vue = new Vue({
      el: '#app',
      data: {
        model: {
          date: ''
        }
      },
      methods: {
        submit: function () {
          console.log(this.model.date)
        }
      },
      created: function () {
        $('#date1').datepicker()
      }
    })
  </script>
</body>

如果我們想要改成國字的顯示,可能就會改成如下

<body>
  <link href="https://code.jquery.com/ui/jquery-ui-git.css" rel="stylesheet" type="text/css" />
  <script src="https://code.jquery.com/jquery-git.js"></script>
  <script src="https://code.jquery.com/ui/jquery-ui-git.js"></script>
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <div id="app">
    <input id="date1" type="test" v-model="model.date" />
    <input type="button" value="add" @click="submit" />
  </div>

  <script>
    let vue = new Vue({
      el: '#app',
      data: {
        model: {
          date: ''
        }
      },
      methods: {
        submit: function () {
          console.log(this.model.date)
        }
      },
      created: function () {
        var ops = {
          dayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
          dayNamesMin: ["日", "一", "二", "三", "四", "五", "六"],
          monthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
          monthNamesShort: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
          prevText: "上月",
          nextText: "次月",
          weekHeader: "週",
          showMonthAfterYear: true,
          dateFormat: "yy-mm-dd"
        }
        $('#date1').datepicker(ops)
      }
    })
  </script>
</body>

但是請想像一下如果我們在很多頁面都用到的話,這些設定值散落各處,一想都會覺得非常的悲慘,如果有一天又要改format的話,這樣子我們不就要全部找出來哪個地方有用到datepicker,全部修改完畢,接著我們來包成元件解決這個問題吧

把jquery ui的plugin包裝成component

<body>
  <link href="https://code.jquery.com/ui/jquery-ui-git.css" rel="stylesheet" type="text/css" />
  <script src="https://code.jquery.com/jquery-git.js"></script>
  <script src="https://code.jquery.com/ui/jquery-ui-git.js"></script>
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <div id="app">
    <datepicker v-model="model.date"></datepicker>
    <datepicker v-model="model.date1"></datepicker>
    <input type="button" value="add" @click="submit" />
  </div>

  <script>
    Vue.component('datepicker', {
      props: ['value'],
      template: '<input type="text" />',
      mounted: function () {
        let vm = this
        $(this.$el).datepicker({
          dayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
          dayNamesMin: ["日", "一", "二", "三", "四", "五", "六"],
          monthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
          monthNamesShort: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
          prevText: "上月",
          nextText: "次月",
          weekHeader: "週",
          showMonthAfterYear: true,
          dateFormat: "yy-mm-dd",
          onSelect: function (date) {
            vm.$emit('input', date) //注意一下裡面的this是jquery對象的部份,所以定義一個vm變數代表vue的實體
          }
        })
      }
    })

    let vue = new Vue({
      el: '#app',
      data: {
        model: {
          date: '',
          date1: ''
        }
      },
      methods: {
        submit: function () {
          console.log(this.model.date)
          console.log(this.model.date1)
        }
      }
    })
  </script>
</body>

因為我們包成component了,也就不用再需要id的編號了,可以在畫面放多個元件,而且也不用管id是要命名什麼了,此示例有興趣可以至(http://jsbin.com/savigewoli/edit?html,output)改動測試看看。

動態決定config的設定

其實做法取決於設計者的做法,不過這邊的做法只是示例,比較正確來說應該是只有需求改變的時候,再設定特定的props,不要為了預測需求而去浪費時間過度假設,而如果我們設定的細項越細的話,當然就也可以設定還有說明註解寫得更清楚,讓使用者可以了解component有什麼props可以用。

<body>
  <link href="https://code.jquery.com/ui/jquery-ui-git.css" rel="stylesheet" type="text/css" />
  <script src="https://code.jquery.com/jquery-git.js"></script>
  <script src="https://code.jquery.com/ui/jquery-ui-git.js"></script>
  <script src="https://unpkg.com/vue/dist/vue.js"></script>
  <div id="app">
    <datepicker v-model="model.date" :option="option"></datepicker>
    <datepicker v-model="model.date1"></datepicker>
    <input type="button" value="add" @click="submit" />
  </div>

  <script>
    Vue.component('datepicker', {
      props: ['value', 'option'],
      template: `<input type="text" />`,
      mounted: function () {
        var vm = this
        let option = {}
        if (!this.option) {
          option = {
            dayNames: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
            dayNamesMin: ["日", "一", "二", "三", "四", "五", "六"],
            monthNames: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
            monthNamesShort: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
            prevText: "上月",
            nextText: "次月",
            weekHeader: "週",
            showMonthAfterYear: true,
            dateFormat: "yy-mm-dd",
            onSelect: function (date) {
              vm.$emit('input', date)
            }
          }
        } else {
          option = this.option
          option.onSelect=function(date){
            vm.$emit('input', date)
          }
        }
        $(this.$el).datepicker(option)
      }
    })

    let vue = new Vue({
      el: '#app',
      data: {
        model: {
          date: '',
          date1: ''
        },
        option: {
          dateFormat: "mm-dd"
        }
      },
      methods: {
        submit: function () {
          console.log(this.model.date)
          console.log(this.model.date1)
        }
      }
    })
  </script>
</body>

可以直接至此測試看看(http://jsbin.com/levewilaqa/edit?html,output)

結論

雖然vue已經提供了非常多的元件了,但是如果你還需要其他原本jquery的,或者你需要操作到dom的方式,來自訂一些元件的話,一定得要包裝成元件,才是比較好和正確的方式,盡量不要在vue的程式碼裡面操作dom對以後維護來說都會更好。