昨日内容回顾

1. Vue使用
1. 生成Vue实例和DOM中元素绑定
2. app.$el --> 取出该vue实例绑定的DOM标签
3. app.$data --> 取出该vue实例绑定的data属性
2. 模板语法
1. {{name}} --> 在标签中间引用data属性中的变量
2. v-html='msg' --> 在页面上显示我定义的标签元素 3. v-if='ok' --> 控制标签在不在DOM中
4. v-show='!ok' --> 控制标签的display属性的值(是否显示) 5. v-bind:href='url' --> 将标签的属性和vue实例的data属性绑定起来
6. v-on:click='dianwo'--> 给标签绑定一个点击事件,方法需要在vue实例的methods中定义 7. v-model='article' --> 用在input标签和textarea标签中,将用户输入和vue实例中的数据属性建立双向绑定 3. 计算属性和侦听器
1. 计算属性
(字符串翻转的例子)
1. 计算属性需要定义在vue实例的 computed 中
2. 多用于对变量做一些自定义的操作
3. 我们在页面上像使用普通data属性一样使用计算属性
2. 侦听器
多用于一些复杂的运算或者异步操作
侦听器需要放在 vue实例的 watch 中
4. class和style属性
1. 基于对象的绑定
2. 基于数组的绑定
5. 条件渲染
v-if
如果想控制多个标签的显示与否,可以使用 template 标签把它们包起来
v-if/v-else
v-if/v-else if /v-else 6. 列表渲染
v-for循环
7. 事件处理
详见2.模板语法
8. 表单绑定
详见2.模板语法 二. 小清单
1. 对象的深拷贝
2. 根据索引删除数组中的元素
splice(索引,删除个数,插入的元素)

一、Vue组件

组件基础

组件的组织

通常一个应用会以一棵嵌套的组件树的形式来组织:

将上图理解为一个网页

例如,你可能会有页头、侧边栏、内容区等组件,每个组件又包含了其它的像导航链接、博文之类的组件。

为了能在模板中使用,这些组件必须先注册以便 Vue 能够识别。这里有两种组件的注册类型:全局注册和局部注册。至此,我们的组件都只是通过 Vue.component 全局注册的:

Vue.component('my-component-name', {
// ... options ...
})

全局注册的组件可以用在其被注册之后的任何 (通过 new Vue) 新创建的 Vue 根实例,也包括其组件树中的所有子组件的模板中。

到目前为止,关于组件注册你需要了解的就这些了,如果你阅读完本页内容并掌握了它的内容,我们会推荐你再回来把组件注册读完。

组件注册

组件名

在注册一个组件的时候,我们始终需要给它一个名字。比如在全局注册时:

Vue.component('my-component-name', { /* ... */ })

该组件名就是 Vue.component 的第一个参数。

你给予组件的名字可能依赖于你打算拿它来做什么。当直接在 DOM 中使用一个组件 (而不是在字符串模板或单文件组件) 的时候,我们强烈推荐遵循 W3C 规范中的自定义组件名 (字母全小写且必须包含一个连字符)。这会帮助你避免和当前以及未来的 HTML 元素相冲突。

你可以在风格指南中查阅到关于组件名的其它建议。

组件名大小写

定义组件名的方式有两种:

使用 kebab-case

Vue.component('my-component-name', { /* ... */ })

当使用 kebab-case (短横线分隔命名) 定义一个组件时,你也必须在引用这个自定义元素时使用 kebab-case,例如 <my-component-name>

使用 PascalCase

Vue.component('MyComponentName', { /* ... */ })

当使用 PascalCase (驼峰式命名) 定义一个组件时,你在引用这个自定义元素时两种命名法都可以使用。也就是说 <my-component-name> 和 <MyComponentName>都是可接受的。注意,尽管如此,直接在 DOM (即非字符串的模板) 中使用时只有 kebab-case 是有效的

全局注册

到目前为止,我们只用过 Vue.component 来创建组件:

Vue.component('my-component-name', {
// ... 选项 ...
})

这些组件是全局注册的。也就是说它们在注册之后可以用在任何新创建的 Vue 根实例 (new Vue) 的模板中。比如:

js代码:

