文章目录
01 Vue的基本指令
03 动态绑定
1. v-bind的基本使用
一般形式:v-bind:属性名="值"
简写形式::属性名="值"
如:
<img v-bind:src="imgUrl" alt="">
2. v-bind绑定class属性
3. v-bind绑定style属性
04 计算属性computed
计算属性, 就是用来进行属性的组合利用的
例如我们有一个firstName , 和一个lastName , 此时可以使用插值表达式 {{firstName + ’ ’ + lastName }} 来进行组合, 但是这么做的可读性与重复利用性又十分糟糕
但是我们可以利用methods方法来进行属性的组合, 但是这么做会带来一定额外的开销, 并且我们可以注意到我们对firstName 和lastName的操作不会涉及到其他任何属性, 就好像他们是一个属性一样, 所以就有了计算属性
1. 实现属性的组合的三种方法
实现属性组合有三种方法
- 插值表达式中直接写
如:{{firstName }} {{lastName}}
- 在methods中写getXXX方法 , 然后利用mastache语法 {{getXXX()}}调用, 注意这里需要加括号
使用: {{getFullName()}}
methods: {
getFullName(){return this.firstName+this.lastName}
}
- 第三种方式就是, 定义computed 属性(本质是一个属性)
计算属性的本质是一个属性, 详情请看本节的 2. , 因此使用时与methods不同 , computed属性不需加()
2. 计算属性基本使用
与data
, methods
, el
属性相同, computed
属性定义在Vue对象中, 可以使用一个函数来给他的属性赋值, 如下
const app = new Vue(){
el: "#app",
data: {
fristName: "A",
lastName: "B"
} ,
//------------------
computed:{
fullName: function(){
return firstName + " " + lastName
}
//-------------------
}
}
3. 计算属性的本质
其实计算属性的完整写法如下 , 也就是说, 计算属性本质上是一个对象属性
computed: {
fullName: {
get : function(){
},
set: function(){
}
}
}
但是我们一般不希望别人去set, 所以我们一般不会定义set方法
computed: {
fullName: {
get : function(){
}
}
}
但是这么 写有有些麻烦, 所以就有了简便写法
computed: {
fullName: function(){}
}
4. computed 和 methods的区别
computed 和 methods 都能够实现属性的组合, 他们的区别在于computed会对属性值进行缓存, 每次调用computed属性, 他只会调用一次get方法, 而methods会被调用多次
考虑下面的代码, 在chrome 开发者工具中多次调用, 可以看到如上讨论的结果
computed: {
//computed只会被调用一次
fullName:function(){
console.log("computed called")
return this.firstName + this.lastName
}
},
methods:{
//methods会被调用多次
getFullName(){
console.log("method called")
return this.firstName + this.lastName
}
练习1-获取和设置姓名
假设data中有以下数据
data:{
familyName : “张”, //姓
lastName: “三” , //名
}
写 fullName 的set 和 get方法(假设姓只有一个字并且总是字符串第一个字符), 利用 Google chrome 调试工具, app.name = “张三” , 来设置一个姓名, 利用app.name来获取姓名进行调试
如:
app.fullName // 显示 张三
app.fullName = “李四”
//设置 familyName 于 lastName
05 Vue中的事件监听v-on
1. v-on的基本使用
v-on
指令的一般语法是
v-on:事件名="函数名[(参数1,参数2,...]"
如:
<h1 v-on:click="cleack">v-on非简写</h1>
v-on
指令有语法糖@
, 即
@事件名="函数名[参数1,参数2,...]"
如:
<h1 @click="cleack">v-on简写</h1>
v-on语法糖:@指令
.stop: 停止冒泡事件
.prevent: 阻止默认事件
.key: 按下某个键
2. v-on参数传递
- 调用不加括号时, 默认函数参数第一个为event事件对象
<!--不加参数时, 函数的第一个参数为event 对象, 其他(如果有的话)为undefined-->
<button @click="btn1Click">不加参数</button>
- 调用加括号时, 按指定传入, 如果想要事件对象, 需要在参数列表中写
$event
<!-- 加参数时, 如果不需要添加event对象, 直接再括号中写参数列表即可-->
<button @click="btn2Click('dslkjflsdkfj', 234)">加参数不要event对象</button>
<!-- 加参数时, 如果想添加event对象, 则需要在括号中写$event-->
<button @click="btn3Click('str', $event , 12345)">加参数要Event对象</button>
3. v-on修饰符
常用修饰符如下
@事件.stop
: 阻止冒泡事件@事件.prevent
: 阻止默认事件@keyUp/keyDown.键位名称
: 监听键盘事件
示例如下:
<!-- 利用.stop来取消冒泡事件-->
<div @click="div1Click">
<button @click.stop="btn1Click">不冒泡</button>
<button @click="btn1Click">冒泡</button>
</div>
<!--2. 利用prevent来取消默认事件, 如提交按钮的提交事件-->
<form action="www.baidu.com">
<input type="submit" @click.prevent="mySubmit" value="取消提交默认事件" >
<input type="submit" value="不取消的提交">
<!-- 3.@keyUp.enter 来监听回车事件-->
<input type="text" @keyup.enter="keyupEnter">
</form>
注意:
keyUp
这种键盘监听事件一般只能在input中使用
06 条件判断
1.v-if/ v-else/v-else-if 的基本使用
vue条件判断的基本语法是:
v-if="布尔表达式"
v-else-if="布尔表达式"
v-else
示例如下
<div id="app">
<!-- 1. v-if/v-else-if="布尔表达式"/v-else-->
<h1 v-if="score>=90">优秀</h1>
<h1 v-else-if="score>=80">良好</h1>
<h1 v-else-if="score>=60">及格</h1>
<h1 v-else>不及格</h1>
</div>
2. vue中的DOM渲染机制及Key指令
看下面的案例, 在点击切换时, input框明明不是同一个, 切换后的内容却相同
切换前:
切换后:
<div id="app">
<span id="username" v-if="username">
<span>用户账号</span>
<input type="text" placeholder="用户账号">
</span>
<span id="email" v-if="email">
<span>用户邮箱</span>
<input type="text" placeholder="用户邮箱">
</span>
<!--点击切换后发现, input框明明不是同一个, 内容却相同, 原因是vue内部为了节省性能, 会尽可能的复用DOM元素-->
<button @click="toggleType">切换类型</button>
</div>
究其根本, 是因为vue内部为了节省性能资源, 会尽可能的渲染元素
官方文档: 虚拟DOM
解决方案:
添加key
指令, 作为DOM唯一标识, 就不会再复用
<div id="app">
<span id="username" v-if="username">
<span>用户账号</span>
<input type="text" placeholder="用户账号" key="username">
</span>
<span id="email" v-if="email">
<span>用户邮箱</span>
<input type="text" placeholder="用户邮箱" key="email">
</span>
<!--点击切换后发现, input框明明不是同一个, 内容却相同, 原因是vue内部为了节省性能, 会尽可能的复用DOM元素-->
<button @click="toggleType">切换类型</button>
</div>
这里涉及到virtualDOM底层问题, 目前我们不需过度深究
3. v-show 与 v-if
v-show
指令与v-if
指令语法相同 , 并且可以使用v-else与v-else-if
<div id="app">
<!-- 1. v-show="布尔表达式"-->
<h1 v-show="score>=90">优秀</h1>
<h1 v-else-if="score>=80">良好</h1>
<h1 v-else-if="score>=60">及格</h1>
<h1 v-else>不及格</h1>
</div>
区别在于
- 当使用
v-show
时, 若条件为false
仅仅只是将元素的display
属性设置为none
- 而当使用
v-if
时, 如果条件为false
元素的DOM根本不会存在
根据以上的特点 - 当一个元素需要频繁的在显示和隐藏直接切换时, 就用
v-show
- 当一个元素只需要渲染一次或少次的时候就用
v-if
★注意:上面的案例中的
v-else-if
/v-else
与v-if
一样, 如果为false
不会存在
07 v-for循环遍历
1. v-for遍历数组
v-for 遍历数组有两种方法:
item in 数组名
: 得到的是值(item , index ) in 数组名
: 得到的是值和索引
<div id="app">
<ul>
<!-- 1. 如果只拿一个拿的是值-->
<li v-for="item in movies">{{item}}</li>
<!-- 2. 括号获取索引-->
<li v-for="(item , index) in movies">{{index + '.'+item }}</li>
</ul>
</div>
2. v-for遍历对象
v-for
遍历对象有三种语法:
value in 对象名
: 获取每个对象的值(value , key) in 对象名
: 获取每个对象的值和键(value, key , index) in 对象名
: 获取每个对象的值、键、索引
示例如下:
<div id="app">
<ul>
<!-- 1. 如果只拿一个拿的是值-->
<li v-for="item in obj">{{item}}</li>
<!-- 2. 两个参数获取值和键-->
<li v-for="(value , key) in obj">{{key + ":"+value }}</li>
<!-- 3. 三个参数获取值、键、索引-->
<li v-for="(value , key,index) in obj">{{index + '.'+key + ":"+value }}</li>
</ul>
</div>
3. v-for与key
key属性的作用就是提高DOM渲染的速率, 要尽量保证元素key的唯一
vue官方建议: 在使用v-for时, 最好给每个元素添加一个
key
属性
4. 数组中哪些方法为响应式
不是所有的 JavaScript
数组方法都是响应式的, 如利用数组索引改变元素就不会更新浏览器的DOM
push
: 在数组末尾插入元素pop
: 在数组末尾删除元素shift
: 在数组开头删除元素unshift
: 在数组开头插入元素sort
: 对数组进行排序reverse
: 对数组进行逆序splice(a1,a2,a3)
: 在a1
位置删除a2
个元素并且插入a3
元素
08-Javascript高阶函数
1. 数组的遍历
数组的高阶遍历有两种方式:
- Let …in …: 索引遍历
- let …of …元素遍历
//1. 方式1
let totalPrice = 0;
for(let i in this.books){
totalPrice += this.books[i].price * this.books[i].count;
}
//方式2
let totalPrice2 = 0;
for (let book of this.books){
totalPrice2 += book.price * book.count
}
2. filter函数
filter(Function)
: 用来获得掉符合Function条件的内容, Function为返回布尔值的函数
如过滤n大于100的数字, 获得n<100的数字
let nums = [1,1244,192,93,34,19042,24,194]
nums.filter(function(n){
return n < 100
})
可以直接利用Lambda表达式
let newNums1 = nums.filter(n => n < 100)
3. map函数
map(Function(n))
: map用来根据Function生成新的数组, 它会对数组中每一个元素进行遍历, n
为输入的每个元素, 随后对n进行更改, 更改的值为返回值
如将数组中每个元素乘2
let newNums1 =newNums.map(n => n*2)
4. reduce函数
reduce(Function(preValue, n), initPreValue)
: reduce
会对数组中的每个元素进行遍历
preValue
: 上次Function 的返回值n
: 每次遍历时数组的元素initPreValue
: 初始时preValue的值
如计算数组的和
let total = newNums1.reduce( (preValue, n)=> preValue + n, 0 )
上面三个函数可以写在一行直接得到:
nums.filter(n => n < 100).map(n => n*2).reduce( (preValue , n ) => preValue + n, 0 );
09 v-model
01-v-model基本使用
v-model
指令用来进行数据的双向绑定
<!-- 1. v-model="表达式" 实现数据的双向绑定-->
<input type="text" v-model="message">
{{message}}
当文本框内容更改时, message的内容也进行更改
02-v-model的本质
v-model
的本质其实就是v-on
和v-bind
的结合, 如我们可以利用 v-on:input
事件与v-bind
指令来实现数据的双向绑定
<!-- 1. v-model 本质是两个指令的结合:v-on 和 v-bind -->
<input type="text" :value="message" v-on:input="message = $event.target.value">
{{message}}
03-v-model与radio
当v-model
中的值为true
时代表选中
<!-- name让radio变为单选-->
<!-- value与v-model变量相同代表选中-->
<label for="">
<input type="radio" id="male" name="sex" value="男" v-model="sex"> 男
</label>
<label for="">
<input type="radio" id="female" name="sex" value="女" v-model="sex"> 女
</label>
04-v-model结合checkbox类型
单选: v-model中填true代表选中
多选: v-model中填数组, input中要有value值
- 当数据元素中存在对应value 的元素时代表选中
<!--1. checkbox单选框对应布尔值, 当v-model中的变量值为true时表示选中-->
<div id="app">
<label for="license">
<input type="checkbox" id="license" v-model="isAgree">同意XXX协议
<!-- button的disabled表示不可点击-->
<div><button :disabled="!isAgree">下一步</button></div>
</label>
<!--2. checkbox单选框对应数组-->
<!-- 当选中时, value值添加到数组中-->
<!-- 当value值存在在数组中时表示选中-->
<label for="">
<input class="hobbies" type="checkbox" value="篮球" v-model="hobbies">篮球
<input class="hobbies" type="checkbox" value="足球" v-model="hobbies">足球
<input class="hobbies" type="checkbox" value="羽毛球" v-model="hobbies">羽毛球
<input class="hobbies" type="checkbox" value="乒乓球" v-model="hobbies">乒乓球
<!-- button的disabled表示不可点击-->
<div >您的爱好是{{hobbies}}</div>
</label>
<!-- 3. 我们可以利用v-bind绑定的形式来写多选的checkbox等-->
<label v-for="item in allHobbies" for="item">
<input type="checkbox" :value="item" id="item" v-model="hobbies">{{item}}
</label>
</div>
05-v-model结合select类型
select类型与checkbox类似, 同样的, 多选时, option标签中要有能与数组对应的value属性
<!-- 1. select 单选-->
<!-- 当value值与变量相同时表示选中-->
<select name="abc" v-model="fruit">
<option value="苹果">苹果</option>
<option value="香蕉">香蕉</option>
<option value="葡萄">葡萄</option>
<option value="橘子">橘子</option>
</select>
<div>选中: {{fruit}}</div>
<!-- 2. select多选-->
<!-- 当数组中存在与value相同的元素时表示选中-->
<select v-model="fruits" multiple>
<option value="苹果">苹果</option>
<option value="香蕉">香蕉</option>
<option value="葡萄">葡萄</option>
<option value="橘子">橘子</option>
</select>
<div>选中: {{fruits}}</div>
</div>
06-v-model结合v-for
<!-- 3. 我们可以利用v-bind绑定的形式来写多选的checkbox等-->
<label v-for="item in allHobbies" for="item">
<input type="checkbox" :value="item" id="item" v-model="hobbies">{{item}}
</label>
07-v-model修饰符的使用
添加修饰符的一般语法: v-model.修饰符=""
常用修饰符如下
<div id="app">
<!-- 1. lazy:懒加载, 使得当输入失去焦点或者按下回车时才进行数据的绑定-->
<input type="text" v-model.lazy="message">
<div>{{message}}</div>
<input type="text" v-model.number="num">
<div>{{num}}类型: {{typeof num}}</div>
<!-- 3. trim: 去除前后的空格-->
<!-- 通过console查看, 未去除前后空格-->
<!-- <input type="text" v-model="strTrim">-->
<!-- 通过console查看, 的确去除前后空格s-->
<input type="text" v-model.trim="strTrim">
<div>{{strTrim}}</div>
</div>
10 组件化-组件的创建
01-组件化实现和使用步骤
组件化分为三个步骤
- 利用
Vue.extend(options)
创建组件构造器对象 - 注册组件, 有两种方法
- 全局组件: 利用
Vue.component('标签名' , 构造器对象)注册组件
- 局部组件: 在Vue实例中使用
template
属性来进行注册Vue({ template:{ 标签名:组件构造器 } })
- 全局组件: 利用
- 使用组件
注意:
组件只能在Vue实例中使用
- 组件的模板必须只能拥有一个根元素
下面写法正确✔
<template id="counter"> <h2>当前计数:{{count}}</h2> </template>
下面写法 错误:
X
<template id="counter"> <h2>当前计数:{{count}}</h2> <h2>当前计数:{{count}}</h2> </template>
实例代码如下
//1. 创建组件构造器对象
const cpn = Vue.extend({
template:`
<div>
<h1>我是组件</h1>
<p>我是组件的内容</p>
</div>
`
})
//2. 注册组件(全局组件, 在任何Vue实例中都可以使用)
Vue.component("mcpn" , cpn)
02-全局组件与局部组件
全局组件: 能在所有Vue实例中使用的组件, 使用Vue.component注册的组件为全局组件
局部组件: 只能在注册的Vue实例中使用的组件, 在components
属性中进行注册
局部组件的注册:
//2. 注册组件(全局组件, 在任何Vue实例中都可以使用)
// Vue.component("mcpn" , cpn)
const app = new Vue({
el:"#app",
data:{
counter: 0,
message: "你好啊",
movies:["movie1" ,"movie2", "movie3", "movie4"]
},
methods:{
},
components:{
//注册局部组件: 标签名:组件构造器对象
mcpn:cpn
}
})
03-父子组件与root组件
我们可以将组件
在另外一个组件中注册,该组件称为父组件
,被注册的组件称为子组件
, Vue实例称为根组件
Notes
:
在父组件中注册的组件只能在父组件中使用, 无法在其他组件(包括root组件)中使用
const cpnC1 = Vue.extend({
template:`
<div>
<h1>我是子组件</h1>
<p>我是子组件的内容</p>
</div>
`
})
const cpnC2 = Vue.extend({
template:`
<div>
<h1>我是父组件</h1>
<p>我是父组件的内容</p>
<cpn1></cpn1>
</div>
`,
components:{
cpn1:cpnC1
}
})
Vue.component("cpn2" ,cpnC2)
04-组件创建的语法糖写法
// 1. Vue2.0之后, 提供组件的语法糖写法, 省去了创建组件构造器对象的步骤(官方推荐这种写法)
Vue.component("cpn1", {
template:`
<div>
<h1>我是子组件</h1>
<p>我是子组件的内容</p>
</div>
`
})
05-组件模板的抽离写法
在javascript带代码中写过多的html代码会让代码看起来十分混乱, 因此我们采取模板抽离的写法, 有两种实现方式
script
标签template
标签
在对应标签中都需要填写id
属性, 之后注册时写 template:'#id'
示例代码:
<div id="app">
<cpn1></cpn1>
<cpn2></cpn2>
</div>
<script src="../js/vue.js"></script>
<!--1. 方式一: script标签-->
<script type="text/x-template" id="cpn1">
<div>
<h1>script模板抽离</h1>
</div>
</script>
<!--方式二: template标签-->
<template id="cpn2">
<div>
<h1>template标签模板抽离</h1>
</div>
</template>
<script>
Vue.component("cpn1", {
template: "#cpn1"
})
Vue.component("cpn2" ,{
template:"#cpn2"
})
const app = new Vue({
el:"#app",
data:{
counter: 0,
message: "你好啊",
movies:["movie1" ,"movie2", "movie3", "movie4"]
},
methods:{
},
components:{
}
})
</script>
06-组件中的data()属性
组件中无法使用Vue实例中的数据, 实际上, 组件可以有自己的数据, 数据的保存使用函数进行保存
采用函数进行保存的原因:
我们可能建立多个组件的实例, 如果使用对象保存, 那么所有组件的对象都是同一个对象, 因此使用函数进行保存, 使得每个实例拥有不同的
data
对象
<body>
<div id="app">
<counter></counter>
<counter></counter>
<counter></counter>
</div>
<template id="counter">
<div>
<h2>当前计数:{{count}}</h2>
<button @click="increment">+</button>
<button @click="decrement">-</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
Vue.component("counter", {
template:"#counter",
data(){
return {
count :0
}
},
methods:{
increment(){
this.count++
},
decrement(){
this.count--
}
}
})
const app = new Vue({
el:"#app",
data:{
counter: 0,
message: "你好啊",
movies:["movie1" ,"movie2", "movie3", "movie4"]
},
methods:{
}
})
</script>
</body>
11 组件化-组件的通信
01-组件通信-父传子-props属性
父组件传递给子组件数据利用的是子组件的props
属性, 有两种方法
数组写法
: [‘变量名1’ , ‘变量名2’ ,…]props: ['变量名1' , '变量名2' ,...]
- 在组件标签中利用父组件变量赋值 (利用
v-bind:
指令)
<cpn :cmovies="movies"></cpn>
如果变量名使用了驼峰形式如
cMovies
, 那么在v-bind:
绑定时要写为:c-movies
- 在子组件中使用即可
对象写法
:- 指定类型, 默认值
注意, 对于数组与对象的默认值, 必须是一个函数:
props: { cmovies:{ type: Array, default(){ return [] } } }
- 在组件标签中利用父组件变量赋值 (利用
v-bind:
指令)
<cpn :cmovies="movies"></cpn>
- 在子组件中使用即可
注意
:不要在子组件中修改prop属性中的值, 不推荐这么做(因为值和父组件值绑定), 并且会报错
示例代码如下
<div id="app">
<!-- 2. 在组件标签中赋值-->
<cpn :cmovies="movies"></cpn>
<cpn1 :cmovies="movies"></cpn1>
</div>
<script src="../js/vue.js"></script>
<template id="cpn">
<div>
<h2>我是子组件</h2>
<ul>
<!-- 3.使用 -->
<li v-for="(item,index) in cmovies"> {{item}}</li>
</ul>
</div>
</template>
<script>
const app = new Vue({
el:"#app",
data:{
counter: 0,
message: "我是父组件",
movies:["movie1" ,"movie2", "movie3", "movie4"]
},
methods:{
},
components:{
cpn:{
template:"#cpn",
//1. props数组写法, ['变量名1' , '变量名2' ,...]
props:[ "cmovies" ]
},
cpn1:{
template:"#cpn",
//2.对象写法:
props: {
cmovies:{
type: Array,
default(){
return []
}
}
}
}
}
})
</script>
02-组件通信-子传父-自定义事件与$emit
子传父只能通过事件进行传递
- 在子组件中定义事件
- 事件触发时执行this.$emit(‘自定义事件名’ , 参数1,参数2)
- 在子组件标签中写
@自定义事件名="方法/js代码"
- 中方法不需要填写参数, 参数会自动传递
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<!-- @自定义事件名="执行方法"-->
<cpn @itemclick="itemclick"></cpn>
</div>
<script src="../js/vue.js"></script>
<template id="cpn">
<div>
<h2>我是子组件</h2>
<ul>
<li v-for="(item,index) in books">
<button @click="btnClick(item)">{{item.name}}</button></li>
</ul>
</div>
</template>
<script>
const app = new Vue({
el:"#app",
data:{
counter: 0,
message: "我是父组件",
movies:["movie1" ,"movie2", "movie3", "movie4"]
},
methods:{
itemclick(item){
//自定义事件
console.log(item)
}
},
components:{
cpn:{
template:"#cpn",
data(){
return {
books:[
{id:1, name:"计算机原理"},
{id:2, name:"操作系统原理"},
{id:3, name:"C++ Primer中文版"},
]
}
},
methods:{
btnClick(item){
this.$emit("itemclick" , item)
}
}
},
}
})
</script>
</body>
</html>
03子组件自实现父组件双向绑定
自实现绑定, 使得子组件父组件的两个data与子属性中的props属性双向绑定
数据的绑定不能使用
props
中的变量,会导致混乱 必须使用data中的变量
不要在子组件中修改prop属性中的值, 不推荐这么做(因为值和父组件值绑定), 并且会报错
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--子组件父组件数据绑定(props , data), input改变时跟着改变-->
<div id="app">
<div>pnum1:{{pnum1}}</div>
<cpn :number1="pnum1" :number2="pnum2"
@num1change="num1Change" @num2change="num2Change"
></cpn>
<div>pnum2:{{pnum2}}</div>
</div>
<script src="../js/vue.js"></script>
<template id="cpn">
<div>
<div>num1: props:{{number1}}</div>
<div>num2: data:{{num1}}</div>
<input type="text" @input="num1Input">
<div>num2: props:{{number2}}</div>
<div>num2: data:{{num2}}</div>
<input type="text" @input="num2Input">
</div>
</template>
<script>
const app = new Vue({
el:"#app",
data:{
counter: 0,
message: "你好啊",
movies:["movie1" ,"movie2", "movie3", "movie4"],
pnum1:1,
pnum2:2
},
methods:{
num1Change(value){
this.pnum1 = value * 1 //转化为int
},
num2Change(value){
this.pnum2 = value * 1
}
},
components:{
cpn:{
template:"#cpn",
data(){
return {
num1:this.number1,
num2:this.number2
}
},
props:{
number1:{
type:Number,
default() {
return 0;
}
},
number2:{
type:Number,
default() {
return 0;
}
}
},
methods:{
num1Input(event){
this.num1 =event.target.value
this.$emit('num1change', this.num1)
},
num2Input(event){
this.num2 = event.target.value
//不要在子组件中修改prop属性中的值, 不推荐这么做(因为值和父组件值绑定), 并且会报错
this.$emit('num2change', this.num2)
}
}
}
}
})
</script>
</body>
</html>
04-父组件访问子组件
父访问子组件实例有两种方法:
this.$children
:父组件可以直接访问到所有的子组件示例, 子组件示例会添加到this.$children
数组中this.$ref
: 与$children不同,$ref
默认是空对象- 给子组件实例添加
ref='引用名'
属性, 来添加子组件的引用 - 父组件中通过
this.$ref['引用名']
来进行引用
- 给子组件实例添加
一般不会通过
$children
拿子组件, 而是通过$ref
,$ref用的非常多
代码示例如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--父访问子有两种方式: $children, $ref-->
<div id="app">
<!-- 1. 通过$children拿到值-->
<cpn name="第0个组件"></cpn>
<cpn name="第1个组件"></cpn>
<button @click="btnClick">Click me</button>
<!-- 2. 通过ref-->
<cpn name="用ref绑定的组件" ref="cpn3"></cpn>
<button @click="refClick">refClick</button>
</div>
<template id="cpn">
<div>
<p>{{this.name}}</p>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el:"#app",
data:{
counter: 0,
message: "你好啊",
movies:["movie1" ,"movie2", "movie3", "movie4"]
},
methods:{
btnClick(){
console.log(this.$children)
},
refClick(){
console.log(this.$refs)
console.log(this.$refs["cpn3"])
}
},
components:{
cpn:{
template:'#cpn',
props:{
name:{
type:String ,
default:'第0个组件'
}
}
}
}
})
</script>
</body>
</html>
05-子组件访问父组件
$parent
:访问使用该子组件示例的父组件示例
$root
:访问Vue实例
若父组件为Vue实例, 那么
$parent
访问的就是Vue实例
parent
使用的非常少
下面示例通过点击按钮来测试$parent
与$root
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<cpn>
</cpn>
</div>
<template id="cpn">
<div>
<button @click="btnClick">子组件</button>
<ccpn></ccpn>
</div>
</template>
<template id="ccpn">
<div>
<button @click="btnClick">子组件</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const app = new Vue({
el:"#app",
data:{
counter: 0,
message: "你好啊",
movies:["movie1" ,"movie2", "movie3", "movie4"]
},
methods:{
},
components:{
cpn:{
template:"#cpn",
methods: {
btnClick(){
console.log(this.$parent)
}
},
components:{
ccpn:{
template:"#ccpn",
methods:{
btnClick(){
console.log(this.$parent)
console.log(this.$root)
}
}
}
}
}
}
})
</script>
</body>
</html>
11 slot插槽
01-无名插槽的使用slot
我们可以给模板指定插槽, 来让父组件决定要插入的内容
- 在模板中添加
slot
标签可以在 slot标签中内嵌内容作为默认内容
- 在组件实例化标签内部嵌入要插入的内容
如下
- 在模板中添加
slot
标签
<tempalte id="cpn">
<div>
<h1></h1>
<slot>
默认内容
</slot>
</div>
</tempalte>
- 在组件实例化标签内部嵌入要插入的内容
<div id="app">
<!--子组件实例中使用-->
<cpn>
<div>Anonymous Slot Here</div>
</cpn>
</div>
02-具名插槽的使用
- 定义: 在模板的slot标签中添加
name
属性 - 使用: 在子组件实例中带有
slot='name属性值'
的标签, 使用该名的插槽
<template id="cpn">
<div>
<!-- 1. 在模板中定义-->
<slot name="content">
默认内容
</slot>
</div>
</template>
<div id="app">
<cpn>
<!-- 2. 在子组件实例中使用-->
<div slot="content">名为content的插槽</div>
</cpn>
</div>
不填名字使用无名插槽
03-编译作用域
到底是哪个变量取决于使用变量的位置, 变量在哪个组件的模板中使用, 就优先使用哪个组件的变量
如下面的cpn
组件,这里的模板是父组件的模板, isShow
使用的是父组件即Vue实例app中的isShow
<div id="app">
<h1>{{message}}</h1>
<!--变量是在父组件中的模板使用的, 因此使用父组件中的变量-->
<cpn v-show="isShow"></cpn>
</div>
04-作用域插槽(暂留: depreceted)
在父组件中使用组件时可以拿到子组件的数据, 父组件替换插槽的标签, 但是内容由子组件来提供
12 模块化开发
01-ES5的模块化开发
02-CommonJS的模块化开发
模块化开发规范:AMD, CommonJS, ES6, CMD
导出:module.exports = {值1, 值2,...}
导入: const {值1, 值2} = require('文件');
导出: export const 变量=值
导入: import {值1, 值2, 值3,..} from "文件"
03-webpack与安装
webpack为了可以正常运行, 必须依赖node环境, 利用npm工具可以用来安装webpack
输入下面命令进行全局安装
npm install webpack@3.6.0 -g
为什么全局安装后, 还需要局部安装呢?
- 在终端直接执行webpack命令, 使用的是全局的webpack
- 在
package.json
中定义了scripts时, 其中包含了webpack命令, 那么使用的是webpack
04-webpack起步
webpack 是一个而现代的JavaScript引用的静态模块化打包工具
核心概念是: 模块与打包
ES6, sass等制作的文件没办法直接放到服务器上, 肯定是要通过打包,编译工具编译成ES5等绝大多数浏览器能够识别的格式, grunt, gulp, webpack
05-webpack的基本使用
- 建立
dist
与src
文件夹dist
文件夹存放打包后的bundle.js
src
文件夹存放源码
- 在
src
中编写代码 webpack
打包:
$ webpack js文件 打包的位置
05-webpack的config.js与Package.json配置
安装path包
npm init
meetwebpack
06-loader的使用
07-webpack vue
- 安装vue
npm install vue --save
开发环境与生产环境都要用, 就不要 --save-dev 了
- js代码中引入vue
//导入vue
import Vue from 'vue'
const app = new Vue({
el: '#app',
data:{
message : "hello world"
}
})
- webpack .config.js添加 resolve
const path = require('path');
module.exports = {
entry: './src/main.js',
output: {
filename: 'Bundle.js',
path: path.resolve(__dirname, 'dist'),
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
}
};
08 plugin
vue-template 源码
程序的入口?
- 程序启动的命令为:
vue-cli-server serve
vue-cli-server
为 基于webpack-dev-server
的构建的服务器, 在vue.config.js
的 devServer项中配置
包
babel
:
vue-cli
https://cli.vuejs.org/guide/cli-service.html
https://cli.vuejs.org/guide/cli-service.html