Vue组件关于踩坑技术的细节
【摘要】 系列请多关注
使用组件的细节点
解析 DOM 模板时的注意事项
<div id="root">
<table>
<tbody>
<row></row>
<row></row>
<row></row>
</tbody>
</table>
</div>
<script type="text/javascript">
Vue.component('row', {
template: '<tr><td>this is a row</td></tr>'
})
var vm = new Vue({
el: '#root'
})
</script>
上面代码中,row
组件在渲染页面时,并不会把tr
节点渲染到tbody
里面,而是被提升到了和table
同一个级别的地方。原因是在html编码规范中,tbody
里面只能放tr
,正确的做法是使用tr
标签添加is
属性等于组件名称row
:
<tbody>
<tr is="row"></tr>
<tr is="row"></tr>
<tr is="row"></tr>
</tbody>
同样,ul>li
、ol>li
、select > option
标签也要注意这样的问题。
需要注意的是如果我们从以下来源使用模板的话,这条限制是不存在的:
- 字符串 (例如:
template: '...'
) - 单文件组件 (
.vue
) <script type="text/x-template">
子组件内的data要使用函数返回
Vue.component('row', {
data() {
return {
content: 'this is content'
}
},
template: '<tr><td>{{content}}</td></tr>'
})
之所以这样设计是因为子组件有可能会被调用多次,而每次调用时的data数据都应该是独立的。因此需要通过一个函数来实现,每个实例可以维护一份被返回对象的独立的拷贝。
这样才不会出现每个子组件数据相互影响的情况。
通过 ref 引用操作DOM
虽然并不推荐我们在使用vue的时候操作DOM,但是某些情况下我们必须要操作DOM来实现一些功能,因此可以通过ref引用的形式来获取到DOM节点。
<!-- `vm.$refs.p` 指向DOM元素节点 -->
<p ref="p">hello</p>
<!-- `vm.$refs.child` 指向组件实例 -->
<child-component ref="child"></child-component>
ref
被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs
对象上。如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例。
组件实例对象 VueComponent
打开控制台,点击demo中的按钮可查看组件实例
<p class="codepen" data-height="460" data-theme-id="light" data-default-tab="js,result" data-user="xugaoyi" data-slug-hash="VwLeMoM" style="height: 460px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 20px solid; margin: 1em 0; padding: 1em;" data-pen-title="VwLeMoM">
<span>See the Pen <a href="https://codepen.io/xugaoyi/pen/VwLeMoM">
VwLeMoM</a> by xugaoyi (<a href="https://codepen.io/xugaoyi">@xugaoyi</a>)
on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>`
父组件给子组件传值
父组件中,通过给子组件标签v-bind绑定属性的方式传入值
<ComponentName v-bind:name="value"></ComponentName>
如果不使用v-bind传入的值为字符串,使用v-bind绑定传入的值为表达式。
子组件中,通过props对象接收值
props: {
name: { // 接收父组件传入值
type: String || ...,
default: ''
}
}
单向数据流
所有的 prop 都使得其父子 prop 之间形成了一个单向下行绑定:父级 prop 的更新会向下流动到子组件中,但是反过来则不行。这样会防止从子组件意外改变父级组件的状态,从而导致你的应用的数据流向难以理解。
子组件不能直接修改父组件传入的值
这里有两种常见的试图改变一个 prop 的情形:
- 这个 prop 用来传递一个初始值;这个子组件接下来希望将其作为一个本地的 prop 数据来使用。在这种情况下,最好定义一个本地的 data 属性并将这个 prop 用作其初始值:
props: ['initialCounter'],
data: function () {
return {
counter: this.initialCounter
}
}
- 这个 prop 以一种原始的值传入且需要进行转换。在这种情况下,最好使用这个 prop 的值来定义一个计算属性:
props: ['size'],
computed: {
normalizedSize: function () {
return this.size.trim().toLowerCase()
}
}
父子组件间传递数据 demo
<p class="codepen" data-height="400" data-theme-id="light" data-default-tab="js,result" data-user="xugaoyi" data-slug-hash="mdJVqgg" style="height: 400px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="mdJVqgg">
<span>See the Pen <a href="https://codepen.io/xugaoyi/pen/mdJVqgg">
mdJVqgg</a> by xugaoyi (<a href="https://codepen.io/xugaoyi">@xugaoyi</a>)
on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
子组件派发事件和值给父组件
子组件通过$emit
派发事件和值给父组件(值可以有多个)
this.$emit('fnX', value)
父组件通过v-on
绑定子组件派发的事件,并触发一个新的事件,新的事件内可以接收传来的值
<ComponentName @fnX="fnY"></ComponentName>
methods: {
fnY(value) {
console.log(value)
}
}
父子组件间传递数据 demo
<p class="codepen" data-height="400" data-theme-id="light" data-default-tab="js,result" data-user="xugaoyi" data-slug-hash="mdJVqgg" style="height: 400px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;" data-pen-title="mdJVqgg">
<span>See the Pen <a href="https://codepen.io/xugaoyi/pen/mdJVqgg">
mdJVqgg</a> by xugaoyi (<a href="https://codepen.io/xugaoyi">@xugaoyi</a>)
on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://static.codepen.io/assets/embed/ei.js"></script>
Prop 验证 与 非 Prop 的 Attribute
Prop 验证
子组件对父组件传递来的参数进行校验
Vue.component('my-component', {
props: {
// 基础的类型检查 (`null` 和 `undefined` 会通过任何类型验证)
propA: Number,
// 多个可能的类型
propB: [String, Number],
// 必填的字符串
propC: {
type: String,
required: true
},
// 带有默认值的数字
propD: {
type: Number,
default: 100
},
// 带有默认值的对象
propE: {
type: Object,
// 对象或数组默认值必须从一个工厂函数获取
default: function () {
return { message: 'hello' }
}
},
// 自定义验证函数
propF: {
validator: function (value) {
// 这个值必须匹配下列字符串中的一个
return ['success', 'warning', 'danger'].indexOf(value) !== -1
}
}
}
})
非 Prop 的 Attribute
当子组件没有定义对应的Prop来接收父组件传来的值时,这个值将会出现在组件根元素的Attribute
上面。
用处
例如,想象一下你通过一个 Bootstrap 插件使用了一个第三方的 <bootstrap-date-input>
组件,这个插件需要在其 <input>
上用到一个 data-date-picker
attribute。我们可以将这个 attribute 添加到你的组件实例上:
<bootstrap-date-input data-date-picker="activated"></bootstrap-date-input>
然后这个 data-date-picker="activated"
attribute 就会自动添加到 <bootstrap-date-input>
组件的根元素上。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)