(GoRails )使用Vue.js制作拖拉list功能(v1-4) gem 'acts_as_list'(自动排列顺序)

系列视频:

use Vue.js to build the drag and drop support for the list themselves

the cards that are underneath them, and then we're going to be syncing(同步) this back to the rails app using AJAX。

async(异步)


 

视频1

app添加必要gem,  添加基础结构,建设Vue.js单文件组件app.vue,和packs/applications.js ,添加热重加载。

重点:添加library: vuedragger

 

初始化:

10283 rails new Trello --webpack=vue
10284 cd Trello
10285 atom .  然后add gem 'devise'
10286 bundle 
10287 rails g devise:install
10288 rails g devise user
10289 rails db:migrate

add gem 'bootstrap'和gem 'jquery-rails'

10292 bundle install
10293 git add .
10294 git commit -m 'Initialize/add gem devise, bootstrap, jquery-rails'

 

数据架构:

10295 rails g scaffold List name position:integer
10297 rails g scaffold Card list:references name position:integer

add gem 'acts_as_list'  (点击查看git) 用于自动排序

  • (当一条记录的postion发生变化,其他的对应变化,比如在表格第一行插入一条记录,之后的记录的position会全部➕1)

类似于ranked-model(全占里面有教学,见博客)

10298 bundle install


 

 

在routes.rb加上 root to: 'lists#index'

在view/lists/index.html.erb?️添加:

<%= tag.div("dsa",id: :boards, data: { lists: @lists.as_json(include: :cards)})%>

tag.<tag_name>(optional content, options)

⚠️:这是5.1中的ActionView::Helper::TagHelper方法,在5.2版本的Module中被去掉了。但仍可以在Rails5.21中使用。

⚠️老版Rails的to_json从3.0就改成as_json方法,但都能用,功能一样。

 


 

安装资源库:从Vue资源:https://github.com/vuejs/awesome-vue下载

Libraries/UI Components/Form/Drag and Drop

yarn add vuedraggable (5000?)     (点击查看git)

 


 

 

在layout/application.html.erb上的<header>增加:

<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload'%>
<%= stylesheet_pack_tag 'application', media: 'all', 'data-turbolinks-track': 'reload'%>

 

⚠️:

  • media: 'all' 是默认值,代表接受任意的设备类型(iphone, computer, screenreaders等等)
  • media属性被用于指定目标URL,  目标URL是为特定的设备所设计。

 


 

⚠️:热重加载:(热重载) Hot Reload(hot reload)

这是Vue Loader的功能之一

 

修改 .vue 文件时,该组件的所有实例将在不刷新页面的情况下被替换。

保持了应用程序和被替换组件的当前状态!(有3条规则)

当你调整模版或者修改样式时,这极大地提高了开发体验。

 

状态保留规则:

  • 当编辑一个组件的<template>时,这个组件实例就地重渲染,保留当前的所有私有状态。
  • 当编辑一个组件的<script>时,这个组件实例销毁!,并重新创建。即重加载而不是重新渲染。
  • <style>通过vue-style-loader自行热重载。不会影响应用的状态!

 

用法:

  • 使用vue-cli手脚架工具,开箱即用。
  • 手动设置你的工程时,启动bin/webpack-dev-server --hot服务时自动开启。
  • 高级用户: vue-loader内部的vue-hot-reload-api

关闭热重载:

 

module: {
  rules: [
    {
      test: /\.vue$/,
      loader: 'vue-loader',
      options: {
        hotReload: false // 关闭热重载
      }
    }
  ]
}

 

 

 


  

在application.js 

<App v-bind:xxx=''外部数据"> 绑定一个prop。

 

在app.js,增加prop, 修改template.


 

视频2

写template和相关的method。 

增加新cards到Vue app, 数据存入数据库。

用Ajax提交请求,并再渲染UI

 

⚠️: 注意提交请求的data数据要通过服务器端的验证:包括参数白名单,模型验证等。