Vue.component('component-a', { /* ... */ })
Vue.component('component-b', { /* ... */ })
Vue.component('component-c', { /* ... */ }) new Vue({ el: '#app' })

html代码:

<div id="app">
<component-a></component-a>
<component-b></component-b>
<component-c></component-c>
</div>

在所有子组件中也是如此,也就是说这三个组件在各自内部也都可以相互使用。

常规举例

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!--监听点击事件-->
<button v-on:click="ttt">弹弹弹</button>
</div>
<script>
var app = new Vue({
el:"#app",
data:{},
methods:{
// 自定义方法
ttt:function () {
alert('弹走鱼尾纹');
}
}
})
</script>
</body>
</html>

访问网页,点击按钮,效果如下:

如果页面其他地方,也需要弹框效果呢?代码复制一遍?
这不符合编程习惯,需要使用组件

组件是可复用的 Vue 实例,且带有一个名字

组件举例

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!--使用自定义组件tankuang-->
<tankuang></tankuang>
</div>
<script>
//注册自定义组件,组件名为tankuang
Vue.component('tankuang',{
template:`<button v-on:click="ttt">弹弹弹</button>`,
methods:{
ttt:function(){
alert('弹走鱼尾纹');
}
}
})
var app = new Vue({
el:"#app",
data:{},
})
</script>
</body>
</html>

刷新网页,效果同上!

在这个例子中是 <tankuang>,就是一个自定义组件。它作为一个自定义元素来使用!

因为组件是可复用的 Vue 实例,所以它们与 new Vue 接收相同的选项,例如 datacomputedwatchmethods 以及生命周期钩子等。仅有的例外是像 el 这样根实例特有的选项。

组件的复用

你可以将组件进行任意次数的复用:

<div id="app">
<!--使用自定义组件tankuang-->
<tankuang></tankuang>
<tankuang></tankuang>
<tankuang></tankuang>
</div>

注意当点击按钮时,每个组件都会各自独立维护它的 count。因为你每用一次组件,就会有一个它的新实例被创建。

刷新网页,效果如下:

data 必须是一个函数

当我们定义这个 <tankuang> 组件时,你可能会发现它的 data 并不是像这样直接提供一个对象:

data: {
count: 0
}

取而代之的是,一个组件的 data 选项必须是一个函数,因此每个实例可以维护一份被返回对象的独立的拷贝:

data: function () {
return {
count: 0
}
}

如果 Vue 没有这条规则,点击一个按钮就可能会影响到其它所有实例

举例:点击按钮,数字加1

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!--使用自定义组件tankuang-->
<tankuang></tankuang>
<tankuang></tankuang>
<tankuang></tankuang>
</div>
<script>
//注册自定义组件,组件名为tankuang
Vue.component('tankuang',{
//监听点击事件,引用count变量
template:`<button v-on:click="ttt">弹弹弹{{count}}</button>`,
data:function(){
return {
//默认值为0
count: 0
}
},
methods:{
ttt:function(){
//自增
this.count +=1
}
}
})
var app = new Vue({
el:"#app",
data:{},
})
</script>
</body>
</html>

刷新网页,效果如下:

局部注册

全局注册往往是不够理想的。比如,如果你使用一个像 webpack 这样的构建系统,全局注册所有的组件意味着即便你已经不再使用一个组件了,它仍然会被包含在你最终的构建结果中。这造成了用户下载的 JavaScript 的无谓的增加。

在这些情况下,你可以通过一个普通的 JavaScript 对象来定义组件:

js代码

var ComponentA = { /* ... */ }
var ComponentB = { /* ... */ }
var ComponentC = { /* ... */ }

然后在 components 选项中定义你想要使用的组件:

new Vue({
el: '#app'
components: {
'component-a': ComponentA,
'component-b': ComponentB
}
})

对于 components 对象中的每个属性来说,其属性名就是自定义元素的名字,其属性值就是这个组件的选项对象。

注意局部注册的组件在其子组件中不可用。例如,如果你希望 ComponentA 在 ComponentB 中可用,则你需要这样写:

var ComponentA = { /* ... */ }

var ComponentB = {
components: {
'component-a': ComponentA
},
// ...
}

