vue组件

1.组件化使用的三个步骤

  1. 创建组件构造器

    调用vue.extend()方法
    
  2. 注册组件

    vue.component("标签名",构造器对象)方法
    
  3. 使用组件

    在vue实例的作用范围内使用组件
    

    1602588356938

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

  1. 以下代码的效果是,当我们输入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;
        }
      } 
    })
    
    
  2. handler方法和immediate属性。这里 watch 的一个特点是,最初绑定的时候是不会执行的,要等到 firstName 改变时才执行监听计算。那我们想要一开始就让他最初绑定的时候就执行改怎么办呢?我们需要修改一下我们的 watch 写法,修改过后的 watch 代码如下:

    watch: {
      firstName: {
        handler(newName, oldName) {
          this.fullName = newName + ' ' + this.lastName;
        },
        // 代表在wacth里声明了firstName这个方法之后立即先去执行handler方法,如果为false就跟1中效果一样,不会立即执行
        immediate: true
      }
    }
    
    
  3. 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
        }
      } 
    })
    
    
posted @ 2023-02-26 17:11  MISF  阅读(17)  评论(0编辑  收藏  举报
     JS过度和变形效果演示   
  
    html5.png