vue组件
1.组件化使用的三个步骤
-
创建组件构造器
调用vue.extend()方法
-
注册组件
vue.component("标签名",构造器对象)方法
-
使用组件
在vue实例的作用范围内使用组件
2.全局和局部组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="div1">
<mycn></mycn>
</div>
<script src="../js/vue.js"></script>
<script>
//1.定义构造器
const cpnC = Vue.extend({
template:
`<div>
<h1>你大爷</h1>
<h1>你大爷</h1>
<p>你大爷</p>
</div>`
});
//2.注册组件(全局组件)
// Vue.component("my-cn",cpnC); my-cn为标签名,cpnC为要注册的构造器对象
const app = new Vue({
el:"#div1",
components:{
mycn:cpnC //局部组件,只能在div1下使用(mycn为标签名)
}
})
</script>
</body>
</html>
3.父组件和子组件
1.父组件其实也就是构造器,父组件中包含子组件,要在父组件的template中使用子组件才能在前端显示
2.引用时不能直接引用子组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="div1">
<father-cpn></father-cpn>
</div>
<script src="../js/vue.js"></script>
<script>
//创建组件1
const cpnC = Vue.extend({
template:
`<div>
<h1>你大爷1</h1>
<h1>你大爷1</h1>
<p>你大爷1</p>
</div>`
});
//创建组件2(因内包含组件1,因此为父组件)
const cpnC2 = Vue.extend({
template:
`<div>
<h1>你大爷2</h1>
<child-cpn></child-cpn>
</div>
`
,
components:{
"child-cpn":cpnC,
}
});
const app = new Vue({
el:"#div1",
components:{
"father-cpn":cpnC2 //局部组件,只能在div1下使用
}
})
</script>
</body>
</html>
4.语法糖写法
在vue2.x中,组件的注册不用上述的方式(写法如:注释掉构造器,将构造器中内容取出),其实主要就是省略了extend
全局组件
Vue.component("my-cn",{
template:
`<div>
<h1>你大爷1</h1>
<h1>你大爷1</h1>
<p>你大爷1</p>
</div>`
})
局部组件
const app = new Vue({
el:"#div1",
components:{
"father-cpn":{
template:
`<div>
<h1>你大爷1</h1>
<h1>你大爷1</h1>
<p>你大爷1</p>
</div>`
} }
})
5.模板分离
1.将template中的内容写到type为text/x-template的script标签下,组件注册中加上script标签的id就好
html代码引用和上面相同
<script type="text/x-template" id="cpn">
<div>
<h1>你大爷1</h1>
<h1>你大爷1</h1>
<p>你大爷1</p>
</div>
</script>
<script>
Vue.component("cpn",{
template:"#cpn"
})
</script>
2.写在template标签中
<template id="cpn">
</template>
<script>
Vue.component("cpn",{
template:"#cpn"
})
</script>
6.组件中模板变量
以上写的tempate都是写死的,组件中的变量不能从vue实例中获取
//模板分离写法
<template id="x">
<div>
{{message}}
</div>
</template>
//注册
<script>
Vue.component("cpn",{
template:"#cpn",
data(){
return {
message:"xxx",
}
}
})
</script>
7.组件中data必须是函数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="div1">
父亲
<childcpn></childcpn>
<childcpn></childcpn>
</div>
<template id="child">
<div>
当前计数:<p>{{counter}}</p>
<button @click="increament">+</button>
<button @click="decreament">-</button>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
//let obj = { 错误写法:此处声明变量,data中return返回obj是一个对象
// counter:0
//}
const cpn = Vue.extend({
template:"#child",
//data(){
// return obj
//},
data(){ //正确写法,疑问:obj={counter:0},但是结果不同
return {
counter:0
}
}
methods:{
increament(){
this.counter++
},
decreament(){
this.counter--
}
}
});
const app = new Vue({
el:"#div1",
components:{
childcpn:cpn
}
})
</script>
</body>
</html>
8.父子组件
8.1父传子props
1.子组件中的data()是传值给当前子组件的template的
2.父组件中使用子组件,其本质就是使用其template,通过child_t传值给子组件,子组件在template中渲染,然后再被父组件使用,跟django中inclusion_tag相似
父组件
<template>
<div style="height: 100%;">
<el-container>
<!-- el-aside放logo和左侧菜单 -->
<el-aside :width="asideWidth">
<!-- 左侧菜单 -->
<an-menu :isCollapse="isCollapse" /> //2.绑定data中的数据,此处需bind
</el-aside>
</el-container>
</div>
</template>
<script>
import anMenu from "@/an-ui/menu";
export default {
name: "layout",
data() {
return {
isCollapse: false,
};
},
components: { //1.引用子组件
anMenu
},
};
</script>
子组件
<template>
<div class="menu">
<el-menu
:background-color="menuOptions.background"
:class="menuOptions.clazz"
:active-text-color="menuOptions.activeColor"
:text-color="menuOptions.color"
:collapse="isCollapse"
:unique-opened="true"
:default-active="$route.path"
:router="true"
>
</el-menu>
</div>
</template>
<script>
import { source2Target } from "@/utils";
export default {
name: "index",
props: {
options: Object,
isCollapse: { //接收父组件传来的数据
type: Boolean,
required: true
}
},
};
</script>
8.1.1传递方式
注意:此方式是写在子组件中的,父组件中template中引用的子组件中绑定的数据就是要通过props传递的
//1.数组形式
props:["message1","message2"]
//2.类型限制
props:{
message1:String //要求父组件传入的类型为String
message2:Array //要求父组件传入的类型为Array
}
//3.提供默认值
props:{
message1:{
type:String,
default:"aaa"
},
message2:{
type:Object, //类型为对象,默认值需要返回方法
default(){
return "XX"
}
}
}
8.2子传父emit
子组件中emit发送事件,在父template中child_t标签中使用v-on绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="div1">
<child_t v-on:ctop="childclick"></child_t>
</div>
<script src="../js/vue.js"></script>
<template id="chi">
<div>
<button v-for="item in child_message" @click="childs(item)">{{item.info}}</button>
</div>
</template>
<script>
const child = {
template:"#chi",
data(){
return {
child_message:[
{"id":"id1","info":"id1info"},
{"id":"id2","info":"id2info"},
{"id":"id3","info":"id3info"},
{"id":"id4","info":"id4info"},
]
}
},
methods:{
childs(item){
// console.log(item.info)
this.$emit("ctop",item) //发送事件(事件名称为ctop)
}
}
};
const app = new Vue({
el:"#div1",
components:{
child_t:child,
},
methods: {
childclick(item){
console.log(item)
}
}
})
</script>
</body>
</html>
8.3父访子:$children/$refs
this.$children得到所有的子组件(在本组件中的template中应用到的),this.$refs得到有ref属性的子组件,this.$refs.aaa得到精确的ref值为aaa的子组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="div1">
<cpn></cpn>
<cpn></cpn>
<cpn ref="aaa"></cpn>
<button @click="showchildmessage">显示子组件</button>
</div>
<template id="cpn1">
<div>
<p>子组件cpn1</p>
</div>
</template>
<script src="../js/vue.js"></script>
<script>
const cpn = {
template:"#cpn1",
methods:{
}
};
const app = new Vue({
el:"#div1",
components:{
cpn
},
methods:{
showchildmessage(){
console.log(this.$children);
console.log(this.$refs.aaa)
}
}
})
</script>
</body>
</html>
父传子(methods中无法通过props来传递,就通过ref来传参),这是父组件
<template>
<div>
<Dialog :dialogTitle="title" ref="x1"></Dialog>
</div>
</template>
<script>
import Dialog from './Dialog'
export default {
data() {
return {
tableData: [],
search: '',
title:"编辑"
}
},
methods: {
handleEdit(index, row) {
console.log(index, row);
this.$refs.x1.sonfun(index,row) //找到ref为x1的子组件中的sonfun方法传参
},
},
components:{
Dialog
}
}
</script>
子组件
<template>
<div>
<el-button type="text" @click="dialogFormVisible = true">打开</el-button>
<el-dialog :title="dialogTitle" :visible.sync="dialogFormVisible">
</el-dialog>
</div>
</template>
<script>
export default {
name: "Dialog",
props:["dialogTitle"],
data(){
return {
formLabelWidth :'120px',
dialogFormVisible: false,
form: {
name: "",
region: "",
}
}
},
methods:{
sonfun(index,row){
this.form.name = row.name;
this.form.region = row.address;
this.dialogFormVisible = true;
}
}
}
</script>
<style scoped>
</style>
8.5子访父:$parent
9.watch+深度监听
参考:https://blog.csdn.net/qq_36688143/article/details/81287535
-
以下代码的效果是,当我们输入
firstName
后,wacth
监听每次修改变化的新值,然后计算输出fullName
。<div> <p>FullName: {{fullName}}</p> <p>FirstName: <input type="text" v-model="firstName"></p> </div> new Vue({ el: '#root', data: { firstName: 'Dawei', lastName: 'Lou', fullName: '' }, watch: { firstName(newName, oldName) { this.fullName = newName + ' ' + this.lastName; } } })
-
handler方法和immediate属性。这里 watch 的一个特点是,最初绑定的时候是不会执行的,要等到
firstName
改变时才执行监听计算。那我们想要一开始就让他最初绑定的时候就执行改怎么办呢?我们需要修改一下我们的 watch 写法,修改过后的 watch 代码如下:watch: { firstName: { handler(newName, oldName) { this.fullName = newName + ' ' + this.lastName; }, // 代表在wacth里声明了firstName这个方法之后立即先去执行handler方法,如果为false就跟1中效果一样,不会立即执行 immediate: true } }
-
deep属性(默认值是false),假如有下面例子,v-model绑定的是obj.a,当我们改变obj.a时发现是无效的,是因为Vue不能检测到对象属性的改变,只有给obj赋值的时候才会监听到,但都太麻烦了,最简单的是使用deep属性,会一层一层向下遍历,给对象的所有属性都加上这个监听器,如下代码,但是这样可能会造成内存泄漏。
<div> <p>obj.a: {{obj.a}}</p> <p>obj.a: <input type="text" v-model="obj.a"></p> </div> new Vue({ el: '#root', data: { obj: { a: 123 } }, watch: { obj: { //解决内存泄露方法:字符串形式监听。改为"obj.a" handler(newName, oldName) { console.log('obj.a changed'); }, immediate: true, deep: true } } })