举例:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!--使用自定义组件tankuang-->
<tankuang></tankuang>
<tankuang></tankuang>
<tankuang></tankuang>
</div>
<script>
//定义常量tankuangComponent
const tankuangComponent = {
template:`<button v-on:click="ttt">弹弹弹{{count}}</button>`,
data:function(){
return {
count: 0
}
},
methods:{
ttt:function(){
//自增
this.count +=1
}
}
}
//注册自定义的局部组件
var app = new Vue({
el:"#app",
data:{},
//components表示组件
components:{
tankuang:tankuangComponent
},
});
</script>
</body>
</html>

刷新网页,效果同上!

总结:

注意事项:
组件中的data属性必须设置成一个函数!!!
1. 注册全局组件
Vue.component(组件名,{
template: ``,
data: function(){
return {}
},
methods: {...}
})
2. 注册局部组件(当前vue实例才能使用的组件)
new Vue({
el: '#app',
components: {
alert: {
template: ``,
data: function(){
return {}
},
methods: {...}
}
}
})

通过 Prop 向子组件传递数据

早些时候,我们提到了创建一个博文组件的事情。问题是如果你不能向这个组件传递某一篇博文的标题或内容之类的我们想展示的数据的话,它是没有办法使用的。这也正是 prop 的由来。

Prop 是你可以在组件上注册的一些自定义特性。当一个值传递给一个 prop 特性的时候,它就变成了那个组件实例的一个属性。为了给博文组件传递一个标题,我们可以用一个 props 选项将其包含在该组件可接受的 prop 列表中:

js代码:

Vue.component('blog-post', {
props: ['title'],
template: '<h3>{{ title }}</h3>'
})

一个组件默认可以拥有任意数量的 prop,任何值都可以传递给任何 prop。在上述模板中,你会发现我们能够在组件实例中访问这个值,就像访问 data 中的值一样。

一个 prop 被注册之后,你就可以像这样把数据作为一个自定义特性传递进来:

html代码:

<blog-post title="My journey with Vue"></blog-post>
<blog-post title="Blogging with Vue"></blog-post>
<blog-post title="Why Vue is so fun"></blog-post>

效果图

然而在一个典型的应用中,你可能在 data 里有一个博文的数组:

js代码:

new Vue({
el: '#blog-post-demo',
data: {
posts: [
{ id: 1, title: 'My journey with Vue' },
{ id: 2, title: 'Blogging with Vue' },
{ id: 3, title: 'Why Vue is so fun' }
]
}
})

并想要为每篇博文渲染一个组件:

html代码:

<blog-post
v-for="post in posts"
v-bind:key="post.id"
v-bind:title="post.title"
></blog-post>

如上所示,你会发现我们可以使用 v-bind 来动态传递 prop。这在你一开始不清楚要渲染的具体内容,比如从一个 API 获取博文列表的时候,是非常有用的。

到目前为止,关于 prop 你需要了解的大概就这些了,如果你阅读完本页内容并掌握了它的内容,我们会推荐你再回来把 prop 读完。

举例:公司客服,每点击一次,表示接待了一个客户

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<!--使用自定义组件tankuang-->
<!--item是每一次for循环的元素,将值赋值给name-->
<!--动态赋值使用v-bind,赋值给子组件-->
<tankuang v-for="item in list" v-bind:name="item"></tankuang>
</div>
<script>
//定义常量tankuangComponent
const tankuangComponent = {
//默认渲染,使用{{name}}{{count}}
template:`<button v-on:click="ttt">{{name}}{{count}}</button>`,
//使用props声明 我这个组件需要外边给我传一个字符串格式的name变量
//父子传值,使用props
props:{
//声明变量name,类型必须是String
//name:String做了一次校验,通过之后,才会给上面的{{name}}
name:String
},
data:function(){
return {
count: 0
}
},
methods:{
ttt:function(){
//自增
this.count +=1
}
}
}
//注册自定义的局部组件
var app = new Vue({
el:"#app",
data:{
//客服列表
list:[
'1號-林志玲',
'2号-柳岩',
'3호-宋慧乔',
]
},
//components表示组件
components:{
tankuang:tankuangComponent
},
});
</script>
</body>
</html>

刷新网页,效果如下:

