提交 b1590f81 编写于 作者: Z zhaoshuangshi

2-1所有小节问题优化

上级 d088ff97
# 全局与局部组件
 <div style="color: pink;font-size:22px;font-weight:700">小常识:</div>
<br>
**定义组件名的方式有两种:**</br>
使用 kebab-case
```javascript
Vue.component('my-component-name', { /* ... */ })
```
当使用 kebab-case (短横线分隔命名) 定义一个组件时,你也必须在引用这个自定义元素时使用 kebab-case,例如 `<my-component-name>`
使用 PascalCase
```javascript
Vue.component('MyComponentName', { /* ... */ })
```
当使用 PascalCase (首字母大写命名) 定义一个组件时,你在引用这个自定义元素时两种命名法都可以使用。也就是说 `<my-component-name>``<MyComponentName>` 都是可接受的。注意,尽管如此,直接在 DOM (即非字符串的模板) 中使用时只有 kebab-case 是有效的。
**全局组件**</br>
到目前为止,我们只用过 Vue.component 来创建组件:
```javascript
Vue.component('my-component-name', {
// ... 选项 ...
})
```
这些组件是全局注册的。也就是说它们在注册之后可以用在任何新创建的 Vue 根实例 (new Vue) 的模板中。比如:
```javascript
Vue.component('component-a', { /* ... */ })
Vue.component('component-b', { /* ... */ })
Vue.component('component-c', { /* ... */ })
```
```javascript
new Vue({ el: '#app' })
<div id="app">
<component-a></component-a>
<component-b></component-b>
<component-c></component-c>
</div>
```
在所有子组件中也是如此,也就是说这三个组件在各自内部也都可以相互使用。
**局部注册**</br>
全局注册往往是不够理想的。比如,如果你使用一个像 webpack 这样的构建系统,全局注册所有的组件意味着即便你已经不再使用一个组件了,它仍然会被包含在你最终的构建结果中。这造成了用户下载的 JavaScript 的无谓的增加。
在这些情况下,你可以通过一个普通的 JavaScript 对象来定义组件:
```javascript
var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }
```
然后在 components 选项中定义你想要使用的组件:
```javascript
new Vue({
el: '#app',
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
})
```
对于 components 对象中的每个 property 来说,其 property 名就是自定义元素的名字,其 property 值就是这个组件的选项对象。
注意局部注册的组件在其子组件中不可用。例如,如果你希望 ComponentA 在 ComponentB 中可用,则你需要这样写:
```javascript
var ComponentA = { /* ... */ }
var ComponentB = {
components: {
'component-a': ComponentA
},
// ...
}
```
或者如果你通过 Babel 和 webpack 使用 ES2015 模块,那么代码看起来更像:
```javascript
import ComponentA from './ComponentA.vue'
export default {
components: {
ComponentA
},
// ...
}
```
**组件注册错误小案例**</br>
```javascript
<!DOCTYPE html>
......@@ -145,18 +44,15 @@ export default {
</html>
```
**运行会报错**</br>
**运行会报错**</br></br>
<br/>![在这里插入图片描述](https://img-blog.csdnimg.cn/113a151dfcbb496f9378f29f5621b98f.png)
<br/>
<br>
 <div style="color: #8E7CC3;font-size:22px;font-weight:700">小测试:</div>
观察上方组件注册错误案例,导致报错的原因是?<br/><br/>
观察上面代码,导致报错的原因是?<br/><br/>
## 答案
......@@ -166,7 +62,7 @@ export default {
### A
不能使用`<aabb-c></aabb-c>`应该改成`<aabbC></aabbC-c>`
不能使用`<aabb-c></aabb-c>`应该改成`<aabbC></aabb-c>`
### B
......
# 父子组件通讯
 <div style="color: pink;font-size:22px;font-weight:700">小常识:</div>
<br>
**父传子**<br>
- 在子组件中定义props属性 值为数组类似于data 但data中的数据来自本身 而props中的数据来自父组件
- 子组件使用模板中使用props中的属性和data中的用法相同
- 父组件通过props传值给子组件
<br/>![在这里插入图片描述](https://img-blog.csdnimg.cn/2020040312014626.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0pIWExf,size_16,color_FFFFFF,t_70)
<br/>
输出结果为:
<br/>![在这里插入图片描述](https://img-blog.csdnimg.cn/20200403120217164.png)
<br/>
说明:
1. 创建Vue实例 data中的数据msg为一个数组
2. 创建组件 在整个项目中 2组件相对就是1的子组件
3. 通过3方式前者msg为props值中的数据 后者msg为newVue中data中的数据
4. 最后正是props中的属性也有data中的使用方法 将数据进行遍历在页面中
注意:props负责获取父组件的传递过来的,props中的值是只读的,不允许修改
**子传父**<br>
- 父组件使用子组件时 在其中定义一个自定义事件 并且绑定父组件中的一个自定义函数 当事件被调用时执行自定义函数
- 子组件通过this$emit执行自定义事件
<br/>![在这里插入图片描述](https://img-blog.csdnimg.cn/20200403121933688.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0pIWExf,size_16,color_FFFFFF,t_70)
<br/>
最终输出结果为3
1. 在子组件中定义一个点击事件 触发时执行子组件中的dian函数 并且将参数传入函数中
2. 在上面的函数中通过this.$emit(‘事件名称’,参数)调用3中的a自定义事件并且将参数传过去
3. 当a事件被触发时 会执行4中的aaa自定义函数 同时获取参数 最终实现子组件向父组件传数据
**实例改造**<br>
根据父子组件之间的数据传递实现产品列表的组件化开发
<br/>![在这里插入图片描述](https://img-blog.csdnimg.cn/2020040312280456.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0pIWExf,size_16,color_FFFFFF,t_70)
<br/>
**代码如下**
```
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
div {
width: 1000px;
margin: 100px auto;
text-align: center;
}
table {
width: 900px;
margin: 50px auto;
border-collapse: collapse;
}
table,
th,
td {
border: 1px solid rgb(218, 124, 17);
}
.color {
background-color: rgb(26, 172, 152);
}
</style>
</head>
<body>
<div id="app">
<atitle @tian="tian" :aatitle="aupda" @cha="cha"></atitle>
<acontent :content="newcontent" @del="del" @upda="upda"></acontent>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
Vue.component('atitle', {
props: ['aatitle'],
data() {
return {
keyword: ''
}
},
template: `<div>
型号 <input type="text" v-model=aatitle.name>
价格 <input type="text" v-model=aatitle.may @keyup.enter="tian">
<button @click="tian">录入</button><br>
<input type="text" v-model="keyword">
</div>`,
methods: {
tian() {
this.$emit('tian', this.aatitle.name, this.aatitle.may)
this.aatitle.name = ''
this.aatitle.may = ''
}
},
watch: {
keyword: {
handler(newvalue) {
this.$emit('cha', newvalue)
},
immediate: true
}
}
})
Vue.component('acontent', {
props: ['content'],
template: `<table>
<tr>
<th>编号</th>
<th>机型</th>
<th>价格</th>
<th>时间</th>
<th>操作</th>
</tr>
<tr v-show="this.content.length==0">
<td colspan="5">没有任何发布任何产品</td>
</tr>
<tr v-for="(item,index) in content">
<td>{{item.id}}</td>
<td>{{item.name}}</td>
<td>{{item.may}}</td>
<td>{{item.time}}</td>
<td>
<a href="#"" @click.prevent="del(item.id)">删除</a>
<a href="#"" @click.prevent='upda(item.id)'>编辑</a>
</td>
</tr>
</table>`,
methods: {
del(id) {
this.$emit('del', id)
},
upda(id) {
this.$emit('upda', id)
}
}
})
const app = new Vue({
el: '#app',
data: {
newcontent: [],
aupda: {},
isup: false,
upid: '',
content: [{
id: 1,
name: '华为',
may: 5000,
time: Date.now()
},
{
id: 2,
name: '小米',
may: 6000,
time: Date.now()
},
{
id: 3,
name: '苹果',
may: 4500,
time: Date.now()
},
{
id: 4,
name: '1+',
may: 3000,
time: Date.now()
},
{
id: 5,
name: 'oppo',
may: 2000,
time: Date.now()
},
{
id: 6,
name: '1+2',
may: 8000,
time: Date.now()
},
{
id: 7,
name: '1+3',
may: 12000,
time: Date.now()
}
]
},
methods: {
del(id) {
let index = this.content.findIndex(item => {
return item.id == id
})
this.content.splice(index, 1)
this.newcontent.splice(index, 1)
},
tian(name, may) {
if (this.isup) {
let a = this.content.find(item => {
return item.id == this.upid
})
a.name = name
a.may = may
} else {
let id = this.content.length - 1 < 0 ? 1 : this.content[this.content.length - 1].id + 1
let content = {
id: id,
name: name,
may: may,
time: Date.now()
}
this.content.push(content)
this.newcontent.push(content)
}
},
cha(value) {
this.newcontent = this.content.filter(item => {
return item.name.includes(value)
})
},
upda(id) {
let a = this.content.find(item => {
return item.id == id
})
this.aupda = {
name: a.name,
may: a.may
}
this.isup = true
this.upid = id
}
}
})
</script>
</body>
</html>
```
<br>
 <div style="color: #8E7CC3;font-size:22px;font-weight:700">小测试:</div>
通过上面的案例,下列说法不正确的是?<br/><br/>
对于父子组件通讯下列说法不正确的是?<br/><br/>
## 答案
父组件向子组件通讯只能使用 props 一种方法
父组件向子组件通讯只能使用 props 一种方法
## 选项
### A
子组件向父组件传参逻辑是通过$emit调用父组件的自定义方法的时候进行传参
子组件向父组件传参可以通过$emit调用父组件的自定义方法的时候进行传参。
### B
props负责获取父组件的传递过来的,props中的值是只读的,不允许修改
props负责获取父组件传递过来的数据,props中的值是只读的,不允许直接修改。
### C
props负责获取父组件的传递过来的值也可以通过插值表达式展示在页面中
Prop 是你可以在组件上注册的一些自定义 attribute。当一个值传递给一个 prop attribute 的时候,它就变成了那个组件实例的一个 property。
......@@ -14,121 +14,6 @@ const bus =new Vue()
>2. 组件B触发bus上对应的事件,把 值当成参数来传递
>3. 组件A通过事件处理程序获取数据
>
<br/>![在这里插入图片描述](https://img-blog.csdnimg.cn/20200403124524548.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0pIWExf,size_16,color_FFFFFF,t_70)
<br/>
**最终点击h2控制台会输出2**<br>
1. 创建1和2两个非父子组件以及vue实例bus
2. 在1组件中 钩子函数created中通过**bus.$on**为bus自定义一个事件aa
3. 在2组件中 当点击h2元素时触发dian函数 并且将值出过去
4. 在2组件的dian函数中通过**bus.$emit**方触发1中的aa事件 并传参过去
5. 当1中的aa事件被触发时会执行其中的函数并获取参数
**通过非父子组件 实现开关灯案例**<br>
关闭状态:
<br/>![在这里插入图片描述](https://img-blog.csdnimg.cn/20200403125323123.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0pIWExf,size_16,color_FFFFFF,t_70)
<br/>
开启状态:
<br/>![在这里插入图片描述](https://img-blog.csdnimg.cn/20200403125354722.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0pIWExf,size_16,color_FFFFFF,t_70)
<br/>
**代码如下**
```
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
#app {
width: 500px;
height: 500px;
margin: 100px auto;
}
.box {
height: 200px;
width: 200px;
margin: 0 auto;
background-color: black;
border-radius: 50%;
}
.below {
height: 200px;
width: 400px;
margin: 50px auto;
}
button {
margin-left: 66px;
width: 100px;
height: 40px;
}
.on {
background-color: rgb(160, 184, 25);
}
</style>
</head>
<body>
<div id="app">
<zss></zss>
<sgy></sgy>
</div>
<script src="./node_modules/vue/dist/vue.js"></script>
<script>
const bus = new Vue()
Vue.component('zss', {
data() {
return {
attribute: "on",
state: false
}
},
created() {
bus.$on('lamp', result => {
this.state = result
})
},
template: `<div class="box" :class="state?attribute:''"></div>`
})
Vue.component('sgy', {
template: `<div class="below">
<button @click="on">开灯</button>
<button @click="off">关闭</button>
</div>`,
methods: {
on() {
bus.$emit('lamp', true)
},
off() {
bus.$emit('lamp', false)
}
}
})
const app = new Vue({
el: '#app',
data: {
}
})
</script>
</body>
</html>
```
**非父子组件不仅这一种通讯方式,其他方式同学们可以去博文中查看**
<br>
 <div style="color: #8E7CC3;font-size:22px;font-weight:700">小测试:</div>
......@@ -136,7 +21,7 @@ const bus =new Vue()
## 答案
eventBus其实就是当触发事件时,发送一个通知出去,在需要响应的地方接收这个通知,响应事件
eventBus其实就是A组件给eventBus注册一个事件,监听事件的处理程序,B组件通过触发eventBus上的事件并将要传递的值作为参数传递,A组件通过事件处理程序获得数据
## 选项
......@@ -146,8 +31,8 @@ eventBus是非父子组件通讯唯一方式。
### B
非父子组件之间进行通讯会造成内存泄漏
非父子组件之间进行通讯势必会造成内存泄漏,一般我们通过将非父子组件转化成父子组件在进行通讯
### C
VueX并不能解决非父子通讯问题。
VueX 并不能解决非父子通讯问题。
# 插槽
 <div style="color: pink;font-size:22px;font-weight:700">小常识:</div>
<br>
下方的alert-box是一个组件,和 HTML 元素一样,我们经常需要向一个组件传递内容,像这样:
```javascript
<alert-box>
Something bad happened.
</alert-box>
```
可能会渲染出这样的东西:<br>
<br/>![在这里插入图片描述](https://img-blog.csdnimg.cn/7a782ff974ab4eee995d84c15b2a81f1.png)
<br/>
幸好,Vue 自定义的 `<slot>` 元素让这变得非常简单:
```javascript
Vue.component('alert-box', {
template: `
<div class="demo-alert-box">
<strong>Error!</strong>
<slot></slot>
</div>
`
})
```
如你所见,我们只要在需要的地方加入插槽就行了——就这么简单!
<br>
 <div style="color: #8E7CC3;font-size:22px;font-weight:700">小测试:</div>
下列关于插槽描述错误的是?<br/><br/>
下列关于插槽描述不正确的是?<br/><br/>
## 答案
Vue中使用插槽是为了解决解决组件美观问题。
Vue中使用插槽仅仅是为了解决解决组件美观问题。
## 选项
### A
插槽就是子组件中的提供给父组件使用的一个占位符
插槽是子组件中的提供给父组件使用的一个占位符。
### B
......
# 动态组件、异步组件
 <div style="color: pink;font-size:22px;font-weight:700">小常识:</div>
<br>
**动态组件**
之前在个多标签的界面中我们通过 is attribute 来切换不同的组件:
```javascript
<component v-bind:is="currentTabComponent"></component>
```
当在这些组件之间切换的时候,你有时会想保持这些组件的状态,以避免反复重新渲染导致的性能问题。
重新创建动态组件的行为通常是非常有用的,在一些案例中,我们更希望那些标签的组件实例能够被在它们第一次被创建的时候缓存下来。为了解决这个问题,我们可以用一个 `<keep-alive>` 元素将其动态组件包裹起来。
```javascript
<!-- 失活的组件将会被缓存-->
<keep-alive>
<component v-bind:is="currentTabComponent"></component>
</keep-alive>
```
注意这个 `<keep-alive>` 要求被切换到的组件都有自己的名字,不论是通过组件的 name 选项还是局部/全局注册。
**异步组件**
在大型应用中,我们可能需要将应用分割成小一些的代码块,并且只在需要的时候才从服务器加载一个模块。为了简化,Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。Vue 只有在这个组件需要被渲染的时候才会触发该工厂函数,且会把结果缓存起来供未来重渲染。例如:
```javascript
Vue.component('async-example', function (resolve, reject) {
setTimeout(function () {
// 向 `resolve` 回调传递组件定义
resolve({
template: '<div>I am async!</div>'
})
}, 1000)
})
```
如你所见,这个工厂函数会收到一个 resolve 回调,这个回调函数会在你从服务器得到组件定义的时候被调用。你也可以调用 reject(reason) 来表示加载失败。这里的 setTimeout 是为了演示用的,如何获取组件取决于你自己。一个推荐的做法是将异步组件和 webpack 的 code-splitting 功能一起配合使用:
```javascript
Vue.component('async-webpack-example', function (resolve) {
// 这个特殊的 `require` 语法将会告诉 webpack
// 自动将你的构建代码切割成多个包,这些包
// 会通过 Ajax 请求加载
require(['./my-async-component'], resolve)
})
```
你也可以在工厂函数中返回一个 Promise,所以把 webpack 2 和 ES2015 语法加在一起,我们可以这样使用动态导入:
```javascript
Vue.component(
'async-webpack-example',
// 这个动态导入会返回一个 `Promise` 对象。
() => import('./my-async-component')
)
```
使用局部注册的时候,你也可以直接提供一个返回 Promise 的函数:
```javascript
new Vue({
// ...
components: {
'my-component': () => import('./my-async-component')
}
})
```
如果你是一个 Browserify 用户同时喜欢使用异步组件,很不幸这个工具的作者明确表示异步加载“并不会被 Browserify 支持”,至少官方不会。Browserify 社区已经找到了一些变通方案,这些方案可能会对已存在的复杂应用有帮助。对于其它的场景,我们推荐直接使用 webpack,以拥有内置的头等异步支持。
<br>
 <div style="color: #8E7CC3;font-size:22px;font-weight:700">小测试:</div>
以下关于动态组件和异步组件的说法不正确的是?<br/><br/>
## 答案
Vue 允许我们以一个工厂函数的方式定义组件只能收到一个 resolve 回调,这个回调函数会在你从服务器得到组件定义的时候被调用
`<keep-alive>` 要求被切换到的组件都要有名字并且keep-alive包裹的一组组件名字都要相同。
## 选项
### A
使用动态组件标签的组件实例能够被在它们第一次被创建的时候缓存下来
`<keep-alive>` 元素可以将动态组件包裹起来,在它们第一次被创建的时候就会被缓存下来。
### B
动态组件可以保持这些组件的状态,以避免反复重渲染导致的性能问题
动态组件可以保持这些组件的状态,以避免反复重渲染导致的性能问题
### C
可以在工厂函数中返回一个 Promise
Vue 允许你以一个工厂函数的方式定义你的组件,这个工厂函数会异步解析你的组件定义。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册