vue学习前传(二)

vue

之前的博客里面,我们讲了vue的数据绑定以及它的用法,而由于之前一直用react开发,难免会进行相互比较,那么这一篇就以与react联系的角度来看看vue的一些特性。
ps:之前的数据绑定,因为当时公司的版本是旧的,为了继续在前fe的基础上继续写,不得已用的是0.12的版本,今天这篇的版本是1.0:)

组件化

props:

查看vue component教程,总结来说,它是react props的扩展版本。
(1)相同的地方在于:props也是默认单向数据流,从父组件传递属性到子组件。
(2)之所以说扩展,体现在两个方面:

  • 扩展一:props in vue == [伪]props in react;
  • 扩展二:props in vue 可单向,可双向绑定数据。

让我们看第一个扩展。

vue的props提供了两种使用方法,静态的+动态绑定。
用react的方式来理解的话:

  • props == 子组件默认的不可变属性。
  • 绑定的props== props in react。
    默认情况下,props只负责传递父组件传给它的属性,且当组件加载后只传递一次,我们可以看到,下面的静态绑定demo中,虽然跟父model同名,但是只解析为字符串,只有变成动态绑定的props,才会解析为从父元素传递下来的变量。每次父组件的相关数据进行变化时,子组件便会随之更改,类似于react中的props.

See the Pen vue组件化demo by lu (@luchen) on CodePen.

1
2
3
4
5
6
7
8
9
//html
<div class="childWrapper">
<input v-model="dynamicMsg">
<br><span>静态绑定:</span>
<child parent-msg="dynamicMsg"></child>
<br><span>动态绑定到父元素:</span>
<child :parent-msg="dynamicMsg"></child>
</div>
1
2
3
4
5
6
7
8
9
10
11
//javascript
Vue.component('child', {
props: ['parentMsg'],
template: '<span>{{ parentMsg }}</span>'
})
var parent = new Vue({
el:".childWrapper",
data:{
dynamicMsg:"hello"
}
})

注意点:

  1. js中的camel写法对应于html中的kebab-case
  2. 如果 prop 是一个对象或数组,是按引用传递。在子组件内修改它会影响父组件的状态,不管是使用哪种绑定类型。就变成了双向绑定了
  3. 如果props是数组,则需要按照动态绑定来写,使得看成变量、表达式,否则会以字符串传递。
    ===更新2017/1/4
  4. 父组件传进来的props作为子组件data的初始值存在的话,如果它变动,内部data是不能响应的,需要设置watch(props),保持data始终在props的基础上变动

再看看第二个扩展
react的props是单向数据流,而vue中还可以实现双向的绑定。
但是最好还是不要这么做,因为父组件有很多子组件,每个都进行双向绑定的话,会有各种冲突问题,而且光看父组件的信息,很难理解父组件的状态

1
<child :msg.sync="parentMsg"></child>

通常是用v-bind来绑定数据,实现js中传值使得数据渲染,在交互频繁的表单上,可以用v-model进行双向绑定。

计算属性

也有双向绑定的含义,watch+反向set

双向props示例

1
2
//child
<modal :category="category" title="禁发" :order="order" :show.sync="showModal"></modal>

parent会对showModal这个变量进行变动。

1
2
3
4
5
//parent button点击响应事件
showDetail(){
console.log(" ==== ", this.showModal);
this.showModal = true;
},

在modal内部