父子传值,一定要使用props。这里说的父,指的是网页整体。子,指的是tankuang局部组件。

网页点击之后,需要将值传给button按钮,最终展示数据!

关键步骤如下:

1.定义了一个列表list,使用for循环遍历每一个元素

2.将值赋给item

3.item动态赋值给name

4.name传给props里面的name,name必须是字符串。

5.通过校验后,将值传给{{name}},前端来渲染。

子组件向父组件传值

需要统计每一个客服,一共接待了多少客户。每增加一个客户,总数加1。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<p>本月接待客户数:{{totalCount}}</p>
<!--使用自定义组件tankuang-->
<!--item是每一次for循环的元素,将值赋值给name-->
<!--动态赋值使用v-bind,赋值给子组件-->
<tankuang v-for="item in list" v-bind:name="item"></tankuang>
</div>
<script>
//定义常量tankuangComponent
const tankuangComponent = {
//默认渲染,使用{{name}}{{count}}
template:`<button v-on:click="ttt">{{name}}{{count}}</button>`,
//使用props声明 我这个组件需要外边给我传一个字符串格式的name变量
//父子传值,使用props
props:{
//声明变量name,类型必须是String
//name:String做了一次校验,通过之后,才会给上面的{{name}}
name:String
},
data:function(){
return {
//每一个客服自己的
count: 0
}
},
methods:{
ttt:function(){
//自增
this.count +=1
}
}
}
//注册自定义的局部组件
var app = new Vue({
el:"#app",
data:{
totalCount: 0, //总数
//客服列表
list:[
'1號-林志玲',
'2号-柳岩',
'3호-宋慧乔',
]
},
//components表示组件
components:{
tankuang:tankuangComponent
},
});
</script>
</body>
</html>

刷新网页,效果如下:

发现一个问题,总数没有变动?为什么呢?

因为这一段代码

methods:{
ttt:function(){
//自增
this.count +=1
}
}

改变时,没有把外面的总数加1。那么如何改变父层的元素呢?需要使用自定义事件

自定义事件

事件名

跟组件和 prop 不同,事件名不存在任何自动化的大小写转换。而是触发的事件名需要完全匹配监听这个事件所用的名称。举个例子,如果触发一个 camelCase 名字的事件:

js代码:

this.$emit('myEvent')

则监听这个名字的 kebab-case 版本是不会有任何效果的:

html代码:

<my-component v-on:my-event="doSomething"></my-component>

跟组件和 prop 不同,事件名不会被用作一个 JavaScript 变量名或属性名,所以就没有理由使用 camelCase 或 PascalCase 了。并且 v-on 事件监听器在 DOM 模板中会被自动转换为全小写 (因为 HTML 是大小写不敏感的),所以 v-on:myEvent 将会变成 v-on:myevent——导致 myEvent 不可能被监听到。

因此,我们推荐你始终使用 kebab-case 的事件名

举例:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<p>本月接待客户数:{{totalCount}}</p>
<!--使用自定义组件tankuang-->
<!--item是每一次for循环的元素,将值赋值给name-->
<!--动态赋值使用v-bind,赋值给子组件-->
<!--自定义事件jiedai,执行方法add-->
<tankuang v-for="item in list" v-bind:name="item" v-on:jiedai="add"></tankuang>
</div>
<script>
//定义常量tankuangComponent
const tankuangComponent = {
//默认渲染,使用{{name}}{{count}}
template:`<button v-on:click="ttt">{{name}}{{count}}</button>`,
//使用props声明 我这个组件需要外边给我传一个字符串格式的name变量
//父子传值,使用props
props:{
//声明变量name,类型必须是String
//name:String做了一次校验,通过之后,才会给上面的{{name}}
name:String
},
data:function(){
return {
//每一个客服自己的
count: 0
}
},
methods:{
ttt:function(){
//自增
this.count +=1
//告诉外层,总数加1,执行方法jiedai。$emit是关键字,表示自定义事件
this.$emit('jiedai')
}
}
}
//注册自定义的局部组件
var app = new Vue({
el:"#app",
data:{
totalCount: 0, //总数
//客服列表
list:[
'1號-林志玲',
'2号-柳岩',
'3호-宋慧乔',
]
},
//components表示组件
components:{
tankuang:tankuangComponent
},
//方法
methods:{
//增加总数
add:function () {
//总数自增
this.totalCount +=1
}
}
});
</script>
</body>
</html>

