jrg-project-5 icon indicating copy to clipboard operation
jrg-project-5 copied to clipboard

数据!数据!

Open FrankFang opened this issue 8 years ago • 36 comments

接下来我们来做预览功能。

首先想一个问题:

ResumePreview 的数据(data)从哪来?

当然是从 ResumeEditor 来,对吧。

怎么拿到数据呢?

方案一:

那么最傻的办法就是在 ResumePreview 里面去读 ResumeEditor 的 data。

这种办法可以是可以,但是有一个「耦合性」太高的问题。

假设 ResumePreview 代码是这样的:

export default {
  name: 'ResumePreview',
  data: function(){
     return readResumeFromResumeEditor() // 这个函数的具体实现我们不管
  }
}

你会发现,ResumePreview 严重依赖 ResumeEditor,换句话说,ResumePreview 必须和 ResumeEditor 在一起,ResumePreview 不能从其他的地方读入 resume 数据。

这样的代码就很不优雅。

方案二:

讲数据抽离出来。我们能不能把 resume 的数据独立出来,专门供 ResumeEditor、ResumePreview 甚至其他组件来使用呢?可以。大概思路是这样:

// ResumeEditor
import globalData from 'globalData'
export default {
  name: 'ResumeEditor',
  data: function(){
    return {
      selected: 'profile',
      resume: globalData.getResume()
    }
  }
}

// ResumePreview
import globalData from 'globalData'
export default {
  name: 'ResumePreview',
  data: function(){
    return {
      resume: globalData.getResume()
    }
  }
}

这样一来,ResumeEditor 和 ResumePreview 互不干涉,只是数据来自同一个地方。

ResumeEditor 改了 resume 之后,由于 ResumePreview 用的是同一个 resume,所以立马就知道 resume 变化了(Vue.js 可以监听任意一个对象的变化)。

Tips:可以通过添加中间层来降低耦合

Vuex

全局数据源

基于方案二,我们再进一步想,为什么不把所有的数据都交给 globalData 来控制呢?

上文中 ResumeEditor 的 selected 属性没有交给 globalData 管理,万一另一个组件要用这个 selected 呢?所以我们还不如把所有的数据都交给 globalData 来控制。

这样,globalData 就叫做全局数据源,管理所有的数据。

双向绑定 V.S. 单向绑定

前面我们学过,可以用 Vue.js 添加双向绑定:

<input v-model="xxx">

实际上,双向绑定不是魔法,上面的代码基本等价于

<input :value="xxx" @input="xxx = $event.target.value">

也就是说:

双向绑定 = 单向绑定 + UI 事件监听

通过这个 JSBin 你应该可以理解这一点。

那么 Vuex 为什么要推荐单向绑定呢?

为了「控制欲」。

双向绑定是很方便,因为 data 和页面内容是自动同步的。

但是成也萧何败萧何。正是因为这个「自动同步」,所以有些人不喜欢双向绑定。「自动同步」意味着你不知道 data 什么时候就变了(when),也不知道是谁变的(who),变成了什么也不通知你(what)。

当然你可以加一个 watch 来监听 data 的变化。但这就显得很复杂了。

单向绑定牺牲一部分的便捷性,换来更大的「控制力」。

单向绑定大概的思路就是:

  1. 所有的数据只有一份
  2. 一旦数据变化,就去更新页面(data -> 页面单向绑定)
  3. 如果用户在页面上做了变动,那么就把变动手动收集起来(而不是自动的),合并到先有的数据中

你会发现单向绑定的思路其实也有双向绑定的意味,只不过重点在于「不是自动的」。

单向绑定还有其他优点,请看这个知乎问答

使用 Vuex

Vuex 就是单向数据绑定的践行者之一了。

你需要先过一遍 Vuex 的文档,来了解 Vuex。你需要:

  1. copy - run - modify 文档中的例子
  2. 了解五个核心概念:Store、Getters、Mutations、Actions 和 Modules

