这些都是我消化理解之后的东西,我不能保证我的理解都是对的,仅供参考。
MVVM模式
MVVM最早由微软提出来,它借鉴了桌面应用程序的MVC思想,在前端页面中,把Model用纯JavaScript对象表示,View负责显示,两者做到了最大限度的分离。
把Model和View关联起来的就是ViewModel。ViewModel负责把Model的数据同步到View显示出来,还负责把View的修改同步回Model。
创建可复用组件需要注意
- 用name属性指定组件的名字,建议使用帕斯卡命名法
- 用props属性指定需要父组件传过来的属性(用在组件的标签上)vue官网 props
- 所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。父组件传递到子组件的prop的改变会反映到子组件中,但是子组件prop的改变不会反映到父组件中。需要用$emit()触发父组件的某个事件,修改父组件的值。
.sync修饰符
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。所以我们用$emit()触发父组件的属性更新事件来通知父组件修改指定属性。
比如:父组件将自己的 visible
属性传给子组件的 shown
属性( :shown="visible"
),子组件想修改 shown
的值,就通过 $emit("update:shown",value)
通知父组件(触发父组件的 update:shown
事件),父组件通过 @update:shown
的回调函数将 visible
的值修改为 value
( @update:shown="value => this.visible = value"
)。综上,父组件包含 :shown="visible" @update:shown="value => this.visible = value"
,这就可以简写为 :shown.sync="visible"
。但是,这种带 .sync
修饰符的属性,不能用表达式,只能直接获取属性,比如: :shown.sync="!visible"
无效,:shown.sync="ui.visible"
是可以的。
slot 和 scoped-slot (已经废弃,用v-slot代替,elementUI依然使用着)
- Slot 意思是插槽,就是组件xxx可以有一个带slot属性的子组件作为插件,elementUI会自动根据slot的值使插件发挥相应的作用。
- Scoped Slot 意思是带自定义域的slot,除了声明slot属性之外,还需要通过slot-scope属性,指定一个变量,在插件中就可以使用该变量暴露的属性。
<!-- 定义一个插槽,name是该插槽的名字,不写默认为default -->
<slot name="xxx" ></slot>
<!-- 使用插槽,通过给标签定义slot属性,声明该标签替换哪个slot,不写默认是default插槽 -->
<div slot="xxx"></div>
<!-- 定义一个带域插槽(域可以理解为一个对象),通过在标签上定义属性,声明域中的变量(对象中的属性),当然可以通过:value动态绑定value变量值 -->
<slot name="xxx" text="这是一个带域插槽" value="10"></slot>
<!-- 使用带域插槽,通过slot属性声明替换的插槽,通过slot-scope声明域的名字(对象名),然后通过域名调用域中的属性。 -->
<div slot="xxx" slot-scope="scope">{{scope.text}},值为{{scope.value}}</div>
v-bind & v-on
v-bind 用来动态绑定属性,v-bind:name="fullName"
:将vm中的fullName属性绑定到标签的name属性上。
- v-bind 可以省略,属性名前直接加:可以达到同样的效果,上面简写为
:name="fullName"
- v-bind 可以解构赋值,
v-bind="obj"
,vue会将obj中所有属性绑定到标签上。注意优先级↓↓↓。
<!-- 将attr1和attr2绑定到div标签上 -->
<div v-bind="{attr1:value1,attr2:value2}"></div>
<!-- 直接通过属性名绑定的优先级更高,下面这种情况,attr1的实际值为value -->
<div :attr1="value" v-bind="{attr1:value1,attr2:value2}"></div>
v-on 用来绑定事件监听,v-on:click="func"
:将vm中的func方法绑定到标签的click事件上。
- v-on 也可以省略为@,上面简写为
@click="func"
- v-on 也可以解构赋值,
v-on="obj"
,vue会将obj中所有属性绑定为标签的事件。注意兼容性↓↓↓。
<!-- 将event1和event2绑定到div标签上 -->
<div v-on="{event1:func1,event2:func2}"></div>
<!-- 这两种绑定方法,绑定的函数会同时存在,因此event事件触发的时候func和func1都会执行。 -->
<div @event="func" v-on="{event1:func1,event2:func2}"></div>
$attrs & $listeners
通常创建一个组件,设置props属性定义需要父组件传入的参数,然后就可以在组件标签上声明相应的属性将数据传到组件中。
如果在该组件标签上声明了一个没有在props
中定义的属性vue会怎么办?当然除了class和style这两个纯天然的属性。
vue会把这些属性存放在this.$attrs
中。它是一个对象({attr1:value1,attr2:value2...}
),因此你可以利用 v-bind
指令将它绑定到子组件上。但是,注意一下优先级。
同理,你在组件标签上定义的事件监听,除了.native修饰的之外,都会放到this.$listeners
中,也可以通过 v-on
指令将它绑定到子组件。但是,同一个事件可能会被绑定两次。
scoped style
需求:去掉elementUI的textarea的边框。
<style scoped>
.el-textarea > textarea{
border: 0;
}
</style>
<!-- ↓↓↓↓↓↓↓↓↓↓↓ vue编译之后 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ -->
<style type="text/css">
.el-textarea > textarea[data-v-1dcb4f26]{
border: 0;
}
</style>
vue组件中的 scooped style 编译之后为了使样式只对当前组件生效,会自动再追加一个属性选择器,然后给当前组件中的标签都添加该属性。
因为,textarea是在el-textarea子组件中的,所以属性选择器并没有添加到textarea上,编译之后的html代码如下。
<div data-v-1dcb4f26 class="el-textarea">
<textarea autocomplete="off" rows="7" class="el-textarea__inner" style="min-height: 33px">
</textarea><!---->
</div>
所以,因为vue的‘隔离’措施,上面的style样式并不会生效。
如果,编译之后代码如下就可以了。
<style type="text/css">
.el-textarea[data-v-1dcb4f26] textarea{
border: 0;
}
</style>
vue允许我们指定添加属性选择器的位置,通过 >>>
操作符(深度作用选择器)实现,如下。
<style scoped>
.el-textarea >>> textarea{
border: 0;
}
</style>
<!-- ↓↓↓↓↓↓↓↓↓↓↓ vue编译之后 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ -->
<style type="text/css">
.el-textarea[data-v-1dcb4f26] textarea{
border: 0;
}
</style>