刷新网页,效果如下:

这样设计的好处是,子组件只能修改自己的。如果需要修改父组件,必须通过自定义事件来完成!

插槽

插槽内容

Vue 实现了一套内容分发的 API,这套 API 基于当前的 Web Components 规范草案,将 <slot> 元素作为承载分发内容的出口。

它允许你像这样合成组件:

html代码:

<navigation-link url="/profile">
Your Profile
</navigation-link>

然后你在 <navigation-link> 的模板中可能会写为:

html代码:

<a
v-bind:href="url"
class="nav-link"
>
<slot></slot>
</a>

当组件渲染的时候,这个 <slot> 元素将会被替换为"Your Profile"。插槽内可以包含任何模板代码,包括 HTML:

<navigation-link url="/profile">
<!-- 添加一个 Font Awesome 图标 -->
<span class="fa fa-user"></span>
Your Profile
</navigation-link>

甚至其它的组件:

html代码:

<navigation-link url="/profile">
<!-- 添加一个图标的组件 -->
<font-awesome-icon name="user"></font-awesome-icon>
Your Profile
</navigation-link>

如果 <navigation-link> 没有包含一个 <slot> 元素,则任何传入它的内容都会被抛弃。

举例:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<p>本月接待客户数:{{totalCount}}</p>
<!--使用自定义组件tankuang-->
<!--item是每一次for循环的元素,将值赋值给name-->
<!--动态赋值使用v-bind,赋值给子组件-->
<!--自定义事件jiedai,执行方法add-->
<tankuang v-for="item in list" v-bind:name="item" v-on:jiedai="add">
<span>上班了!</span>
</tankuang>
</div>
<script>
//定义常量tankuangComponent
const tankuangComponent = {
//默认渲染,使用{{name}}{{count}}
//必须使用闭合标签,比如div,p...等等
template: `<div><button v-on:click="ttt">{{name}}{{count}}</button>
<slot></slot>
</div>`,
//使用props声明 我这个组件需要外边给我传一个字符串格式的name变量
//父子传值,使用props
props: {
//声明变量name,类型必须是String
//name:String做了一次校验,通过之后,才会给上面的{{name}}
name: String
},
data: function () {
return {
//每一个客服自己的
count: 0
}
},
methods: {
ttt: function () {
//自增
this.count += 1
//告诉外层,总数加1,执行方法jiedai。$emit是关键字,表示自定义事件
this.$emit('jiedai')
}
}
}
//注册自定义的局部组件
var app = new Vue({
el: "#app",
data: {
totalCount: 0, //总数
//客服列表
list: [
'1號-林志玲',
'2号-柳岩',
'3호-宋慧乔',
]
},
//components表示组件
components: {
tankuang: tankuangComponent
},
//方法
methods: {
//增加总数
add: function () {
//总数自增
this.totalCount += 1
}
}
});
</script>
</body>
</html>

刷新网页,效果如下:

注意:template必须包含一个<slot> 元素,否则<tankuang></tankuang>中的内容会被丢弃掉,网页不展示!

网页无法展示。template必须使用闭合标签,否则报错!

具名插槽

有些时候我们需要多个插槽。例如,一个假设的 <base-layout> 组件多模板如下:

html代码:

<div class="container">
<header>
<!-- 我们希望把页头放这里 -->
</header>
<main>
<!-- 我们希望把主要内容放这里 -->
</main>
<footer>
<!-- 我们希望把页脚放这里 -->
</footer>
</div>

对于这样的情况,<slot> 元素有一个特殊的特性:name。这个特性可以用来定义额外的插槽:

<div class="container">
<header>
<slot name="header"></slot>
</header>
<main>
<slot></slot>
</main>
<footer>
<slot name="footer"></slot>
</footer>
</div>

在向具名插槽提供内容的时候,我们可以在一个父组件的 <template> 元素上使用 slot 特性:

<base-layout>
<template slot="header">
<h1>Here might be a page title</h1>
</template> <p>A paragraph for the main content.</p>
<p>And another one.</p> <template slot="footer">
<p>Here's some contact info</p>
</template>
</base-layout>

