• 如何在 Rails 中搭配 Turbolinks 使用 Vue


    [Rails] Vue-outlet for Turbolinks

    在踩了 Rails + Turbolinks + Vue 的許多坑後,整理  的作法並和大家分享。

    Initialize the App

    # initialize the app
    rails new rails_sandbox_vue --database=postgresql --webpack=vue
    
    # install package
    bundle
    yarn

    Scaffold the app

    # Scaffold the app
    bin/rails g scaffold User name email
    
    # Create database and migrate
    bin/rails db:setup
    bin/rails db:migrate

    Create Vue Component

    在 ./app/javascript/packs/ 中建立 vue component hello_turbolinks.vue

    <!--  
    ./app/javascript/packs/hello_turbolinks.vue
    -->
    
    <template>
      <div>
        <h4>{{ message }}</h4>
        <ul>
          <li>Object: {{ obj }} </li>
          <li>Number: {{ num }} </li>
          <li>Array: {{ arr }} </li>
          <li>String: {{ str }} </li>
        </ul>
        </div>
    </template>
    
    <script>
    export default {
      props: ['obj', 'arr', 'num', 'str'],
      data: function () {
        return {
          message: 'Hello, Vue and Turbolinks'
        }
      }
    }
    </script>
    
    <style scoped>
    p {
      font-size: 2em;
      text-align: center;
    }
    </style>

    Create Vue Adapter

    建立 vue_adapter.js,在 import Vue 的地方要載入 vue.esm.js 可以 compile template 的版本。另外要把需要使用到的 Vue Component 在這裡執行註冊:

    // ./app/javascript/packs/vue_adapter.js
    import Vue from 'vue/dist/vue.esm.js'
    import HelloTurbolinks from './hello_turbolinks'
    
    /**
     * Register components
     */
    Vue.component('hello-turbolinks', HelloTurbolinks)
    
    function VueConstructor () {
      let outlets = document.querySelectorAll('www.rcsx.org [data-vue-components-outlet]')
      outlets.forEach(function (outlet, index) {
        let id = outlet.getAttribute('data-vue-components-outlet')
        new Vue({
          el: '[data-vue-components-outlet=' + id + ']'
        })
      })
    }
    
    document.addEventListener('turbolinks:load', function () {
      VueConstructor()
    })

    Notice:
    -記得 import 的 Vue 要匯入的是 vue.esm.js
    -記得註冊要使用的 Vue Component

    add vue_adapter in head

    在 layouts/application.html.erb 中的 head 中加入 <%= javascript_pack_tag 'vue_adapter', 'data-turbolinks-track': 'reload' %>

    <!--
    ./app/views/layouts/application.html.erb
    -->
    <!DOCTYPE html>
    <html>
      <head>
        <title>RailsSandboxVue</title>
        <%= csrf_meta_tags %>
    
        <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
        <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
        <%= javascript_pack_tag 'vue_adapter', 'data-turbolinks-track': 'reload' %>
      </head>
    
      <body>
        <%= yield %>
      </body>
    </html>

    Notice: 記得要把 javascript_pack_tag 放在 head 當中

    Import Vue component in template

    我們把 Vue 的組件載入 index.html.erb 中,data-vue-components-outlet 這個屬性是關鍵字,後面放要載入的 Vue 組件名稱:

    <!--
    ./app/views/users/index.html.erb
    -->
    
    <!--  以上省略  -->
    <% @hello_message = {num: 1, str: '2', arr: [1, 2, 3], obj: {name: 'foo', age: 12}} %>
    
    <!-- Import Vue Component -->
    <div data-vue-components-outlet="hello-turbolinks">
      <hello-turbolinks 
      :obj="<%= @hello_message[:obj].to_json %>" 
      :arr="<%= @hello_message[:arr] %>" 
      :str="<%= @hello_message[:str] %>"
      :num="<%= @hello_message[:num] %>"
      ></hello-turbolinks>
    </div>
    <!-- End of Import Vue Component -->
    
    <%= link_to 'New User', new_user_path %>

    完成

    分別開兩個 terminal 到 app 目錄底下,分別執行:

    bin/webpack-dev-server
    bin/rails s

    就可以看到 Vue Component 正確運作了。

    加入 View Helper

    我們也可以寫一個 Rails View Helper 來方便我們使用 Vue 組件:

    在 ./app/helpers/ 中建立一支 vue_helper.rb

    # ./app/helpers/vue_helper.rb
    module VueHelper
      def vue_outlet(html_options = {})
        html_options = html_options.reverse_merge(data: {})
        html_options[:data].tap do |data|
          data[:vue_components_outlet] = "_v" + SecureRandom.hex(5)
        end
        html_tag = html_options[:tag] || :div
        html_options.except!(:tag)
        content_tag(html_tag, '', html_options) do
          yield
        end
      end
    end

    使用方式如下:

    <!--
    ./app/views/users/index.html.erb
    -->
    
    <% @hello_message = {num: 1, str: '2', arr: [1, 2, 3], obj: {name: 'foo', age: 12}} %>
    
    <!-- Import Vue Component by Helper -->
    <%= vue_outlet do %>
      <hello-turbolinks 
      :obj="<%= @hello_message[:obj].to_json %>"
      :arr="<%= @hello_message[:arr] %>" 
      :str="<%= @hello_message[:str] %>"
      :num="<%= @hello_message[:num] %>"
      >
    <% end %>
    <!-- End of Import Vue Component by Helper -->

    如果需要 tag 不想要使用 div 可以加上 options:

     
    <!--
    ./app/views/users/index.html.erb
    -->
    
    <!-- With <p> -->
    <%= vue_outlet tag: 'p' do %>
      <hello-turbolinks 
      :obj="<%= @hello_message[:obj].to_json %>"
      :arr="<%= @hello_message[:arr] %>" 
      :str="<%= @hello_message[:str] %>"
      :num="<%= @hello_message[:num] %>"
      >
    <% end %>
    <!-- End of With <p> -->
  • 相关阅读:
    C#使用GZipStream压缩与解压字符串
    C# 参考之方法参数关键字:params、ref及out
    C#中cookie讲解
    WPF中窗口控件的跨线程调用
    vs2010 快捷键大全
    Python线程池
    Python 爬虫修正
    Python 爬虫插件
    Python发现爬虫插件有BUG。
    Python 存在BUG的线程池
  • 原文地址:https://www.cnblogs.com/tianshifu/p/7333770.html
Copyright © 2020-2023  润新知