如果不通读 Vuex 文档,并运行其中的例子,之后的代码你肯定无法理解!

通读文档非常重要!我讲得再多也没文档讲得清楚。

引入 Vuex

首先我们要把 Vuex 文档里最简单的例子运行在我们的页面里:

commit: npm install vuex --save commit: 按照 http://vuex.vuejs.org/zh-cn/structure.html 的目录结构创建文件 commit: 按照 http://vuex.vuejs.org/zh-cn/getting-started.html 创建一个最简单的 store commit: 将文档中最简单的例子在我的页面里运行成功

改写 data

commit: 将原有数据移动到 store 里

我们把 selected 和 resume 移到 store 里会发现 tab 无法切换了。

这是因为默认 computed 只能用于读数据,如果你还想写数据,就要用到 Vue 的 setter / getter 功能 了。

如果你想知道如何实现 setter 和 getter,就看 MDN 的文档

commot: 使用 setter 让数据可写

commit: 删除测试代码

ResumeEditor 和 ResumePreview 使用同一个 store

你可以看到我们的 store 是放到 <App /> 上的,所以所有组件都可以使用 this.$store 来访问到它。(为什么要以 $ 开头?Vue 习惯如此,所有全局的东西都用 $ 开头,跟 jQuery 无关)

那么我们来试试在 ResumePreview 里访问 resume 数据。

commit: show resume

这个时候你刷新页面,就能在 ResumePreview 里面看到 resume 啦。

  1. 不要一次写太多代码,要小步快跑
  2. 目前页面的样式错乱了,我们需要修复,千万不要等 bug 积累多了再修复

commit: 使用 min-width 代替 width,修复样式 bug

接下来我们让 ResumePreview 变得完整点、好看点:

commit: 显示简介、工作经历和毕业院校 commit: 显示获奖情况和联系方式

好了,我们完成了 ResumePreview 并且引入了 Vuex。

致饥人谷学员

  1. 现在你在页面左边修改 resume,会发现 ResumePreview 不会自动更新,你该怎么办呢?
  2. 实现上面的效果,回复在下面(源码+预览)
  3. 回答代码里的问题(不会就搜):
    1. 多次 import 同一个文件,会怎样?
    2. 为什么要写 white-space: pre-line;

请依次回答上面三个问题。

我的预览的:https://jirengu-inc.github.io/jrg-project-5/step-8-resumer/dist/#/

预告

  1. 下一个任务:实现 Resume 编辑功能
    • 编辑所有内容
    • 保存内容到 localStorage
  2. 下下个任务:
    • 实现用户注册登录(弹框)
    • 实现主题切换
  3. 最终任务:
    • 优化代码

FrankFang avatar Feb 17 '17 11:02 FrankFang

预览 code

  1. 现在你在页面左边修改 resume,会发现 ResumePreview 不会自动更新,你该怎么办呢? 解决方法
  2. 多次 import 同一个文件,会怎样? 貌似是浏览器会根据缓存判断引入文件,不会重复引用
  3. 为什么要写 white-space: pre-line; 因为要保留换行符,并且去掉多余空白符

hungryYang avatar Feb 22 '17 07:02 hungryYang

yjl for v-r-g source demo Q&A: i: 将数据类型为数组的输入框由单向绑定变为双向绑定; ii: Node对引入的模块都会进行缓存(缓存的是编译和执行后的对象),减少二次引入开销; 在Node的加载机制中,缓存的优先级是最高的; 这一点同时适用于不同的模块加载机制,无论ES2015的import还是CommonJS的require; iii: 去除一行文本中的空格,但是保留一行的换行符,作用是防止用户在输入框输入空格而产生对用户不友好显示效果

TerenYeung avatar Feb 22 '17 11:02 TerenYeung

预览 代码

问题1 :

