频:https://gorails.com/episodes/using-vuejs-for-nested-forms-part-1?autoplay=1
在嵌套表格上使用vue.js。
在application.html.erb
上<head>内加上:<%= javascript_pack_tag 'hello_vue' %>
如果有style(css)的话加上:<%= stylesheet_pack_tag 'hello_vue' %>
在hello_vue.js 进行配置:
需要安装vue-turbolinks和vue-resource:
在terminal上输入:
- yarn add 'vue-turbolinks'
- yarn add ''vue-resource''
添加:
import TurbolinksAdapter from 'vue-turbolinks'
import VueResource from 'vue-resource'
Vue.use(VueResource)
Vue.use(TurbolinksAdapter)
HTMLElement.dataset
The dataset property on the HTMLElement interface provides read/write access to all the custom data attributes(data-*) set on the element
返回一个DOMStringMap, 可以读写元素的custom data attributes (data-*)
- string = element.dataset.camelCasedName;
- element.dataset.camelCasedName = string;
- string = element.dataset[camelCasedName];
- element.dataset[camelCasedName] = string;
案例:
视频1 嵌套表格
clone后,进入/teams
需要运行:bin/webpack-dev-server命令,提示没有找到
更新bundle update webpacker,再启动rails s
报告:config/webpacker.yml No such file 提示运行rails webpacker:install
rails webpacker:install安装后
我运行:
- bin/webpack
- bin/webpack-dev-server, 这个窗口必须始终打开。
然后程序就可以正确执行了,?✌️
本节目标
是结合嵌套表格的功能,在新建页面新建team的时候,同时也新建team关联的players。需要用到Vue.js框架。
重点:
- 参数的传递。使用JSON作为格式。用到了dataset方法。
- new Vue()中的data属性,这里是个函数。
备注:
改使用视频3自建的app ,创建了一个分支:在分支上做视频1的练习。
视频提供的代码:mixins:[TurbolinksAdapter]❌报告错误,改成Vue.use(TurbolinksAdapter)✅。
知识点:
1. 数组的mutation methods
- push()在尾部增加一个, pop()去掉尾部的那个
- unshift()在开头增加一个, shift()去掉开头的那个
- splice(index, howMany, item, ..., itemX)
- index用于定位,
- howMany如果是非0正整数则代表移除几个,
- 后面的item是新增给array的。
2. 在input标签内,v-model='team'等同于v-bind:value='team'加上v-click:input="team = $event.target.value"
疑惑:
this的作用。在方法removePlayer中,必须使用this。 this.team.players_attributes.splice(index, 1)
好像也没有问题。
view:
data-*数据是为vue app准备的从database取出并转化为JSON的初始数据。
app/javascript/packs/nestedform.js 这里没有使用单文件组件。
视频2,继续开发嵌套表格:
目标:可以保存或更新team,可以删除关联player。
⚠️:
因为内部有${},必须使用``斜单引号。使用普通的''会报告❌。
this.$http.put(`/teams/${this.team.id}`, {team: this.team})
1.保存新建或者保存更新:(根据条件进行判断)
需要加上验证token,使用vue-resource中的方法:
Vue.http.headers.common['X-CSRF-Token'] = document.querySelector("meta[name='csrf-token']").getAttribute('content')
新建的保存使用vue-resource中的发请求方法:this.$http.post('/teams', {team: this.team})
解释: 这里的team对象是request的数据参数,在server端,team对象中的各个hash数据,会被controller#team_params进行白名单检查。
2.nestedform.js中添加2个方法:用于移除/恢复 要删除的关联player。
_form.html.erb,new/edit中的view![](https://i-blog.csdnimg.cn/blog_migrate/693bdc5d2f52f33475aeab8d62a1944d.png)
视频3,新建一个app:
(昨晚做的)
10155 rails new myapp --webpack=vue
10160 cd myapp
10161 atom .
10163 rails g scaffold team title
10164 rails db:migrate
10165 bundle install #gem 'webpacker', github: 'rails/webpacker'
10170 bin/webpack-dev-server #新开一个窗口运行它。
10171 rails s
bundle exec rails webpacker:install:vue #(如果已经在一个app上建立webpacker了)
重点:
1. 在hello_vue.js中,document.addEventListener,需要改成turbolinks:load。
原因:从teams页面到teams/new页面, hello_vue.js不会加载,因为turbolinks 缓存了第一个版本。需要改成turbolinks:load事件。放弃原先的缓存,从新加载变更的vue app。
2.进入teams 并新建了一个team后,inspect中的vue.js可以使用了✌️!
HTML scoped Attribute
一个布林值,用于<style>。当true时,这个styles只装饰这里的元素的父元素和子元素。
render: h => h(App)
h是Vue里的createElement函数。这个函数的作用就是生成一个 VNode节点,render 函数得到这个 VNode 节点之后,返回给 Vue.js 的 mount 函数,渲染成真实 DOM 节点,并挂载到根节点上。
render: function (createElement) {
return createElement(App); }
缩写为:
render (h){
return h(App); }
最后可以写成箭头函数。
Vue.js1.0版本是比较原始的写法,这是2.0版本的写法。
视频4
Vue.js和Turbolinks一起使用是如何做到的(原理解析)?
已经有现成的插件可以使用了。
执行命令安装插件:yarn add 'vue-turbolinks'
然后import TurbolinksAdapter from 'vue-turbolinks',
并使用插件: Vue.use(TurbolinksAdapter)
原理:
加上钩子beforeMount方法 ,在挂载开始之前被调用:相关的 render
函数首次被调用。
git代码:https://github.com/chentianwei411/Vuejs-and-turbolinks/blob/master/app/javascript/packs/hello_vue.js
知识点:
Element.outerHTML:
元素DOM接口的outerHTML
属性获取描述元素(包括其后代)的序列化HTML片段。
包括元素本身,得到或替换(使用string格式)。(不在页面内显示,仍存在内存中)。
对应的innerHTML:
只获得元素内部的一切,或者替换。不包括元素本身。
更新知识点:
单文件组件 xxx.vue
在很多 Vue 项目中,我们使用 Vue.component
来定义全局组件,紧接着用 new Vue({ el: '#container '})
在每个页面内指定一个容器元素。
这种方式在很多中小规模的项目中运作的很好,在这些项目里 JavaScript 只被用来加强特定的视图。
但当在更复杂的项目中,或者你的前端完全由 JavaScript 驱动的时候,下面这些缺点将变得非常明显:
- 不支持css。
- 全局定义强制要求每个componment的名字唯一。
- 没有构建步骤,不能使用预处理器。
single-file components解决了上面所有问题。
如何看待 关注分离点?
- 关注分离点不等于 文件类型分离。
- 现代UI开发,比传统的分离三个大层次并将其相互交织起来更合理。
- 在一个组件内,模版template,逻辑script,样式style是内部耦合的,把它们搭配在一起让组件更加内聚,并容易维护。
(⚠️ 本章教程上有后续学习路径和资源)
视频5
Vue.js Components in Rails Views
视频的步骤:
- rails webpacker:install
- rails webpacker:install vue
- _head.html.erb这是applcaiton.html.erb中的<head>中的代码。
- 增加了:<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
- data-turbolinks-track="reload": (点击链接) :
- 用途:从一个page到另一page,追踪<head>tag中的URLs中的asset elements,如果它们改变了会自动发出完全的reload。
- 目的:确保用户总是使用最新版本的程序的脚本scripts和styles
- 解释:这样所有的views都会被wrapped 进view application这个单文件组件
- 解释:可以自动的把更新的数据传递到vue实例app中。比原生js少了很多代码,节省了时间。
- 另一个酷的地方是,可以通过循环each,加载多遍组件
- 特色的内置的组件特性:inline-template
- 忽略单文件组件中的的template,然后在当前组件实例上写自己需要的html 代码。
- 忽略单文件组件中的的template,然后在当前组件实例上写自己需要的html 代码。
视频6 slots
如何利用插槽,显示下拉框/菜单,组件可以用于任何位置的htmltag,非常方便。
Webpacker
webpacker可以预处理JS, 并绑定webpacker 4来管理Rails中的类似程序的JS。
它和asset pipeline共存,因为它的主要目的是app-like JS,不是Css和image
给一个rails app增加webpacker给gemfile:
- gem 'webpacker', github: 'rails/webpacker' #会获得稳定的版本。
- 或者使用yarn add https://github.com/rails/webpacker.git
- bundle 后,
- bundle exec rails webpacker:install
usage
安装后就可以写JS apps了。
连接JS pack in Rails view使用: javascript_pack_tag 帮助方法。
<%= javascript_pack_tag 'xxx' %>
⚠️ : xxx.js需要放在pack文件夹内。
假设新增文件在app/javascript/gorails/index.js
编辑index.js, 加一行代码export default {gorails: true}
在application.js中,使用import Gogogo from 'gorails/index.js'可以引入文件,并console.log(Gogogo)
在浏览器页面控制台, 输出一个对象{gorails: true}。
import用于导入由另一个模块导出的绑定。![](https://i-blog.csdnimg.cn/blog_migrate/963ebbc4babb75d9e781308574dcbebe.png)
语法:
import defaultExport from "module-name"; import * as name from "module-name"; import { export } from "module-name"; import { export as alias } from "module-name"; import { export1 , export2 } from "module-name";
module-name:
要导入的模块,这通常是包括该模块的.js文件的相对路径,或绝对路径。rails可以包括.js扩展名。
Development
Webpacker ships with two binstubs:
-
bin/webpack-dev-server
-
bin/webpack
2个简单的wrappers:webpack.js和webpack-dev-server.js,确保正确的配置文件和环境变量基于你的环境来加载。
在开发模式下,Webpacker 编译基于命令的,而不是默认预定义。
当你在任何pack assets上使用Webpacker 帮助方法, Webpacker编译。
如果你响应使用live code 再加载, 或者你有足够多的命令式编译的JS导致太慢,
需要运行:bin/webpack-dev-server
这个proecess会查看在app/javascript/packs/*.js文件中的变化,并自动reload浏览器来匹配变化。
一旦你开始这个开发server, Webpacker将自动开始代理所有webpack asset 请求到这个server,
当你停止这个server,它会转回命令式编译。
⚠️: Rails 5.2+, 需要在content_security_policy.rb中加一行代码,安装vue的时候会提示,具体见git。
安装javascript框架:
rails webpacker:install:vue
插件: vue-resource(8000+✨)
已经被Vue官方放弃
替代品是https://github.com/axios/axios (48000✨)
概述:
一个轻量级的关联HTTP 请求响应的插件。
- 替代了$ajax功能的插件。
- 另外还提供了inteceptor功能,可以在请求前/后附加一些行为:比如在ajax请求时,显示loading界面。
参考:http://www.cnblogs.com/keepfool/p/5657065.html
安装 yarn add vue-resource
提供服务为制造web requests 和 处理responses
案例:发送请求。
文档:
- Configuration
- HTTP Requests/Response
- Creating Resources 另外一种访问HTTP的方法(基于上一种的方式实现的)
- Code Recipes 代码窍门/食谱。 普通的Forms , request案例用法。
- API Reference
HTTP Requests/Response
- Methods: 7个方法
- Config: 对常用参数的解释,其中body参数是请求body中的数据,可以是Object, string, FormData.
- Response: 一个响应对象的特性6个和方法3个
http server全局的用 Vue.http, 而在Vue实例中用 this.$http
方法:在全局对象或Vue实例上可以使用,可以被所有请求类型使用
get(url, [config])
head(url, [config])
delete(url, [config])
jsonp(url, [config])(被放弃)
post(url, [body], [config])
put(url, [body], [config])
patch(url, [body], [config])
例子:
this.$http.post('/someUrl', [body], [config]).then(successCallback, errorCallback);
Vue.http.get('/someUrl', [config]).then(successCallback, errorCallback);
- errorCallback是在响应失败时调用.
- 替代errorCallback: 可以在then后面附加.catch(function() {...}). catch是在整个请求到响应过程中,只要程序出错了就会被调用。
Resource
另外一种访问HTTP--resource服务,可以结合URI template使用。
Vue.resource
or in a Vue instance this.$resource
.
Methods
resource(url, [params], [actions], [options])
使用inteceptor
拦截器可以在请求发送前和发送请求后做一些处理。
Vue.http.interceptors.push((request, next) => {
// ...
// 请求发送前的处理逻辑
// ...
next((response) => {
// ...
// 请求发送后的处理逻辑
// ...
// 根据请求的状态,response参数会返回给successCallback或errorCallback
return response
})
})
实例1:
比如,网络慢,画面又没给反馈,用户不知道他的操作是否成功,也不知道是否该继续等待。
通过inteceptor,可以为所有请求处理添加一个loading。