1
2
3
4
5
6
7
<div class="modal" v-show="show"> //here
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true" @click="closeModal">&times;</button>
<h4 class="modal-title">{{category}}</h4>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
export default {
name:"PopModal",
props:["category","order","show"], //表明从父元素传递下来
data () {
return{
}
}
method(){
closeModal(){
this.show = false;
},
}

需要注意的是,如果modal绑定的时候是单向的,即 :show = “showModal”,那么子组件内部使得show = false的时候,父组件的showModal还是保持true的状态。那么会导致父的状态是显示,子状态是不显示,那么点击 showPop按钮的时候是无法显示的。应该改为双向上。

1
2
//update
<modal :category="category" title="禁发" :order="order" :show.sync="showModal"></modal>

开发杂项

  1. scope 限制css
    A组件,B组件都引入到组件C中,但是A,B都有同样的样式.class name,那么会冲突,因此需要用scope 去进行限制,而且需要注意的是在style里面进行 import,scope是不起作用的。只能inline css

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <style lang="scss" scoped>
    .modal{
    display: block;
    display: flex;
    align-items:center;
    justify-content:center;
    background-color: rgba(11, 11, 11, 0.6);
    .action{
    cursor: pointer;
    }
    }
    .modal-dialog{
    max-width: 30%;
    }
    </style>
  2. vue-router 注意事项

1
2
3
4
<ul class="nav nav-tabs">
<li class=""><a v-link=" '/event/list' " >信息列表</a></li>
<li><a v-link=" '/event/create' " >创建事件</a></li>
</ul>

这边的v-link 跟v-on一样,里面的默认是一个变量,如果想传递字符串进去,需要另加单引号

同理,@click,看这个例子

1
2
3
// toggleActive()里面的如果直接是A,会认为是一个变量,无法得到,需要变成字符串
<li :class="['tab-item',isA?'tab-active':''] " @click="toggleAcitive('A')"><a v-link=" '/event/list' " >信息列表</a></li>
<li :class="['tab-item',!isA?'tab-active':''] " @click="toggleAcitive('B')"><a v-link=" '/event/create' ">创建事件</a></li>
  1. class 动态绑定

    1
    <li class="pageList[0]===1?'disabled':''">

    这样是无法识别的,里面不是三元符,而是就是 一个字符串,需要加bind绑定才会变成三元表达式

  2. input checkbox绑定到一个数组的时候,需要指定他们的value,否则相当于一个,会同时选中或不选中,指定后才会各自控制。

  3. ajax ui体验优化

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    handleEventEdited(data){
    //直接更新
    var temp = Object.assign({},this.eventList);
    this.eventList = this.eventList.map(event=>{
    if(event.name==data.name)
    return Object.assign({},event,{name:data.newName});
    else return event;
    });
    //发送请求
    this.$http.post(server_path+"/event",data).then((response)=>{
    console.log("事件修改成功");
    },(err)=>{
    //修改失败后回退
    this.eventList = temp;
    console.log("事件修改失败");
    });
    },
  4. 生命周期

楼主最近的开发过程中遇到这么一个问题,单页应用,最外层组件为app.vue。内层靠路由嵌套了几个子组件。子组件页面一加载就需要去发请求获取数据,而请求的param里面依赖父组件获得的数据。

在no组件,no单页的情况下,这种可以用一个页面加载同步请求去搞定。但是现在不允许这样。还牵扯到该在哪个合适的生命周期里去发送请求的问题。

困惑点1:
之前写react的时候,官方建议在componentDidMount里面进行fetch,但是我比较疑惑的是为什么不在componentWillMount或者render里面操作。因为1,数据取得后就一直存在着,mount以后肯定可以显示。2,难道是因为willMount和render是在dom渲染,可能阻塞ui线程的问题。但是ajax是另开一个线程啊,应该是不影响的啊。

科普一下vue的生命周期,楼主大概打印了一下mount之前的执行顺序。

父子组件生命周期

结合官网的生命周期列表,我们可以看到,都会经历如下的过程:

beforeCreated-> 生成data,computed 这些数据,初始化事件
->created,实例对象被创建
-> 在从created到beforeMount过程中编译模板(template)
-> 编译完成后将template插入el或者父html中,这就完成了mounted。

而对于父组件,因为嵌套了子组件,它的mount需要等到子组件都处理完,生成el并插入document后才算完成。也就解释了上面打印的内容。

现在的规划大概是这样的,在父组件created的时候去fetch数据。然后在子组件中用v-if=’isParentDataGot’ 来确定装载与否。因为上面我们说了,子组件先创建实例,去计算这些data,既然父组件数据还未获取。那么本组件v-if === false。不显示
但是子组件的生命周期还在进行。只是当父组件获取到后update,把数据附上去,
然后在mounted里面去发送自己的请求。

困惑点2:
楼主想知道是否可以在beforeMount里面return false来控制是否装载。
困惑点3:
一般是在mounted发送请求,那么vue现在的生命周期中,在created,beforeMount这些里面发送会有什么影响。


知识回顾

  1. mouseenter mouseover区别
    mouseenter只在刚进入某个元素时触发,不会冒泡
    而mouseover在进入,以及在该元素上移动时都会触发

  2. git远程合并
    楼主是项目owner的话,接受远程pull request后merge到dev分支。
    本地

    1
    2
    3
    4
    5
    git fetch bit-origin dev:new-branch
    git checkout new-branch 查看最新代码。如果可以的话
    git checkout dev
    git merge new-branch。使得dev为最终代码
    git remove new-branch