<div class="resumeField" v-for="(value,key) in subitem">
    <label>{{key}}</label>
    <input type="text" v-model="subitem[key]"> //将input设置为双向绑定解决..
</div>

问题2:

第一次引入后应该会有缓存吧,不是很了解....

问题3:

因为不能保证用户会不会按多次空格, 这条属性能够使空白字符压缩并保持换行符

zhangjiuyi avatar Feb 22 '17 12:02 zhangjiuyi

预览 代码

问题1 : 首先直接改动index.js里的数据发现review有变化,说明问题出在editor里的input没有把数据传入store,于是给input双向绑定即可。 问题2: 浏览器会根据缓存判断引入文件,不会重复引用 问题3: 看了同学的答案知道了其作用是防止用户在输入框多次输入空格而产生对用户不友好显示效果

code-zhangrui avatar Feb 23 '17 06:02 code-zhangrui

预览 源码 1.在input上添加v-model绑定一下 2.引用的都是同一个 3.把空白合并,但是保留换行,如果去掉的话,就没有换行了,默认空白全部忽略

raszxcv avatar Feb 23 '17 08:02 raszxcv

预览 代码 2. 我的项目不引入第二个Vue打包出来的js文件会变小。而webpack并没有根据词法解析改变原来文件内容。所以我觉得会打包两次。 3. 作用只是到该行满后换行。并没有提供空白合并和保留回车。因为过来的数据里根本没有多个空格和换行符。 WHJ

wuhanjun avatar Feb 24 '17 04:02 wuhanjun

预览 源码

问题1

  • 把input 的绑定变为双向绑定
  <div class="resumeField" v-for="(value,key) in subitem">
                      <label>{{key}}</label>
                      <input type="text" v-model="subitem[key]">
                  </div>

问题2

  • 多次引入的的那个资源会缓存在浏览器里,HTTP状态304,引入多次无妨
  • 因为要保留换行符,并且去掉多余空白符, 防止用户在输入框里输入多个空白符,导致界面显示不友好 WXY

WangXiaoyugg avatar Feb 24 '17 08:02 WangXiaoyugg

  • 1、 现在你在页面左边修改 resume,会发现 ResumePreview 不会自动更新,你该怎么办呢? 解决方法:在ResumeEditor.vue 文件中第二十行代码 <input type="text" :value="value" >v-model="subitem[key]" 让input双向绑定数据即可:
                 <div class="resumeField" v-for="(value,key) in subitem">
                   <label >{{key}}</label>
                   <input type="text" :value="value" > //此处未双向绑定数据
                 </div>
  • 2、在多个文件 import vue,会怎样? 这个不是很清楚,老师可以给我们讲讲哦~

  • 3、为什么要写 white-space: pre-line; white-space: pre-line的作用是合并空白符序列,但是保留换行符、<br>及填充line盒子时也会换行。 我们这里不加的话, a、 1.既定产品需求; 2.修复 bug 就不会换行了。 b、在input填写时,如果填写多个空格也会在全部显示出来,导致页面显示很难看。

预览

源码

LC

have-not-BUG avatar Feb 24 '17 13:02 have-not-BUG

预览

代码

  • 在resumEdtor组件中添加v-model指令在表单控件上使用双向绑定,<input type="text" :value="value" v-model="subitem[key]">,
  • 添加white-space:pre-line后,当输入框中输入多个空白符时预览中会合并空白,允许自动换行的同时并且会保留换行符;
  • 关于多次import同一个文件会怎样,查了资料,说会在打包的时候使文件变大,webpackp配置文件每当遇到import或者require()依赖项时,就会解析并且打包,如果多次import同一个文件,会使打包文件变大;

ZW

muxi7 avatar Feb 25 '17 09:02 muxi7

预览 1.对编辑组件内的数组类型的数据的input控件改成model指令绑定 v-model="subitem[key]" 2.在同一个js文件中引入两个会报错(Duplicate declaration),在store的index.js中不引入vue会报错,你们说的缓存是什么情况,难道只有我报错嘛。。。 3.主要是为了文字换行,white-space: pre-line和white-space: pre-wrap都会换行,查了下区别pre-line是对空白符合并,而pre-wrap不会对空白符合并;