另一种 slot 特性的用法是直接用在一个普通的元素上:

<base-layout>
<h1 slot="header">Here might be a page title</h1> <p>A paragraph for the main content.</p>
<p>And another one.</p> <p slot="footer">Here's some contact info</p>
</base-layout>

我们还是可以保留一个未命名插槽,这个插槽是默认插槽,也就是说它会作为所有未匹配到插槽的内容的统一出口。上述两个示例渲染出来的 HTML 都将会是:

<div class="container">
<header>
<h1>Here might be a page title</h1>
</header>
<main>
<p>A paragraph for the main content.</p>
<p>And another one.</p>
</main>
<footer>
<p>Here's some contact info</p>
</footer>
</div>

举例:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- 开发环境版本,包含了有帮助的命令行警告 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
</head>
<body>
<div id="app">
<p>本月接待客户数:{{totalCount}}</p>
<!--使用自定义组件tankuang-->
<!--item是每一次for循环的元素,将值赋值给name-->
<!--动态赋值使用v-bind,赋值给子组件-->
<!--自定义事件jiedai,执行方法add-->
<tankuang v-for="item in list" v-bind:name="item" v-on:jiedai="add">
<!--多个元素使用template包裹-->
<template slot="he">
<span>上班了!</span>
<span>打卡!</span>
</template>
<!--使用具名插槽-->
<span slot="heng">哼哼!</span>
</tankuang>
</div>
<script>
//定义常量tankuangComponent
const tankuangComponent = {
//默认渲染,使用{{name}}{{count}}
//必须使用闭合标签,比如div,p...等等
//slot定义name属性,表示具名插槽
template: `<div><button v-on:click="ttt">{{name}}{{count}}</button>
<slot name="he"></slot>
<slot name="heng"></slot>
</div>`,
//使用props声明 我这个组件需要外边给我传一个字符串格式的name变量
//父子传值,使用props
props: {
//声明变量name,类型必须是String
//name:String做了一次校验,通过之后,才会给上面的{{name}}
name: String
},
data: function () {
return {
//每一个客服自己的
count: 0
}
},
methods: {
ttt: function () {
//自增
this.count += 1
//告诉外层,总数加1,执行方法jiedai。$emit是关键字,表示自定义事件
this.$emit('jiedai')
}
}
}
//注册自定义的局部组件
var app = new Vue({
el: "#app",
data: {
totalCount: 0, //总数
//客服列表
list: [
'1號-林志玲',
'2号-柳岩',
'3호-宋慧乔',
]
},
//components表示组件
components: {
tankuang: tankuangComponent
},
//方法
methods: {
//增加总数
add: function () {
//总数自增
this.totalCount += 1
}
}
});
</script>
</body>
</html>

刷新网页,效果如下:

总结:

1. 父组件 -传值-> 子组件
v-bind:变量='值'
注意事项:
子组件接收值需要在props里面声明 2. 子组件 -传值-> 父组件
触发自定义事件的方式,为了确保父组件的值不会被子组件直接修改
子组件触发事件:
this.$emit('事件名')
父组件监听事件:
v-on:事件名='处理的方法' 3. 插槽和带名字的插槽
引用子组件的时候,我可以传递一些额外的标签元素

二、前端开发工具包

node.js

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。 
Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。 
Node.js 的包管理器 npm,是全球最大的开源库生态系统。

官网:

https://nodejs.org/en/

下载最新版本

安装,疯狂点击下一步,就可以了!

安装完成后,打开cmd控制台,输入命令node -v 查看版本:

C:\Users\xiao>node -v
v10.7.0

本质上还是JS,跑在V8引擎上的,让JS能够和操作系统进行交互
和Python\php类似的脚本语言

npm

npm 是 JavaScript 世界的包管理工具,并且是 Node.js 平台的默认包管理工具。通过 npm 可以安装、共享、分发代码,管理项目依赖关系。

NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题

打开cmd控制台,输入命令npm -v 查看版本:

C:\Users\xiao>npm -v
6.1.0

类似于Python中的pip,帮助我们解决包和包之间版本的依赖关系

webpack

webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。

安装webpack,使用一下命令:

npm install webpack -g
npm install webpack-cli -g

关闭cmd窗口,再次打开,查看版本

C:\Users\xiao>webpack -v
4.16.2

准备文件

新建a.js

(function(){
//定义全局变量
//这种方式经常被用到一个匿名函数执行后将一些函数公开到全局
window.ryf = 'ruanyifeng';
})();

一般定义需要被导入的变量或者方法,使用function定义。

如果直接使用var 声明,那么html导入js之后,就直接有了全局变量,可能会影响当前html的全局变量,会被覆盖!

推荐使用方法,调用时,才使用变量

新建test.html,引入a.js

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--导入a.js-->
<script src="a.js"></script>
<script>
console.log(ryf); //打印ryf变量
</script>
</body>
</html>

访问网页,效果如下:

发现Console打印出变量了

Nodejs 编写模块相当的自由,开发者只需要关注 require,exports,module 等几个变量就足够,而为了保持模块的可读性,很推荐把不同功能的代码块都写成独立模块,减少各模块耦合。

module.exports

用来导出代码,初始值为一个空对象 {}

修改a.js

(function(){
//定义全局变量
//这种方式经常被用到一个匿名函数执行后将一些函数公开到全局
window.ryf = 'ruanyifeng';
})(); //当前这个包 向外提供一个变量:ryf
//module.exports 则用来导出代码,初始值为一个空对象 {}
module.exports = {
ryf: ryf
}

require

webpack中可以写commonjs格式的require同步语法

经典的commonjs同步语法

新建b.js

var obj = require('./a.js');

此时webpack会将a.js打包进引用它的文件中,这是最普遍的情形!

正式使用Webpack

webpack可以在终端中使用,在基本的使用方法如下:

# {extry file}出填写入口文件的路径,本文中就是上述main.js的路径,
# {destination for bundled file}处填写打包文件的存放路径
# 填写路径的时候不用添加{}
webpack {entry file} {destination for bundled file}

指定入口文件后,webpack将自动识别项目所依赖的其它文件,不过需要注意的是如果你的webpack不是全局安装的,那么当你在终端中使用此命令时,需要额外指定其在node_modules中的地址。

在终端中输入如下命令:

必须先进入到b.js文件的目录

C:\Users\xiao>e:
C:\Users\xiao>cd E:\python_script\Vue

再执行命令

webpack b.js

效果如下:

由于没有指定打包文件的存放路径,执行完成之后,会在当前目录生成dist目录,里面有一个文件main.js

查看main.js

!function(e){var r={};function t(n){if(r[n])return r[n].exports;var o=r[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,t),o.l=!0,o.exports}t.m=e,t.c=r,t.d=function(e,r,n){t.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:n})},t.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},t.t=function(e,r){if(1&r&&(e=t(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(t.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var o in e)t.d(n,o,function(r){return e[r]}.bind(null,o));return n},t.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(r,"a",r),r},t.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},t.p="",t(t.s=0)}([function(e,r,t){t(1)},function(e,r){window.ryf="ruanyifeng",e.exports={ryf:ryf}}]);

发现代码被压缩成一行了,代码被打乱了,看不懂的

修改test.html,改为导入mian.js

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<!--导入main.js-->
<script src="dist/main.js"></script>
<script>
console.log(ryf); //打印ryf变量
</script>
</body>
</html>

刷新网页,效果如下:

发现变量依然有效!

