本文版权归 “公众号 | 前端一万小时” 所有,欢迎转载!
转载请注明出处,未经同意,不可修改文章内容。
🔥🔥🔥本系列文章已在“公众号 | 前端一万小时”更新完毕,有需要的小伙伴可按需前往查看。
🔥🔥🔥“前端一万小时”两大明星专栏——“从零基础到轻松就业”、“前端面试刷题”,已于本月大改版,合二为一,干货满满,欢迎点击公众号菜单栏各模块了解。
涉及面试题:
1. Vue 组件中 data 为什么必须是一个函数?
2. Vue 的两个核心点?
3. 如何获取 DOM?
[编号:vue_14]
❓本篇需要解决的问题:
is
标签解决 H5 标签上的 bug ;- 子组件里定义
data
,data
值必须为一个函数; ref
这个引用的使用。
1 is
特殊属性解决 H5 标签上的 bug
1.1 H5 标签元素中如何正确使用子组件
❓例如,如何使用下边这组标签:
<table>
<tbody>
<tr>
<td></td>
</tr>
</tbody>
</table>
❌按之前学习的思路,我们可能会写出以下代码:
<body>
<div id="root">
<table>
<tbody>
<row></row>
<row></row>
<row></row>
</tbody>
</table>
</div>
<script>
Vue.component("row", {
template: "<tr><td>This is a superman</td></tr>"
})
var vm = new Vue({
el: "#root"
})
</script>
</body>
😰出现问题:
审查元素时发现 <tr>
与 <table>
处于平级,这是不合理的。
因为 H5 的规范中要求我们需要按以下的嵌套方式写表格标签的代码:
<table>
<tbody>
<tr>
<td></td>
</tr>
</tbody>
</table>
💡类似还有:
<ul>
<li> </li>
</ul>
<ol>
<li> </li>
</ol>
<section>
<option> </option>
</section>
1.2 解决方法:使用 is
在 H5 标签中使用子组件
这样既能保证 tr
使用 row
这个子组件,又符合 H5 的编码规范:
<body>
<div id="root">
<table>
<tbody>
<tr is="row"></tr> <!-- 🚀使用 is 在 H5 标签中使用子组件 -->
<tr is="row"></tr>
<tr is="row"></tr>
</tbody>
</table>
</div>
<script>
Vue.component("row", {
template: "<tr><td>This is a superman</td></tr>"
})
var vm = new Vue({
el: "#root"
})
</script>
</body>
2 子组件里定义 data
,值必须为一个函数
2.1 需求:在子组件定义 data
时传递内容
❌按照之前学习思路,我们可能会写出以下代码:
<script>
Vue.component("row", {
data: {
content: "this is a superman"
},
template: "<tr><td>{{content}}</td></tr>"
})
var vm = new Vue({
el: "#root"
})
</script>
❗️出现报错:
2.2 解决方法:子组件定义 data
时,值必须为一个函数
💡分析:
子组件在调用时,不像根组件只调用一次,它可能会在同一个地方调用多次。每一个子组件在调用时,都应该有自己的数据。
而通过一个“函数”返回一个“对象”值的目的,就能让每一个子组件都拥有一个独立的数据存储,这样不会有多个子组件互相影响的情况出现。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>前端一万小时-使用组件的细节点</title>
<script src="./vue.js"></script>
</head>
<body>
<div id="root">
<table>
<tbody>
<tr is="row"></tr>
<tr is="row"></tr>
<tr is="row"></tr>
</tbody>
</table>
</div>
<script>
Vue.component("row", {
data: function() { /*
🚀在子组件里定义 data ,值必须为一个“函数”,
然后通过函数返回一个“对象”引用来存储值!
*/
return {
content: "Hello,前端一万小时"
}
},
template: "<tr><td>{{content}}</td></tr>"
})
var vm = new Vue({
el: "#root"
})
</script>
</body>
</html>
3 ref
特殊属性
<body>
<div id="root">
<div @click="handleClick">
hello world
</div>
</div>
<script>
var vm = new Vue({
el: "#root",
methods: {
handleClick: function() {
alert("click")
}
}
})
</script>
</body>
3.1 在 Vue 中如何操作 dom
虽然 Vue 不建议我们去操作 DOM ,但是在处理一些极其复杂的动画效果时,只靠 Vue 的这种双向绑定时是处理不了的。所以在有些必要的情况下,我们还是需要操作 DOM 。
🚀我们通过 ref
这种引用的形式来获取 DOM ,并进行 DOM 的操作。
❓需求: 我希望 div 在被点击的时候,我把 div 里边的内容打印出来。
💡需求分析: 我需要获得 div 所对应的 DOM 节点,然后如果能拿到 DOM 节点下的 hello wold
,那么就能够把它打印出来了。
<body>
<div id="root">
<div ref="hello"
@click="handleClick"
>
hello world
</div> <!-- 1️⃣首先,我给这个 div 标签添加 ref 属性,名字叫 hello; -->
</div>
<script>
var vm = new Vue({
el: "#root",
methods: {
handleClick: function() {
alert(this.$refs.hello.innerHTML)
/*
2️⃣这里边的 $refs 指的是父组件的 $refs 对象,使用 ref 注册的所有引用都在 $refs 中,
而 $refs.hello 就特指名字为 hello 的这个 div 的 DOM。
*/
}
}
})
</script>
</body>
3.2 动态获取组件内容
❓需求①: 制作一个计数器,并且能够点击数字就按顺序 +1
代码实现:
<body>
<div id="root">
<counter></counter>
<counter></counter>
</div>
<script>
Vue.component("counter", {
template: '<div @click="handleClick">{{number}}</div>',
data: function() {
return {
number: 0
}
},
methods: {
handleClick: function() {
this.number ++ // 每点击一次,number 上的数字就会 +1。
}
}
})
var vm = new Vue({
el: "#root"
})
</script>
</body>
❓需求②:对以上代码里的两个 counter
组件进行求和。
<body>
<div id="root">
<!-- 7️⃣我们给两个 counter 都添加一个 ref 引用,然后分别取名为“one”和“two”;-->
<counter ref="one" @change="handleChange"></counter> <!-- 4️⃣同时我们会在
父组件“接收”子组件“触发”的 change 事件,
并去执行相关方法; -->
<counter ref="two" @change="handleChange"></counter>
总计:{{total}} <!-- 2️⃣然后通过插值表达式的形式把“数据” total 显示出来; -->
</div>
<script>
Vue.component("counter", {
template: '<div @click="handleClick">{{number}}</div>',
data: function() {
return {
number: 0
}
},
methods: {
handleClick: function() {
this.number ++
this.$emit("change") /*
3️⃣当我们点击子组件时,不仅上边的 number 会+1 ,
同时会“触发”一个 change 事件;
*/
}
}
})
var vm = new Vue({
el: "#root",
data: {
total: 0 // 1️⃣首先,我在 data 里定义一个 total ,并初始化为 0;
},
methods: {
handleChange: function() {
// 5️⃣我们在父组件里定义 handleChange 这个方法;
// 6️⃣但要实现“求和”,我们还需要返回父组件模板里边去,通过 ref 引用的方式,获取到相应 DOM;
this.total = this.$refs.one.number + this.$refs.two.number
/*
8️⃣通过 this.$refs.one 获取“子组件” counter 的一个“引用”,
然后继续通过 this.$refs.one.number 拿到“one”的“数目”(同样的方式获得“two”的数目),
最后作一个加法运算。
*/
}
}
})
</script>
</body>
3.3 “标签”和“子组件”里使用 ref
的区别
- 在“标签”里使用
ref
时,我们通过this.refs.引用的名字
获取到的是这个“标签”对应的 DOM 元素; - 而在“子组件”里使用
ref
时,我们通过this.refs.引用的名字.xxx
获得到的是“子组件”的一个“引用”!
祝好,qdywxs ♥ you!