Hsyneve avatar Feb 25 '17 10:02 Hsyneve

doge~


预览

源码

现在你在页面左边修改 resume,会发现 ResumePreview 不会自动更新,你该怎么办呢? 1、根据VUEX推荐的是单向绑定,所以我们也要在input框中绑入数据派发的事件

多次 import 同一个文件,会怎样? 2、在main.js以及index.js里面,都会deplicate报错,我还尝试注掉了base.config里面的alies,结论依旧 image

为什么要写 white-space: pre-line; 3、把换行文字往左边对顶

starlikerain avatar Feb 25 '17 10:02 starlikerain

预览 代码 1.我没完全跟着教程来,并没有出现问题。。。 2.正确的应该是优先寻找缓存文件,不会二次引入。至于楼上所说的完全是因为没有该变量所引起的; 3.修正多个空格为一个空格,且正确显示换行符。

lzm320856 avatar Feb 25 '17 15:02 lzm320856

预览 代码 1.对input使用双向绑定就可以了; 2.会报错,提示重复声明; 3.当 white-space 属性设置为 pre-line 时,浏览器会保留换行符,并允许自动换行,但是会合并空白符

wlf1112 avatar Feb 26 '17 08:02 wlf1112

预览 代码

  1. 给input使用双向绑定
  2. 由于重复引入了相同的文件,会报错
  3. 合并空白,但是保留换行符

LisaLi85 avatar Feb 26 '17 14:02 LisaLi85

  1. 很奇怪我没有遇到这个问题.
  2. 源码, 预览
  3. webpack不会重复打包多次import的重复模块,webpack 在处理依赖关系的时候,会给模块分配个 id,同一模块只会写入打包文件一次。
  4. white-space:per-line的作用是合并空白符,但是保留换行符及自动换行。所以这样可以防止用户输入过多空白符导致我们生成的简历太奇怪。

SHZ

ReedSun avatar Feb 27 '17 12:02 ReedSun

预览 代码

问题1:

<div class="resumeField" v-for="(value,key) in subitem">
    <label>{{key}}</label>
    <input type="text" v-model="subitem[key]">
</div>

问题2: 猜测重复引用应该是无效的,浏览器会优先判断是否有缓存

问题 3: white-space:per-line合并空白符,但会正确显示换行符

SJ

Rice-F avatar Feb 27 '17 14:02 Rice-F

源码 演示

问题一

1.在非严格模式下: 将写为双向绑定即可 <input type="text" :value="value" @input="resume[item.field][key] = $event.target.value"> 2.在严格模式下:

const store = new Vuex.Store({
// ...
strict: true
})

用之前的方法会报错,那么用『Vuex 的思维』去解决这个问题的方法是:给 中绑定 value,然后侦听 input 或者 change 事件,在事件回调中调用 action。代码还未实现,有些不熟练😂

问题二:多次 import 同一个文件,会怎样?

最近在写react的时候,所有子组件中都要写 import React from 'react',直觉告诉我webpack不傻,引用多次肯定不会多次打包,但我在网上没有搜到让我信服的理由。于是自己做了个实验 目录结构:

//demo.js--相当于vue
export default {
  test(argu) {
    console.log(argu)
  }
}

//test1.js --相当于某个组件

import demo from './demo'

export default {
  test1() {
    demo.test(1)
  }
}

//test2.js --相当于另一个组件
import demo from './demo'

export default {
  test1() {
    demo.test(2)
  }
}

//add.js --入口文件

import Test1 from './test1'
import Test2 from './test2'

Test1.test1()
Test2.test2()

