Vue基础_随笔
一、 Vue基础
一、 模板语法
1.1数据绑定
1.1.1文本,v-text、{
在mustache语法中,是可以使用加减乘除运算符的
<div id="app">
<div>
{{uage *2}}
</div>
<div v-text="uage"></div>
</div>
<script>
const app = new Vue({
el:'#app',
data:{
uage:10
}
})
</script>
1.1.2 v-once:
只将数值绑定一次
<div id="app">
<div v-once>
{{uage}}
</div>
</div>
1.1.3v-pre:
将标签内的内容不编译进行渲染
<div id="app">
<div v-pre>
{{uage *2}}
</div>
</div>
1.1.4v-cloak:
使数据加载之后才渲染页面
<div id="app">
<div v-cloak>
{{uage *2}}
</div>
</div>
原理:在vue数据加载之前,标签中有v-cloak这个属性,阻止元素的显示,数据加载之后,驱动页面渲染,元素上就没有v-cloak这个属性了
1.1.5 v-html
插入带html的字符
<div id="app">
<div v-html ='url'>
</div>
</div>
<script>
const app = new Vue({
el:'#app',
data:{
uage:10,
url:'<a href="http://www.baidu.com">ddd</a>'
}
})
</script>
1.1.6v-bind:
动态绑定属性值
语法糖::
<div id="app">
<a v-bind:href= "url">
我是百度
</a>
</div>
<script>
const app = new Vue({
el: '#app',
data: {
uage: 10,
url: 'http://www.baidu.com'
}
})
</script>
扩展使用:绑定class
文件css
.active { color: red; } .uncheck { color: yellow; } .green{ color: green; }
文件js
<script> const app = new Vue({ el: '#app', data: { isActive: true, isUncheck: false }, methods: { btnClick: function () { this.isActive = !this.isActive, this.isUncheck = !this.isUncheck }, getClass:function(){ return {active:this.isActive,uncheck:this.isUncheck} } } }) </script>
用法一:直接使用{}绑定一个class
<div :class={active:true}> 我是直接绑定的样式 </div>
用法二:使用变量传入boolean类型控制多个class是否生效
<div @click="btnClick" :class="{active:isActive,uncheck:isUncheck}" > 我要变色了 </div>
用法三:与其他class共同使用,样式冲突的情况下以到单独写的class为主
<div @click="btnClick" :class="{active:isActive,uncheck:isUncheck}"class="green" > 我要变色了 </div>
用法四:如果过于复杂,可以放在一个methods或者computed中
<div @click="btnClick" v-bind:class="getClass()" > 我要变色了 </div> //调用方法的时候可以选择不加括号
使用数组绑定class:
<div :class= "['green','fontClass']" class="active" > 我绑定了好几个class哦~ </div>
这样驻足绑定的方法可以使用data中的变量,也不与单独写的class冲突
但是在渲染的时候,是优先渲染内联class,所以如果有样式重叠,绑定的样式会覆盖掉内联class,截图如下:
-
v-bind绑定style
<div :style="{fontSize:'30px'}">我绑定了style</div> <div :style="{color:color,fontSize:fontSize+'px'}">我也绑定了style</div>
data: { color: "red", fontSize:30 },
注意事项:
- 格式为
:style= "{属性名:属性值}"
- 如果属性值是类似font-size带有
-
的属性值都要转换为fontSize,否则会报错 - 属性值如果直接写数值要加
''
,如果是变量则不用加
- 格式为
computed: {
fullName:function(){
return this.firstName + ' ' + this.lastName;
}
},
1.1.7v-model
在表单上创建双向绑定,v-model会忽略所有表单元素的value,checked,selected属性 初始值,而选定Vue实例数据为具体值。
<body>
<div id="app">
<input type="text" v-model = "userName">
<p>{{userName}}</p>
</div>
</body>
<script>
const app = new Vue({
el:"#app",
data:{
userName:"hong"
}
})
</script>
v-model的相关使用:
<body>
<div id="app">
<!-- v-model与radio的配合使用 -->
<label for="male">
<input id="male" type="radio" name="sex" v-model="sex" value="男">男
</label>
<label for="female">
<input id="female" type="radio" name="sex" v-model="sex" value="女">女
</label>
<p>选中的性别是:{{sex}}</p>
<!-- v-model与checkBox的配合使用 -->
<!-- <input type="checkbox" value="篮球" v-model="checked">篮球
<input type="checkbox" value="足球" v-model="checked">足球
<input type="checkbox" value="乒乓球" v-model="checked">乒乓球
<input type="checkbox" value="羽毛球" v-model="checked">羽毛球
<input type="checkbox" value="橄榄球" v-model="checked">橄榄球
<input type="checkbox" value="高尔夫" v-model="checked">高尔夫 -->
<label v-for= "item in hobbies" :for="item" >
<!-- 注意label的for与input的id都需要动态绑定,input的value也是需要动态绑定的 -->
<input type="checkbox" :value="item" :id="item" v-model= "checked" >{{item}}
</label>
<p>我选中了{{checked}}</p>
<!-- v-model与select配合使用 -->
<select name="" id="" v-model= "checkBooks" multiple>
<option v-for = "item in books" :value="item">{{item}}</option>
</select>
<p>我选中了:{{checkBooks}}</p>
</div>
</body>
<script src="../js/vue.js"></script>
<script>
Vue.component('cpn', cpnC)
const app = new Vue({
el: '#app',
data: {
// 给单选框一个默认值“男”
sex: '男',//单选
checked: [],//多选
hobbies:["足球","乒乓球","羽毛球","橄榄球","高尔夫"],
books:["钢铁是怎样炼成的","啊","Linux该怎么学","前端好难","努力学习"],
checkBooks:[]
},
})
</script>
1.1.7.1model修饰符
-
.lazy
默认情况下v-model是实时同步输入框的值和数据,加上
.lazy
后变为触发change时间后再同步(即相当于修改后要按下回车,或点击其他位置后才触发数据同步)<input type="text" v-model.lazy = "userName">
-
.number
将用户输入的内容转化成数值类型,转化规则与js的Number()的规则相同
<input type="text" v-model.number = "userName">
-
.trim
过滤掉输入框的首位空格
<input type="text" v-model.trim = "userName">
1.2事件绑定
1.2.1 v-on
作用:绑定事件监听器
语法糖:@
参数:event
1.2.1.1基本使用
使用v-on绑定事件
- 一个元素上可以绑定多个不同的事件
- 事件的绑定也可以通过methods中定义函数的方法来实现绑定
- 当定义的事件没有参数,所以我们在调用方法的时候不需要添加()
<body>
<div id="app">
<p>{{total}}</p>
<!-- 一个元素上可以绑定多个不同的事件 -->
<div class="div1" @mouseout = "total++" @click = "total--"></div>
<!-- 事件的绑定也可以通过methods中定义函数的方法来实现绑定 -->
<!-- 因为现在定义的事件没有参数,所以我们在调用方法的时候不需要添加() -->
<button v-on:click = "reduce">-</button>
<button v-on:click = "increase">+</button>
</div>
</body>
<script>
const app = new Vue({
el:"#app",
data:{
total:1
},
methods:{
// 定义total增加的函数
increase(){
this.total++;
},
// 定义total减少的函数
reduce(){
this.total--;
}
}
})
</script>
1.2.1.2事件监听传参
- 当方法需要参数但未传递实参,会将event对象当成默认参数返回
- 正常传递参数
- 当需要传递其他参数和event的时候,需要借助
$event
实现
<body>
<div id="app">
<!-- 省略参数,会将event事件当成默认的参数返回 -->
<button @click = "clickBtn">按钮</button>
<!-- 传递所需参数 -->
<button @click = "clickBtn1('sss')">按钮</button>
<!-- 同时传递需要的参数和event,使用vue封装的$event进行传参 -->
<button @click = "clickBtn2(123,$event)">按钮</button>
</div>
</body>
<script>
const app = new Vue({
el:"#app",
data:{
},
methods:{
clickBtn(){
console.log(event);
},
clickBtn1(a){
console.log(a);
},
clickBtn2(a,event){
console.log(a,event);
}
}
})
</script>
1.2.2 v-on的修饰符
- .stop调用了event。stopPropagation()
- .prevent调用event.preventDefault()
- .{keyCode|keyAlias}是事件只从特定按键触发时才触发回调
- .native 监听组件根元素的原生事件
- .once 只触发一次回调
<!-- 阻止冒泡 -->
<button @click.stop = "clickBtn">按钮</button>
<!-- 阻止默认行为 -->
<button @click.prevent = "clickBtn">按钮</button>
<!-- 阻止默认行为,没有表达式 -->
<form @submit.prevent></form>
<!-- 串联修饰符 -->
<button @click.stop,prevent = "clickBtn">按钮</button>
<!-- 按键别名,键盘上的名称 -->
<input @keydown.+ = "onEnter">
<!-- 按键代码,按键对应的代码数字 -->
<input @keydown.13 = "onEnter">
1.2.2 v-if、v-else、v-else-if
1..2.2.1 v-if、v-else
v-if与js的if用法相同,是通过v-if = ""引号中的Boolen值去进行判断,如果为false就隐藏元素是true就显示
<body>
<div id="app">
<div v-if="isShow">true</div>
<div v-else>false</div>
<button @click="changeClick">切换</button>
</div>
</body>
<script>
const app = new Vue({
el: "#app",
data: {
isShow: true
},
methods: {
changeClick() {
this.isShow = !this.isShow;
}
}
})
</script>
1.2.2.2v-else-if
用处不多,不赘余
<div id="app">
<div v-if="score >90 ">优秀</div>
<div v-else-if="score >80 ">良好</div>
<div v-else-if="score > 60">及格</div>
<div v-else>不及格</div>
</div>
1.3 v-for循环遍历
用法与for…in相同,详见w3school的for…in介绍
1.3.1循环数组
1.3.1.1无索引循环
<body>
<div id="app">
<ul>
<li v-for = "item in names" v-block>{{item}}</li>
</ul>
</div>
</body>
<script>
const app = new Vue({
el: "#app",
data: {
names:["h","w","l","g","z"]
},
methods: {
}
})
</script>
1.3.1.2 有索引循环
- 加一个小括号,里面加上item和index
<ul>
<li v-for = "(item,index) in names" v-block>{{index}}----{{item}}</li>
</ul>
1.3.2对象循环遍历
1.3.2.1无key无索引遍历
<body>
<div id="app">
<ul>
<li v-for = "item in names" v-block>{{item}}</li>
</ul>
</div>
</body>
<script>
const app = new Vue({
el: "#app",
data: {
names:{
name:"hong",
age:18,
sex:"男"
}
},
methods: {
}
})
</script>
1.3.2.2有key无索引遍历
<ul>
<li v-for = "(item,key) in names" v-block>{{key}}------{{item}}</li>
</ul>
1.3.2.2有key有索引遍历
<ul>
<li v-for = "(item,key,index) in names" v-block>{{key}}------{{item}}-----{{index}}</li>
</ul>
1.4(了解)如何正确使用key
-
v-for使用时,为了能够更好的复用,我们在使用v-for的时候,需要搭配key属性的使用
<body> <div id="app"> <ul> <li v-for = "item in names" key = "item">{{item}}</li> <li v-for = "item in user" key = "item">{{item}}</li> </ul> </div> </body> <script> const app = new Vue({ el: "#app", data: { names:{ name:"hong", age:18, sex:"男" }, user:["s","d","f","j"] }, methods: { } }) </script>
二、计算属性
2.1基本使用
<div id="app">
<div>{{fullName}}</div>
</div>
data: {
firstName: 'zhang',
lastName: 'san'
},
computed: {
fullName: function () {
return this.firstName + ' ' + this.lastName;
}
},
三、ES6语法
-
对象的增强语法
ES5的创建方法
var a = new Object(); a.sname = "hong";
var a = { sname = "hong" }
-
ES6语法
const sname = "hong"; var a = { sname, } //在es6的语法中,上面写法会吧sname当成key,将变量sname的值赋值给它
四、组件
4.1 全局组件与局部组件
<body>
<div id="app">
<!-- 全局组件在哪里都可以调用 -->
<global-c></global-c>
<!-- 局部组件只有在注册的组件内才能调用 -->
<cpn></cpn>
</div>
<div id="app2">
<global-c></global-c>
<!-- <cpn></cpn> -->
</div>
</body>
<script src="../js/vue.js"></script>
<script>
// 定义组件
const cpnC = Vue.extend({
template: `
<div>
<span>hhh</span>
<input type="text">
</div>
`
})
// 全局组件注册
Vue.component('globalCi', cpnC)
const app = new Vue({
el: '#app',
data: {
},
// 局部组件注册
components: {
cpn: cpnC
}
})
const app2 = new Vue({
el: "#app2",
})
</script>
提示:组件命名的时候是允许驼峰命名的,但是在使用的时候,要将大写字母转小写,前面加一个中划线
-
如Vue.component('globalComponent',***)在使用时就要
4.2父子组件
<body>
<div id="app">
<cpn></cpn>
</div>
</body>
<script src="../js/vue.js"></script>
<script>
// 定义组件1
const cpnC = Vue.extend({
template: `
<div>
我是组件1
</div>
`
})
const cpnC2 = Vue.extend({
template: `
<div>
我是组件2
<!-- 将注册好的组件在父组件中调用-->
<sonCpn></sonCpn>
</div>
`,
components:{
// 将组件1注册到组件2,此时组件1为字子组件,组件2为父组件
sonCpn:cpnC
}
})
const app = new Vue({
el: '#app',
data: {
},
// 在root根组件中注册组件2,在使用组件
components: {
cpn: cpnC2
}
})
const app2 = new Vue({
el: "#app2",
})
</script>
在调用组件的时候,Vue对象会先在自己的组件中去找,是否注册了这个组件,如果没有,去全局组件中查找,如果都没有,将报错
4.2.1父子组件语法糖
旧写法
// 定义组件
const cpnC = Vue.extend({
template: `
<div>
我是组件1
</div>
`
})
// 全局组件注册
Vue.component('globalCi', cpnC)
新写法
Vue.component("ss",{
template: `
<div>
我是组件1
</div>
`
})
//------------------------------------------
components: {
cpn: {
template: `
<div>
我是组件1
</div>
`
}
}
//-----------------------------------------------
const cpn = {
template: `
<div>
我是组件1
</div>
`
}
//在vue组件中定义
const app = new Vue({
el: '#app',
components: {
//ES6语法,key与value相同时,直接写一个就可以了
cpn
}
})
4.2.2将template抽离出来
4.2.2.1使用script标签
使用<script type="text/x-template"></script>
标签将html代码包裹,并赋以ID值,实现html代码的剥离
<body>
<div id="app">
<cpn></cpn>
<cpn1></cpn1>
<!-- <cpn2></cpn2> -->
</div>
<script type="text/x-template" id="test">
<div>
我是组件,但代码抽离了哦~
</div>
</script>
</body>
<script src="../js/vue.js"></script>
<script>
// 下面是注册全局组件的方式
Vue.component('cpn', {
template: "#test"
})
const app = new Vue({
el: '#app',
// 下面是注册局部组件的方式
components: {
cpn1: {
template: "#test"
}
}
})
</script>
4.2.2.2使用template标签
使用<template></template>
标签将html代码包裹,并赋以ID值,实现html代码的剥离
<template id="test02">
<div>
hi~我是用template标签实现的
</div>
</template>
实现方法与上面相同只是标签使用方法不同
🔅注意,在组件中使用变量是可以的但是data要使用data(){}方法,用return返回一个对象的方式实现,如下
// 下面是注册全局组件的方式
Vue.component('cpn1',{
template:"#test02",
//data必须使用方法,然后return返回
data(){
return {
title:"我是标题"
}
}
})
因为我们使用方法再ruturn的情况下,每次调用都相当于在不同的地址生成对象,在复用的时候,会同步更改,所以设计者尤大大规定组件中必须使用data(){reutrn {} }的方式
理论同下,帮助理解
function a (){ return { sname:"hong", sage:18 } } let b = a(); let c = a(); let d = a(); //上面的b,c,d并不是相同的物理地址
4.2.3 父子组件传值
4.2.3.1父传子
-
通过
props
属性进行传值<body> <div id="app"> <cpn :cmovies="movies"></cpn> </div> <!-- 下面的是子组件的html --> <template id="ccpn"> <div> {{cmovies}} </div> </template> </body> <script src="../js/vue.js"></script> <script> // 下面是子组件 const cpn = { template: '#ccpn', props: ['cmovies'], data() { return{ } } } // 下面是根组件也是父组件 const App = new Vue({ el: "#app", data() { return { movies: ['海王', '海贼'] } }, components: { cpn, } }) </script>
通过上面的方法,我们借助
props
属性来将父组件的数据传递给子组件,在调用子组件的时候通过v-bind
属性来绑定子组件的变量和父组件中的变量compnents
属性不止可以使用[]
也可以使用{}
,在使用对象语法的时候,我们可以验证传过来的数据类型,基本语法如下
4.2.3.1.1 porps属性的使用
-
动态props
上面的代码就是动态的props
-
静态props
<body> <div id="app"> <!-- props静态的赋值 --> <cpn cmovies="sss"></cpn> </div> <template id="ccpn"> <div> {{cmovies}} </div> </template> </body>
注意点:
- props的变量前面不需要加
:
,不加:
的情况下,后面赋值就不会被认为是变量
- props的变量前面不需要加
-
props验证
props: { // 基础类型检测, null意味着任何类型都行 propA: Number, // 多种类型 propB: [String, Number], // 必传且是String propC: { type: String, required: true }, // 数字有默认值 propD: { type: Number, default: 101 }, // 数组、默认值是一个工厂函数返回对象 propE: { type: Object, default: function () { console.log("propE default invoked."); return { message: "I am from propE." }; } }, // 自定义验证函数 propF: { isValid: function (value) { return value > 100; } } }
可检测的类型有:
- String
- Number
- Boolean
- Function
- Object
- Array
- Symbol
单向数据流
props 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。这是为了防止子组件五一修改父组件的状态。
所以不应该在子组件中修改 props 中的值,Vue 会报出警告。
let childNode = { template: ` <div class="child"> <div> <span>子组件数据</span> <input v-model="forChildMsg"/> </div> <p>{{forChildMsg}}</p> </div>`, props: { "for-child-msg": String } }; let parentNode = { template: ` <div class="parent"> <div> <span>父组件数据</span> <input v-model="msg"/> </div> <p>{{msg}}</p> <child :for-child-msg="msg"></child> </div> `, components: { child: childNode }, data() { return { msg: "default string." }; } };
这里我们给父组件和子组件都有一个输入框,并且显示出父组件数据和子组件的数据。当我们在父组件的输入框输入新数据时,同步的子组件数据也被修改了;这就是 props 的向子组件传递数据。而当我们修改子组件的输入框时,浏览器的控制台则报出错误警告
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "forChildMsg"
-
修改 props 数据
- 通常有两种原因:
- prop 作为初始值传入后,子组件想把它当做局部数据来用
- prop 作为初始值传入后,由子组件处理成其他数据输出
应对办法是:
- 定义一个局部变量,并用 prop 的值初始化它
但是由于定义的 ownChildMsg 只能接受 forChildMsg 的初始值,当父组件要传递的值变化发生时,ownChildMsg 无法收到更新。
let childNode = { template: ` <div class="child"> <div> <span>子组件数据</span> <input v-model="forChildMsg"/> </div> <p>{{forChildMsg}}</p> <p>ownChildMsg : {{ownChildMsg}}</p> </div>`, props: { "for-child-msg": String }, data() { return { ownChildMsg: this.forChildMsg }; } };
这里我们加了一个
用于查看 ownChildMsg 数据是否变化,结果发现只有默认值传递给了 ownChildMsg,父组件改变只会变化到 forChildMsg,不会修改 ownChildMsg。
-
定义一个计算属性,处理 prop 的值并返回
由于是计算属性,所以只能显示值,不能设置值。我们这里设置的是一旦从父组件修改了 forChildMsg 数据,我们就把 forChildMsg 加上一个字符串"---ownChildMsg",然后显示在屏幕上。这时是可以每当父组件修改了新数据,都会更新 ownChildMsg 数据的。
let childNode = { template: ` <div class="child"> <div> <span>子组件数据</span> <input v-model="forChildMsg"/> </div> <p>{{forChildMsg}}</p> <p>ownChildMsg : {{ownChildMsg}}</p> </div>`, props: { "for-child-msg": String }, computed: { ownChildMsg() { return this.forChildMsg + "---ownChildMsg"; } } };
-
更加妥帖的方式是使用变量存储 prop 的初始值,并用 watch 来观察 prop 值得变化。发生变化时,更新变量的值。
let childNode = { template: ` <div class="child"> <div> <span>子组件数据</span> <input v-model="forChildMsg"/> </div> <p>{{forChildMsg}}</p> <p>ownChildMsg : {{ownChildMsg}}</p> </div>`, props: { "for-child-msg": String }, data() { return { ownChildMsg: this.forChildMsg }; }, watch: { forChildMsg() { this.ownChildMsg = this.forChildMsg; } } };
-
单向数据流
props 是单向绑定的:当父组件的属性变化时,将传导给子组件,但是不会反过来。这是为了防止子组件五一修改父组件的状态。
所以不应该在子组件中修改 props 中的值,Vue 会报出警告。
let childNode = { template: ` <div class="child"> <div> <span>子组件数据</span> <input v-model="forChildMsg"/> </div> <p>{{forChildMsg}}</p> </div>`, props: { "for-child-msg": String } }; let parentNode = { template: ` <div class="parent"> <div> <span>父组件数据</span> <input v-model="msg"/> </div> <p>{{msg}}</p> <child :for-child-msg="msg"></child> </div> `, components: { child: childNode }, data() { return { msg: "default string." }; } };
这里我们给父组件和子组件都有一个输入框,并且显示出父组件数据和子组件的数据。当我们在父组件的输入框输入新数据时,同步的子组件数据也被修改了;这就是 props 的向子组件传递数据。而当我们修改子组件的输入框时,浏览器的控制台则报出错误警告
[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop being mutated: "forChildMsg"
-
修改 props 数据
通常有两种原因:
-
prop 作为初始值传入后,子组件想把它当做局部数据来用
-
prop 作为初始值传入后,由子组件处理成其他数据输出
应对办法是
-
定义一个局部变量,并用 prop 的值初始化它
但是由于定义的 ownChildMsg 只能接受 forChildMsg 的初始值,当父组件要传递的值变化发生时,ownChildMsg 无法收到更新。
let childNode = { template: ` <div class="child"> <div> <span>子组件数据</span> <input v-model="forChildMsg"/> </div> <p>{{forChildMsg}}</p> <p>ownChildMsg : {{ownChildMsg}}</p> </div>`, props: { "for-child-msg": String }, data() { return { ownChildMsg: this.forChildMsg }; } };
这里我们加了一个
用于查看 ownChildMsg 数据是否变化,结果发现只有默认值传递给了 ownChildMsg,父组件改变只会变化到 forChildMsg,不会修改 ownChildMsg。
-
定义一个计算属性,处理 prop 的值并返回
由于是计算属性,所以只能显示值,不能设置值。我们这里设置的是一旦从父组件修改了 forChildMsg 数据,我们就把 forChildMsg 加上一个字符串"---ownChildMsg",然后显示在屏幕上。这时是可以每当父组件修改了新数据,都会更新 ownChildMsg 数据的。
let childNode = { template: ` <div class="child"> <div> <span>子组件数据</span> <input v-model="forChildMsg"/> </div> <p>{{forChildMsg}}</p> <p>ownChildMsg : {{ownChildMsg}}</p> </div>`, props: { "for-child-msg": String }, computed: { ownChildMsg() { return this.forChildMsg + "---ownChildMsg"; } } };
- 更加妥帖的方式是使用变量存储 prop 的初始值,并用 watch 来观察 prop 值得变化。发生变化时,更新变量的值。
let childNode = { template: ` <div class="child"> <div> <span>子组件数据</span> <input v-model="forChildMsg"/> </div> <p>{{forChildMsg}}</p> <p>ownChildMsg : {{ownChildMsg}}</p> </div>`, props: { "for-child-msg": String }, data() { return { ownChildMsg: this.forChildMsg }; }, watch: { forChildMsg() { this.ownChildMsg = this.forChildMsg; } } };
上面部分代码借鉴https://www.jianshu.com/p/89bd18e44e73
-
4.2.3.2 子传父
-
在子组件中通过
$emit()
来触发事件。 -
在父组件中通过
v-on
来监听子组件事件<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <!-- 父组件模板 --> <div id="app"> <!-- 调用childMessage方法的时候如果省略参数,系统将会自动接收子组件方法传递过来的值 --> <cpn @btn-click = childMessage></cpn> </div> <!-- 子组件模板 --> <template id="cpn"> <div> <button @click = "logClick(item)" v-for = "item in categories">{{item.wname}}</button> </div> </template> </body> <script src="../js/vue.js"></script> <script> // 子组件 const cpn ={ template:"#cpn", data(){ return { categories:[ { id:1, wname:'篮球' },{ id:2, wname:'乒乓球' }, { id:3, wname:'羽毛球' }, ] } }, methods:{ logClick(item){ // 这个输出是在子组件本身内完成的 console.log("我点击了",item.wname); // 下面是将数据传递给父组件 this.$emit('btn-click',item.wname,) } } } // 父组件 const app = new Vue({ el:'#app', data(){ return{ message:'hello' } }, methods:{ childMessage(arg){ console.log(arg); } }, components:{ cpn } }) </script> </html>
父子组间访问
4.3.4.1 父访问子
-
$children
$children
是一个数组,打印之后显示VueComponent,VueComponent里面包含了很多数据,其中就有自组件中的属性或者方法。- 整体代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../js/vue.js" type="text/javascript"></script> </head> <body> <div id="app"> <button @click="btnClick">按钮</button> <Cpn></Cpn> </div> <template id="cpn"> <div>我是子组件</div> </template> </body> <script> //下面是子组件 const Cpn = { template: '#cpn', // 子组件的data必须使用方法的形式 data(){ return{ msg:"我是一条在子组件的消息" } }, methods: { showMessage() { console.log("sss"); return "我是返回的内容" } } }; //下面是父组件 const app = new Vue({ el: "#app", data() { return { } }, methods: { btnClick() { // 获取$children console.log(this.$children); // 获取子组件中的方法并调用 console.log(this.$children[0].showMessage()); // 获取子组件data中的变量 console.log(this.$children[0].msg) }, }, components: { Cpn } }) </script> </html>
- 关键代码:
methods: { btnClick() { // 获取$children console.log(this.$children); // 获取子组件中的方法并调用 console.log(this.$children[0].showMessage()); // 获取子组件data中的变量 console.log(this.$children[0].msg) }, },
但是不推荐这种,因为如果后期dom树更改的时候,就会对这个方法造成影响。
-
$refs
refs是一个对象,默认是个空对象,里面包含了被选中的子组件的所有元素
-
在需要使用的子集上通过属性
ref
添加属性名 -
在父级使用
$refs.属性名
来获取自组件中的数据 -
整体代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../js/vue.js" type="text/javascript"></script> </head> <body> <div id="app"> <button @click="btnClick">按钮</button> <Cpn ref="son" ></Cpn> </div> <template id="cpn"> <div>我是子组件</div> </template> </body> <script> const Cpn = { template: '#cpn', // 子组件的data必须使用方法的形式 data(){ return{ msg:"我是一条在子组件的消息" } }, methods: { showMessage() { console.log("sss"); return "我是返回的内容" } } }; const app = new Vue({ el: "#app", data() { return { } }, methods: { btnClick() { // // 获取$children // console.log(this.$children); // // 获取子组件中的方法并调用 // console.log(this.$children[0].showMessage()); // // 获取子组件data中的变量 // console.log(this.$children[0].msg) // 打印$refs console.log(this.$refs); // 获取aaa的msg变量 console.log(this.$refs.son.msg); // 获取aaa的方法 console.log(this.$refs.son.showMessage()); }, }, components: { Cpn } }) </script> </html>
-
关键代码;
btnClick() { // 打印$refs console.log(this.$refs); // 获取aaa的msg变量 console.log(this.$refs.son.msg); // 获取aaa的方法 console.log(this.$refs.son.showMessage()); },
-
-
子访问父(理解)
-
$parent
可以访问到子组件的直系父级(但因为这样的原因,开发时一个组件可能有多个父级,但并不是所有父级都有你所要的属性,那么就会返回
undefined
,所以开发时一般不用)。-
完整代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../js/vue.js" type="text/javascript"></script> </head> <body> <div id="app"> <cpn ref="son"></cpn> </div> <!-- 下面是cpn子组件 --> <template id="cpn"> <div> <div>我是cpn组件</div> <ccpn></ccpn> </div> </template> <!-- 下面是ccpn组件 --> <template id="ccpn"> <div> <div>我是ccpn组件</div> <button @click="checkParent">按钮</button> </div> </template> </body> <script> // 下面是cpn的子组件 const ccpn = { template: "#ccpn", methods: { checkParent() { console.log(this.$parent.msg); } } } // 下面是第一个子组件 const cpn = { template: '#cpn', // 注册ccpn组件 components: { ccpn }, data() { return { msg: "我是cpn组件中的一条消息" } }, methods: {} }; const app = new Vue({ el: "#app", components: { cpn, } }) </script> </html>
-
关键代码:
methods: { checkParent() { console.log(this.$parent.msg); } }
-
-
$root
无论在哪的组件,可以直接获取到根组件的属性:
-
完整代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../js/vue.js" type="text/javascript"></script> </head> <body> <div id="app"> <cpn ref="son"></cpn> </div> <!-- 下面是cpn子组件 --> <template id="cpn"> <div> <div>我是cpn组件</div> <ccpn></ccpn> </div> </template> <!-- 下面是ccpn组件 --> <template id="ccpn"> <div> <div>我是ccpn组件</div> <button @click="checkParent">按钮</button> </div> </template> </body> <script> // 下面是cpn的子组件 const ccpn = { template: "#ccpn", methods: { checkParent() { console.log(this.$root.msg); } } } // 下面是第一个子组件 const cpn = { template: '#cpn', // 注册ccpn组件 components: { ccpn }, data() { return { msg: "我是cpn组件中的一条消息" } }, methods: {} }; const app = new Vue({ el: "#app", data(){ return{ msg:"我是根组件的一条消息" } }, components: { cpn, } }) </script> </html>
-
关键代码
methods: { checkParent() { console.log(this.$root.msg); } }
-
-
五、插槽
5.1普通插槽的使用
-
首先在子组件中需要改变的地方写上插槽(
<slot></slot>
) -
在父级调用组件的标签内写这里需要显示的内容(调用就必须使用双标签)
-
整体代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../js/vue.js" type="text/javascript"></script> <style> img { width: 100px; height: 100px; } </style> </head> <body> <div id="app"> <!-- 第一个插槽显示按钮 --> <cpn> <button>按钮</button></cpn> <!-- 第二个插槽显示图片 --> <cpn> <img src="../img/01.png" alt="个人logo"></cpn> <!-- 第三个插槽显示文字 --> <cpn> <span>我就是一段文字</span></cpn> </div> <!-- 下面是子组件 --> <template id="cpn"> <div> <h2>我是一个子组件</h2> <!-- 定义一个插槽 --> <slot></slot> </div> </template> </body> <script> const cpn = { template: "#cpn", }; const app = new Vue({ el: "#app", components: { cpn } }) </script> </html>
-
关键代码:
<div id="app"> <!-- 第一个插槽显示按钮 --> <cpn> <button>按钮</button></cpn> <!-- 第二个插槽显示图片 --> <cpn> <img src="../img/01.png" alt="个人logo"></cpn> <!-- 第三个插槽显示文字 --> <cpn> <span>我就是一段文字</span></cpn> </div> <!-- 下面是子组件 --> <template id="cpn"> <div> <h2>我是一个子组件</h2> <!-- 定义一个插槽 --> <slot></slot> </div> </template>
5.2默认插槽值
-
使用过程与上面一样,不同的是在子组件中直接给
<solt></slot>
一个默认值 -
在调用的时候,如果没有指定插槽内容,就会显示默认的插槽内容
<body> <div id="app"> <!-- 第一个插槽显示按钮 --> <cpn> <button>我是另一个按钮</button></cpn> <!-- 第二个插槽默认内容 --> <cpn></cpn> <!-- 第三个插槽显示文字 --> <cpn> <span>我就是一段文字</span></cpn> </div> <!-- 下面是子组件 --> <template id="cpn"> <div> <h2>我是一个子组件</h2> <!-- 给插槽一个默认值 --> <slot><button>按钮</button></slot> </div> </template> </body>
5.3具名插槽
-
使用
name
属性给插槽一个标识 -
在调用的时候使用属性
slot
来确定给哪个插槽替换 -
如果没有用名称来确定的标识的内容,就会去寻找未具名的插槽,将其替换
-
如果没有未具名的插槽,未指定
name
的内容将不会显示 -
整体代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../js/vue.js" type="text/javascript"></script> <style> img { width: 100px; height: 100px; } </style> </head> <body> <div id="app"> <cpn> <!-- 将第一个插槽替换为按钮 --> <button slot="first"><</button> <!-- 将第二个插槽替换为文本+输入框 --> <span slot="second"> <span>搜索</span> <input type="text" placeholder="搜索"> </span> <!-- 第三个插槽变空 --> <span slot="third"></span> <!-- 替换没有名称的插槽 --> <span>淦</span> <span>淦</span> </cpn> </div> <!-- 下面是子组件 --> <template id="cpn"> <div> <slot name="first">我是第一个插槽</slot> <slot name="second">我是第二个插槽</slot> <slot name="third">我是第三个插槽</slot> <slot></slot> </div> </template> </body> <script> const cpn = { template: "#cpn", }; const app = new Vue({ el: "#app", components: { cpn } }) </script> </html>
-
关键代码
<div id="app"> <cpn> <!-- 将第一个插槽替换为按钮 --> <button slot="first"><</button> <!-- 将第二个插槽替换为文本+输入框 --> <span slot="second"> <span>搜索</span> <input type="text" placeholder="搜索"> </span> <!-- 第三个插槽变空 --> <span slot="third"></span> <!-- 替换没有名称的插槽 --> <span>淦</span> <span>嘿</span> </cpn> </div> <!-- 下面是子组件 --> <template id="cpn"> <div> <slot name="first">我是第一个插槽</slot> <slot name="second">我是第二个插槽</slot> <slot name="third">我是第三个插槽</slot> <slot></slot> </div> </template>
如果我们在子组件中将最后的那个未具名的插槽删除,那么上面的文字将不会显示:
<!-- 下面是子组件 --> <template id="cpn"> <div> <slot name="first">我是第一个插槽</slot> <slot name="second">我是第二个插槽</slot> <slot name="third">我是第三个插槽</slot> </div> </template>
5.4作用域插槽
-
在子组件中的插槽上通过
:
来绑定一个属性名与属性值,语法为<slot :list = "Arr"> 内容 </slot>
。属性名不能包含大写字母 -
父级在调用的时候需要在组件内写一个
<template slot-scope="slot">内容</template>
(低版本必须用template,高版本可以不用) -
整体代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <script src="../js/vue.js" type="text/javascript"></script> <style> img { width: 100px; height: 100px; } </style> </head> <body> <div id="app"> <cpn></cpn> <cpn> <template slot-scope="slot"> <span v-for="item in slot.list">{{item}}-</span> </template> </cpn> </div> <!-- 下面是子组件 --> <template id="cpn"> <div> <h2>我是子组件</h2> <slot :list="Arr"> <ul> <li v-for="item in Arr"> {{item}} </li> </ul> </slot> </div> </template> </body> <script> const cpn = { template: "#cpn", data() { return { Arr: ["xiaoming", "xiaohong", "xiaoguang"] } } }; const app = new Vue({ el: "#app", data() { return { } }, methods: {}, components: { cpn } }) </script> </html>
-
关键代码:
<div id="app"> <cpn></cpn> <cpn> <template slot-scope="slot"> <span v-for="item in slot.list">{{item}}*</span> </template> </cpn> </div> <!-- 下面是子组件 --> <template id="cpn"> <div> <h2>我是子组件</h2> <slot :list="Arr"> <ul> <li v-for="item in Arr"> {{item}} </li> </ul> </slot> </div> </template>