//手脚架自动生成的card_params方法中没有:list_id,会报告❌ .

在controller#create中有:

format.json { render json: @card.errors, status: :unprocessable_entity }

在控制台提示:

// list: [must exits]。

 

messages[list_id]是data选项中的messages: {}和<textarea>绑定的prop选项的其中一个值。

因为有多个输入框<textarea>所以需要绑定多个prop,这里用一个messages对象作为prop,

绑定的是messages[list.id]。

messages如果是String的话,就悲剧了,所有输入框都绑定同一个prop的值,就乱套了。

 


 

视频3

实做Vue.draggable插件,增加drag和drop功能给Vue.js app, 并同步变化到服务器。 

第一步,drag list。

drag card更复杂,除了在一个list内改变位置,还可以在lists之间改变,这就增加了难度,所以以后再做。

 

在app.vue中加上:

<script>

 // import是否可以加在外面???
 import draggable from 'vuedraggable'

..

 

更改<template>

<draggable>会自动生成<div>标签。

<draggable v-model='lists' v-bind:options="{group: 'lists'}" class='row dragArea' @end='listMoved'>

分析:

  1. v-model是用于绑定data选择中的lists数据。
  2. :options="{group: 'lists'}" <draggable>组件的一个可选prop。初始化一个Sortable 对象。
    • new Sortable(组件所在的根元素, {group:"lists", sort: true, ...大量属性,大量方法,回调函数),其中onStart,onEnd等方法也在内。用于拖拉表单的记录。
    • ⚠️:这个是为了card的拖拉功能而加上的prop,只是list的拖拉的话,无需这个prop。
    • 理解英文:因为每个list内还要做一个可拖拽的card功能. 因为每个columns将有一个可拖拉的cards, 你将能够拖拉卡片通过那些columns, 因为它们在同一组。group至关重要的,它可以知道cards能放到哪里/不能放到哪里。
      • that's going to separate these out so that you can't drag and drop cards as a replacements for lists and so on, and so then we're going to go and create another draggable section down below where you have them all as cards, and because each column will have a cards type of draggable, you'll be able to drag cards across those columns because they're the same group, and so that group is crucial to knowing where those objects can and cannot drop。
  3. class='dragArea', 设定最小高度,保证拖动的区域是实际可见的。这样鼠标进入它后,它能够知道这里是可以拖拉的。不是特别重要,它依赖你的UI的设计。
  4. @end='listMoved', 监听一个event事件onEnd(), 并生成一个Event对象含有Sortable的参数。

 

然后添加methods, listMoved. 这个方法包括提交请求request,改变list对象的positon.

需要做的事情:

  1. 写listMoved方法:新建Formdata,添加数据,并用Rails.ajax传递,type是'PATCH'
  2. 写url, 在route.rb中添加一个 resources lists do member do  patch :move end  end
  3. controller中,添加move方法,⚠️参数的传递,验证+白名单。

重点:

  methods: {
    listMoved: function(event) {
      console.log(event)
      // 改变位置发生改变的list的position属性。
      var data = new FormData
      data.append("list[position]", event.newIndex + 1)

      Rails.ajax({
        // url定位到这个被拖拉的元素并执行move方法
        url: `/lists/${this.lists[event.newIndex].id}/move`,
        type: 'PATCH',
        data: data,
        dataType: 'json',
      })
    },

 controller#move

  def move
    @list = List.find(params[:id])
    # acts_as_list中的方法: 改变Positon,并Reorder it.
    # gem 自动对换位的两个list的position字段的值进行交换。
    @list.insert_at(list_params[:position].to_i)
    render action: :index
  end

 


 

 

视频4

handle drag and drop of cards in their own column and also between columns 

 

<draggable v-model='list.cards'  :options="{group: 'cards'}"  class="draggArea" @change="cardMoved">

分析:

1. v-model='list.cards',绑定prop value。

2.  class=''draggArea"

3. :options="{group: 'cards'}" 为这个<draggable>添加options prop,初始化一个Sortable Object。

   有了这个,card才能跨list移动。否则只能在自己的list内部移动。

4. @change=“cardMoved”

draggable组件的change事件有3个特性(added, removed, moved)对应两个行为:

  • 一个元素被添加其他list:  (添加到list prop的array),并从自己的list中删除(从array中移除)
  • 一个元素在自己的list内移动:在array中移动。
cardMoved方法的设计思路

由用户行为所直接产生的数据(added)开始,
这种行为导致的结果(增加/删除数据)存入服务器中,永久保存。
 1. list内部移动,只有moved: {..}
 2. 跨lists移动, 有added和removed。
3.
用户移动card的行为产生了added/moved特性,由此得到被移动的card的id
4. 由card的id,计算出移动后的card所在的list的index: list_index
5. 新增 var data = new FormData, 并附加上要传给服务器的数据信息。
6. 发送请求PATCH, 数据是新增card的属性信息,本例包括postion, list_id
  存入服务器的list_id的值: this.lists[list_index].id
  存入服务器position的值: event.added.newIndex + 1
7. 发送请求的url,和之前listMoved方法中的类似。
   后续的动作在包括router.rb中添加路径move
   Cards#move方法的设计。
methods: {
    cardMoved: function(event) {
    const evt = event.added || event.moved if (evt == undefined) { return }
    const list_index = this.lists.findIndex((list) => { return list.cards.find((card) => { return card.id === evt.element.id }) })

   var data = new FormData
    data.append("card[list_id]", this.lists[list_index].id)
    data.append("card[position]", evt.newIndex + 1)

    Rails.ajax({
    // 使用了模版字符串``,需要编译支持
     url: `/cards/${evt.element.id}/move`,
     type: "PATCH",
     data: data,
     dataType: "json",
    })
  }

分析:

 

理解list_index是如何得到的✅

 

this.lists.findIndex()

把每个list都传入测试函数(lsit)=> {}进行测试。找到符号测试条件的第一个list,并返回这个list的index。

 

对传入的list进行测试,这是测试条件只要返回的不是undefinded,false就通过测试。

return  list.cards.find((card) => {
   return card.id === event.added.element.id
})

传入的list的cards逐一进行测试,找到满足测试条件card.id === event.added.element.id的card对象,

如果通过测试,返回card对象。如果没有通过测试返回undefinded

 

即传入的list内如果有一个card对象通过再测试,即返回了card对象,则该list的测试通过(找到测试函数返回值是真实值true的值)。返回这个list的index。



  

Javascritp中Array的方法: ( 博客 )

findIndex()方法返回数组中满足提供的测试函数的第一个元素的索引。否则返回-1。

find() 方法返回数组中满足提供的测试函数的第一个元素的值。否则返回 undefined。

别和Rails的find方法混淆了:  person.pets.find(id),关联对象的find方法,参数是id.

 

找错误❌???

 

答案:

控制台提示 list is not defined。

看at app.vue:52已给出错误的地点。 list是一个参数。不存在,证明没有传入list.

(lsit) => { return list.cards}

哈哈,找到了!! 因为箭头表达式的funciton(传入参数)的字母写❌了。

 


 

 

小节:

完整的一个单文件组件。

功能:

  1. 新增一个card。
  2. 拖拉一个list并放置到不同位置。
  3. 或者拖拉一个card进行上下的放置或跨lists的放置。 

特点:

  1. 使用了vuedraggable 组件插件。
  2. 使用gem 'acts_as_list', 数据表增加一个position字段。当一条记录的position变化时,其他记录的position自动改变值。

语法难点:

对Javascript的语法使用不熟悉。比如

Array.prototype.findIndex()方法,find()方法。

DOM元素的dataset方法,获得对应元素的data-*的值,返回DOMstring字符串。

 

转载于:https://www.cnblogs.com/chentianwei/p/9651523.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值