我在 test1.js, test2.js中都引入demo.js,并且exoprt 出依赖demo.js的方法,然后再在app.js 中引入 test1.js, test2.js webpack打包后打开bundle.js,找到demo部分 bundle.js中demo部分 发现demo只被引入了一次。 所以得出结论,多次import同一个文件,webpack并不会多次打包,只会在打包后的文件中会多次引用打包文件后的对象。

问题三:为什么要写 white-space: pre-line

合并空白符序列,但是保留换行符。

Zegendary avatar Feb 28 '17 04:02 Zegendary

问题一

1.在非严格模式下: 将写为双向绑定即可 <input type="text" :value="value" @input="resume[item.field][key] = $event.target.value"> 2.在严格模式下:

const store = new Vuex.Store({
// ...
strict: true
})

用之前的方法会报错,为什么会报错? 因为在严格模式下,Vuex的状态不允许在mutation 处理器以外的地方被修改!

那么用『Vuex 的思维』去解决这个问题的方法是: 1.给 中绑定事件,并传递相应的参数,在事件中将相应参数commitVuex.store下的Mutation中 2.在./store/index.js中注册一个响应input事件的Mutation处理器,将得到的payload更新到state.resume

commit : 严格模式下实现ResumePreview自动更新

Zegendary avatar Feb 28 '17 09:02 Zegendary

预览 代码 1.
可以使用双向绑定 也可以基于事件 代码 看了同学的答案没有考虑过严格模式下的问题 2. 查到居然就是楼上的答案:

webpack不会重复打包多次import的重复模块,webpack 在处理依赖关系的时候,会给模块分配个 id,同一模块只会写入打包文件一次。

white-space: pre-line:用来设置如何处理元素中的空白。防止有人思考过程中会敲空格把

baixiaoji avatar Mar 08 '17 14:03 baixiaoji

预览 代码 1.对input添加双向绑定 2.不会重复打包,同一模块只会写入打包文件一次 3.合并连续空格,优化显示效果

Anticlimax avatar Mar 17 '17 07:03 Anticlimax

预览 代码 1.双向绑定数据 2.在同一文件重复引用,报错;不同文件重复引用,不报错,但是不会重复打包 3.合并空格,保留换行符

JeromeYangtao avatar May 09 '17 07:05 JeromeYangtao

1.不会自动更新,是因为input的更新的值没有绑定到state上,双向绑定即可。 2.本项目是在两个文件内import vue,从打包后的源码来看, webpack类似对引入的构造函数进行编号,例如:webpack_require(0)、webpack_require(1)、···,只是多次调用这些打包后对应的函数,并没有重复打包。 在同一文件多次引入同一个文件,会报错“Duplicate declaration “filename””。 3.连续的空白符会被合并。保留换行符。input输入一大段文字,显示在对应的p标签。p标签默认样式是不换行的,但是如果用户强制换行,只会产生空格,故而修改p标签默认样式,在用户需要换行时换行。 预览

superDCF avatar May 11 '17 11:05 superDCF

  • 在editer中双向绑定input即可
    <div class="resumeField" v-for="(value,key) in subitem">
             <label>{{key}}</label>
             <input type="text" v-model="subitem[key]">
    </div>
    

- import 的意思本身就有,不会重复引入,这一点跟include不同

#ifinclude xxx #endif


-  white-space: pre-line是对行首空格的处理,表示无效行首空格,对应的还有 pre-wrap(保留空格)

13hoop avatar Jun 02 '17 12:06 13hoop

问题一: 在页面左边修改 resume,会发现 ResumePreview 不会自动更新,你该怎么办呢 修改input为双向绑定: 原来的:<input type="text" :value="value" > 修改后的:<input type="text" :value="value" @input="subitem[key] = $event.target.value">

问题二:多次 import 同一个文件会怎么样? webpack不会重复打包多次import的重复模块,webpack 在处理依赖关系的时候,会给模块分配个 id,同一模块只会写入打包文件一次。