python 全栈开发,Day90(Vue组件,前端开发工具包)的更多相关文章

  1. Python全栈之路----常用模块----软件开发目录规范

    目录基本内容 log  #日志目录 conf  #配置目录 core/luffycity  #程序核心代码目录  #luffycity 是项目名,建议用小写 libs/modules  #内置模块 d ...

  2. 想成为Python全栈开发工程师必须掌握的技能

    什么是Python全栈工程师? 即从前端页面的实现,到后台代码的编写,再到数据库的管理,一人可以搞定一个公司网站的所有事情,真正实现全栈开发. 全栈只是个概念 也分很多种类 真正的全栈工程师涵盖了we ...

  3. Python全栈之路----目录

    Module1 Python基本语法 Python全栈之路----编程基本情况介绍 Python全栈之路----常用数据类型--集合 Module2 数据类型.字符编码.文件操作 Python全栈之路 ...

  4. python 全栈开发,Day98(路飞学城背景,django ContentType组件,表结构讲解)

    昨日内容回顾 1. 为什么要做前后端分离? - 前后端交给不同的人来编写,职责划分明确. - API (IOS,安卓,PC,微信小程序...) - vue.js等框架编写前端时,会比之前写jQuery ...

  5. python 全栈开发,Day107(CRM初始,权限组件之权限控制,权限系统表设计)

    一.CRM初始 CRM,客户关系管理系统(Customer Relationship Management).企业用CRM技术来管理与客户之间的关系,以求提升企业成功的管理方式,其目的是协助企业管理销 ...

  6. python 全栈开发,Day99(作业讲解,DRF版本,DRF分页,DRF序列化进阶)

    昨日内容回顾 1. 为什么要做前后端分离? - 前后端交给不同的人来编写,职责划分明确. - API (IOS,安卓,PC,微信小程序...) - vue.js等框架编写前端时,会比之前写jQuery ...

  7. Python 全栈开发【第0篇】:目录

    Python 全栈开发[第0篇]:目录   第一阶段:Python 开发入门 Python 全栈开发[第一篇]:计算机原理&Linux系统入门 Python 全栈开发[第二篇]:Python基 ...

  8. python 全栈开发之路 day1

    python 全栈开发之路 day1   本节内容 计算机发展介绍 计算机硬件组成 计算机基本原理 计算机 计算机(computer)俗称电脑,是一种用于高速计算的电子计算机器,可以进行数值计算,又可 ...

  9. python 全栈开发,Day117(popup,Model类的继承,crm业务开发)

    昨日内容回顾 第一部分:权限相关 1. 权限基本流程 用户登录成功后获取权限信息,将[权限和菜单]信息写入到session. 以后用户在来访问,在中间件中进行权限校验. 为了提升用户体验友好度,在后台 ...

随机推荐

  1. P4315 月下“毛景树”

    P4315 月下"毛景树" 题目描述 毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园. 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里. 爬啊爬~爬啊爬 ...

  2. Hadoop基础-HDFS安全管家之Kerberos实战篇

    Hadoop基础-HDFS安全管家之Kerberos实战篇 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 我们都知道hadoop有很多不同的发行版,比如:Apache Hadoop ...

  3. vue基础篇---class样式绑定

    因为class的绑定在实际的工作中会经常用到.所以特意记录一下,有好几种方法. 对象绑定方法,另外一个值来控制显示隐藏 <!DOCTYPE html> <html lang=&quo ...

  4. JSTL中forEach标签应用示例【转】【补】

    forEach样例 <%@ page language="java" import="java.util.*" pageEncoding="ut ...

  5. spring web.xml 难点配置总结【转】

    web.xml web.xml是所有web项目的根源,没有它,任何web项目都启动不了,所以有必要了解相关的配置. ContextLoderListener,ContextLoaderServlet, ...

  6. 绕过/*,web.xml直接访问jsp【转】

    web.xml中如果配置了/* 全匹配,那么不能用servet去响应页面返回了,因为全都被会/*拦截. <servlet> <servlet-name>validateAuth ...

  7. Html-Css 从入门到放弃(一)基础知识

    注意要点: 1.ID属性不要以数字开头,数字开头的ID在 Mozilla/Firefox 浏览器中不起作用. 2.class 选择器用于描述一组元素的样式,class 选择器有别于id选择器,clas ...

  8. 微信公众号绑定服务器 Flask版

    python 代码 from flask import Flask, request from flask_cors import CORS app = Flask(__name__) app.app ...

  9. Storm WordCount Topology学习

    1,分布式单词计数的流程 首先要有数据源,在SentenceSpout中定义了一个字符串数组sentences来模拟数据源.字符串数组中的每句话作为一个tuple发射.其实,SplitBolt接收Se ...

  10. toFixed方法的bug

    最近在工作过程中碰到一个隐藏的bug,经调试发现竟然是toFixed函数不可靠的结果引起的.后端同学在处理价格比较的时候,用foFixed进行价格的四舍五入之后,竟然发现比较的结果有问题: 大家都知道 ...