问题三white-space: pre-line的作用? 多个空格会合并,换行会保留,帮助用户去掉输入过程中连续输入的空格

效果预览 demo

success-cg avatar Jun 07 '17 08:06 success-cg

预览 代码

问题1 <div class="resumeField" v-for="(value,key) in subitem"> <label>{{key}}</label> <input type="text" v-model="subitem[key]"> //将input设置为双向绑定 </div> 或(v-model就是下面的语法糖,双向绑定 = 单向绑定 + UI 事件监听) <div class="resumeField" v-for="(value,key) in subitem"> <label>{{key}}</label> <input type="text" :value="value" @input="subitem[key] = $event.target.value"> //将input设置为双向绑定 </div>

问题2: 多次import同一个文件,会提示‘Duplicate declaration “filename’的错误

问题3: 会合并连续的空格,换行会保留

Honohonoho avatar Jun 15 '17 13:06 Honohonoho

  1. Q:现在你在页面左边修改 resume,会发现 ResumePreview 不会自动更新,你该怎么办呢? A:在ResumeEditor.vue 18行的 input 添加 v-model指令在表单控件上使用双向绑定,<input type="text" :value="value" v-model="subitem[key]">

  2. 源码 预览

  3. Q:多次 import 同一个文件,会怎样? A:Module build failed: Duplicate declaration "xxxx" Q:为什么要写 white-space: pre-line; A:white-space: pre-line; // 合并空白符序列,但是保留换行符。花括号外面要用 ` 小撇,不能不引号 `{ '学习' }`

boloog avatar Jun 17 '17 04:06 boloog

  1. 现在你在页面左边修改 resume,会发现 ResumePreview 不会自动更新,你该怎么办呢? 在ResumeEditor中的<input type="text" :value="value">中加上双向绑定v-model,改写成<input type="text" :value="value" v-model="subitem[key]">

  2. 源码 预览

  3. Q: 多次 import 同一个文件,会怎样? A: 会报错:Module build failed;webpack不会重复打包,重复的话,只会引入已经打包好的参考 Q: 为什么要写 white-space: pre-line; A: 合并空白符序列,但是保留换行符。

komolei avatar Jun 26 '17 01:06 komolei

现在你在页面左边修改 resume,会发现 ResumePreview 不会自动更新,你该怎么办呢? 在ResumeEditor中的中改为单项绑定并且事件监听

<input type="text" :value="value"  @input="subitem[key] = $event.target.value">
<input type="text" :value="value" @input="resume[item.field][key] = $event.target.value">

预览 源码

Q: 多次 import 同一个文件,会怎样? A: 报错:Module build failed;重复打包的时候,只会引入已经打包好的 Q: 为什么要写 white-space: pre-line; A: 合并连续的空格,保留换行

imgwho avatar Jul 21 '17 05:07 imgwho

问题 1.

将input 变为双向绑定即可解决,如

问题 2.

预览

代码

问题 3.

Q1: webpack不会重复打包多次import的重复模块,webpack 在处理依赖关系的时候,会给模块分配个 id,同一模块只会写入打包文件一次。

Q2: white-space:pre-line;
合并空白符序列,但是保留换行符。

robbchan avatar Jul 22 '17 05:07 robbchan

一、现在你在页面左边修改 resume,会发现 ResumePreview 不会自动更新,你该怎么办呢? 根据:Vuex文档中"表单验证“中的方法:给 input 中绑定 value,然后侦听 input 或者 change 事件,在事件回调中调用 action: commit: 自动更新ResumePreview 二、 源码 预览 三、 多次 import 同一个文件,会怎样? A:不同文件中多次import同一个文件,webpack不会多次打包,只会多次引用打包后的该文件对应的函数 为什么要写 white-space: pre-line; A:连续的空白符会被合并。在遇到换行符或者
元素时会换行;帮助用户去掉输入过程中连续输入的空格

selectyang avatar Jul 22 '17 17:07 selectyang