借鉴了将一个大的问题拆分成一个个的小问题这种思想
组件必须放在vue管理的作用域内,如果是多个标签必须被一个元素包裹,就是有一个唯一的祖先元素
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script src="../../js/vue.js"></script>
<div id="app">
    <cpt></cpt>
    <cpt></cpt>
    <cpt></cpt>
    <cpt></cpt>
</div>
<script>
    // 1. 创建组件构造器
    const component = Vue.extend({
        template: `
            <div>
                hello
            </div>`,
    });
    // 2. 注册组件 全局组件
    Vue.component('cpt', component);
    const app = new Vue({
        el: "#app",
        data: {
            message: "hello world"
        }
    });
</script>
</body>
</html>

<div id="app">11
    <cpt></cpt>
    <cpt></cpt>
</div>
<div id="app2">22
    <cpt></cpt>
</div>
<script>
    // 1. 创建组件构造器
    const component = Vue.extend({
        template: `
            <div>
                hello
            </div>`,
    });
    //局部组件 只在app中的作用域有效
    const app = new Vue({
        el: "#app",
        data: {
            message: "hello world"
        },
        components: {
            cpt: component
        }
    });
    //未注册组件
    const app2 = new Vue({
        el: "#app2",
        data: {
            message: "hello"
        }
    });
</script>

<div id="app">11
    <pt></pt>
    <pt></pt>
    <pt></pt>
</div>
<script>
    /*第1个组件构造器*/
    const child = Vue.extend({
        template: `
            <div>
                child
            </div>`
    });
    // 第二创建组件构造器
    const parent = Vue.extend({
        template: `
            <div>
                parent
                <cd></cd>
            </div>`,
        components: {
            cd: child
        }
    });
    //局部组件 只在app中的作用域有效
    const app = new Vue({
        el: "#app",
        data: {
            message: "hello world"
        },
        components: {
            pt: parent
        }
    });
</script>
组件不会向上级作用域传递,只会向下传递,孙子没有在爷爷的作用域注册的话孙子只能在父亲的作用域使用
<div id="app">11
  <pt></pt>
  <pt></pt>
  <pt></pt>
</div>
<script>
  //局部组件 只在app中的作用域有效
  const app = new Vue({
    el: "#app",
    data: {
      message: "hello world"
    },
    components: {
      pt: {
        //  语法糖直接可以放在注册的地方
        template: `
            <div>
                hello
            </div>`
      }
    }
  });
</script>
<script src="../../js/vue.js"></script>
<div id="app">11
  <pt></pt>
  <pt></pt>
  <pt></pt>
</div>
<!--<script type="text/x-template" id="pt">
  <div>
    <div>我是标题</div>
  </div>
</script>-->
<template id="pt">
  <div>
    <div>我是tempalte</div>
  </div>
</template>
<script>
  //局部组件 只在app中的作用域有效
  const app = new Vue({
    el: "#app",
    data: {
      message: "hello world"
    },
    components: {
      pt: {
        //  语法糖直接可以放在注册的地方
        template: "#pt"
      }
    }
  });
</script>
<div id="app">11
  <pt></pt>
  <pt></pt>
  <pt></pt>
</div>
<template id="pt">
  <div>
    <div>我是{{title}}</div>
  </div>
</template>
<script>
  //局部组件 只在app中的作用域有效
  const app = new Vue({
    el: "#app",
    data: {
      message: "hello world"
    },
    components: {
      pt: {
        
        template: "#pt",
        //是一个函数,且只能访问自己的数据
        data(){
          return {title:"title"};
        }
      }
    }
  });
</script>
<div id="app">
  <pt :msg="msg" :title="title"></pt>
</div>
<template id="pt">
  <div>
    <div>{{title}}</div>
    <div>{{msg}}</div>
  </div>
</template>
<script>
  // 1.注册组件
  const pt = {
    template:"#pt",
    data() {
      return {};
    },
    methods: {},
    // props:["title","msg"] 可以写成数组或者对象,对象可以限制类型,对象更好点
    props:{
      // title:Array,
      title:{
        type: Array,
        default(){
          return [];
        }
      },
      //也可以写成对象的添加更多的限制、给默认值
      msg:{
        type:String,
        default:"",
        required:true,
        //自定义validator 这个待查阅
        validator: function (val) {
          return val == "hello worl";
        }
      }
    }
  }
  //局部组件 只在app中的作用域有效
  const app = new Vue({
    el: "#app",
    data: {
      msg: "hello world",
      title:["aaa","bbb","ccc"]
    },
    //字面量简写  pt可替换pt:pt
    components:{pt}
  });
</script>
v-on 事件监听器在 DOM 模板中会被自动转换为全小写 (因为 HTML 是大小写不敏感的),所以 v-on:myEvent 将会变成 v-on:myevent——导致 myEvent 不可能被监听到。<div id="app">
  <!--  不写参数会默认将$emit事件后传的参数【可多个】传出来,写了参数报错-->
  <pt @child-click="parentClick"></pt>
</div>
<template id="pt">
  <div>
    <button v-for="item in categories" @click="btnClick(item)">{{item.name}}</button>
  </div>
</template>
<script>
  // 1.注册组件
  const pt = {
    template: "#pt",
    data() {
      return {
        categories: [
          {id: "aaa", name: "aaa"},
          {id: "bbb", name: "bbb"},
          {id: "ccc", name: "ccc"},
          {id: "ddd", name: "ddd"}
        ]
      };
    },
    methods: {
      btnClick(ite) {
        // js中这样写不能驼峰,vue可以
        this.$emit('child-click', ite,1);
      }
    }
  };
  //局部组件 只在app中的作用域有效
  const app = new Vue({
    el: "#app",
    data: {
      msg: "hello world",
      title: ["aaa", "bbb", "ccc"]
    },
    components: {pt},
    methods: {
      parentClick(obj,a) {
        console.log(obj,a);
      }
    }
  });
</script>
<!--1. num1、num2从父组件传递过来
2. 修改num1,dnum1也变,同时传dnum1给父组件,父组件改变num1,也改变了prop1
3. dnum2一直是dnum1的1%-->
<div id="app">
  <pt :cnum1="num1" :cnum2="num2"
      @change1="cc1"
      @change2="cc2"
  ></pt>
</div>
<template id="pt">
  <div>
    <p>props:{{cnum1}}</p>
    <p>data:{{dnum1}}</p>
    cnum1<input type="text" :value="dnum1" @input="changeProp1"><br>
    <p>props:{{cnum2}}</p>
    <p>data:{{dnum2}}</p>
    cnum2<input type="text" :value="dnum2" @input="changeProp2">
  </div>
</template>
<script>
  //局部组件 只在app中的作用域有效
  const app = new Vue({
    el: "#app",
    data: {
      num1: 1,
      num2: 2
    },
    methods: {
      cc1(eve1) {
        this.num1 = eve1;
      },
      cc2(eve2) {
        this.num2 = eve2;
      }
    },
    components: {
      pt: {
        template: "#pt",
        props: {
          cnum1: {
            type: Number,
            default: 3
          },
          cnum2: {
            type: Number,
            default: 4
          }
        },
        data() {
          return {
            dnum1: this.cnum1,
            dnum2: this.cnum2,
          };
        }, 
        methods: {
          changeProp1(event1) {
            this.dnum1 = event1.target.value;
            console.log(this.dnum1)
            if (this.dnum1) {
              this.dnum1 = parseInt(this.dnum1)
              this.dnum2 = this.dnum1 / 100;
              this.$emit('change1', this.dnum1);
            } else {
              this.dnum2 = "";
            }
          },
          changeProp2(event2) {
            this.dnum2 = event2.target.value;
            this.$emit('change2', parseInt(this.dnum2));
          }
        }
      }
    }
  });
</script>
watch监听对象不能直接监听,可以用computed代替对象
语法:
watch:{
  监听的属性名(newValue, oldValue){
  }
}<script src="../../js/vue.js"></script>
<div id="app">
  {{message}}
  <input type="text" v-model="message">
  {{demo.name}}
  <input type="text" v-model="demo.name">
</div>
<template id="cd">
  <div>
    aaaaa
  </div>
</template>
<script>
  const app = new Vue({
    el: "#app",
    data: {
      message: "hello world",
      demo: {
        name: "nameObj"
      }
    },
    computed:{
      demoName(){
        return this.demo.name;
      }
    },
    watch: {
      message(newVal, oldVal) {
        console.log(newVal, oldVal);
      },
      //不能直接监听对象
      // demo(val) {
      //   console.log(val);
      // }
      demoName(val) {
        console.log(val);
      }
    },
    components: {
      cd: {
        template: "#cd"
      }
    }
  });
</script>
如果是键的路径需要用引号包裹
也可以外部调用
immediate和handler
watch有一个特点,就是当值第一次绑定的时候,不会执行监听函数,只有值发生改变才会执行。如果我们需要在最初绑定值的时候也执行函数,则就需要用到immediate属性。
比如当父组件向子组件动态传值时,子组件props首次获取到父组件传来的默认值时,也需要执行函数,此时就需要将immediate设为true。
deep: 当需要监听一个对象的改变时,普通的watch方法无法监听到对象内部属性的改变,只有data中的数据才能够监听到变化,此时就需要deep属性对对象进行深度监听
<div id="app">
  {{demo1.name}}
  <input type="text" v-model="demo1.name">
  {{demo.name}}
  <input type="text" v-model="demo.name">
  <input type="text" v-model="demo2">
</div>
<script>
  const app = new Vue({
    el: "#app",
    data: {
      message: "hello world",
      demo: {
        name: "nameObj"
      },
      demo1: {
        name: "nameObj"
      },
      demo2:"qweqw"
    },
    computed: {
      demoName() {
        return this.demo.name;
      }
    },
    watch: {
      //如果是键的路径需要用引号包裹
      "demo.name": function (val) {
        console.log(val);
      },
        
      // childrens: {  //监听的属性的名字
      //   handler:function(val){
      //     console.log(val.name);
      //   },
      //   deep: true, //可以监听到一个对象的内部属性变化
       //  immediate: true
      // },
      // "childrens.name":function (val) {
      //   console.log(val);
      // }
    }
  });
  //外部调用
  app.$watch("demo2",function (val) {
    console.log(val)
  })
</script>
<div id="app">
  <tmp ref="a"></tmp>
  <tmp ref="a"></tmp>
  <tmp ref="b"></tmp>
  <button @click="btnClick">打印子组件</button>
</div>
<template id="tmp">
  <div>
    <p>哈哈哈</p>
  </div>
</template>
<script>
  const app = new Vue({
    el: "#app",
    data: {
      message: "hello world"
    },
    methods:{
      btnClick(){
        //1. 一般不会用$children来取子组件
        // console.log("第一个子组件:",this.$children[0]);
        // console.log("所有子组件:",this.$children);
        // 2.$refs.refName|['refName']
        console.log("所有组件有ref属性的组件:",this.$refs);
        //如果多个相同的引用会取最后一个
        console.log("取得固定的ref的元素:",this.$refs["a"]);
        console.log("取得固定的ref的元素:",this.$refs.b);
      }
    },
    components: {
      tmp: {
        template: "#tmp"
      }
    },
  });
</script>
<div id="app">
  <tmp></tmp>
</div>
<template id="tmp">
  <div>
    <p>哈哈哈</p>
    <button @click="btnClick">打印父组件</button>
  </div>
</template>
<script>
  const app = new Vue({
    el: "#app",
    data: {
      message: "hello world"
    },
    components: {
      tmp: {
        template: "#tmp",
        methods: {
          btnClick() {
            //1. 不建议使用,会让组件的耦合增强不够独立
            console.log("打印直系父组件:", this.$parent);
            //祖先组件
            console.log("打印root组件:", this.$root);
          }
        }
      },
    },
  });
<!--1. 插槽的基本使用 <slot></slot>-->
<!--2. 插槽的默认值 <slot>默认值</slot>-->
<div id="app">
  <tmp></tmp><br>
  <tmp></tmp><br>
  <tmp></tmp><br>
  <tmp><div>我是插槽</div></tmp>
  <tmp><i>我是插槽i</i></tmp>
</div>
<template id="tmp">
  <div>
    <p>哈哈哈</p>
    <slot><p>我是默认值*******</p></slot>
    <p>娃娃</p>
  </div>
</template>
<script>
  const app = new Vue({
    el: "#app",
    data: {
      message: "hello world"
    },
    components: {
      tmp: {
        template: "#tmp"
      },
    }
  });
</script>
<div id="app">
  <tmp ><a slot="right" href="#">我替换右边</a></tmp><br>
  <tmp ><a slot="left" href="#">我替换左边</a></tmp><br>
  <tmp><a href="#">我替换没名字的</a></tmp><br>
</div>
<template id="tmp">
  <div>
    <slot name="left"><p>我是默认值left</p></slot>
    <slot name="center"><p>我是默认值center</p></slot>
    <slot name="right"><p>我是默认值right</p></slot>
    <slot><p>我是默认值没有名字</p></slot>
  </div>
</template>
<script>
  const app = new Vue({
    el: "#app",
    data: {
      message: "hello world"
    },
    components: {
      tmp: {
        template: "#tmp"
      },
    }
  });
<div id="app">
<!--    在谁的作用域用谁的变量-->
  <cp v-show="isShow"></cp>
</div>
<template id="cp">
  <div v-show="isShow"><!-- div父元素初始化的时候不受影响 -->
    <a href="">aaa</a>
    <button v-show="isShow">按钮</button>
  </div>
</template>
<script>
  const app = new Vue({
    el: "#app",
    data: {
      message: "hello world",
      isShow: true
    },
    components: {
      cp: {
        template: "#cp",
        data() {
          return {
            isShow: false
          };
        }
      }
    }
  });
</script>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
<script src="../../js/vue.js"></script>
<div id="app">
  <cp>
    <!--    slotData:类似于该组件的对象,2.5之前要用template-->
    <template slot-scope="slotData">
      <!--      取得绑定在组件中的数据-->
      <span v-for="item in slotData.datas">{{item}}-</span>
    </template>
  </cp>
  <cp>
    <template slot-scope="slotData">
      <!--      join方法将数组拼接成字符串-->
      <span>{{slotData.datas.join(' * ')}}</span>
    </template>
  </cp>
</div>
<template id="cp">
  <div>
    <!--    作为传递的数据-->
    <slot :datas="languages">
      <ul>
        <li v-for="item in languages">{{item}}</li>
      </ul>
    </slot>
  </div>
</template>
<script>
  const app = new Vue({
    el: "#app",
    data: {
      message: "hello world",
    },
    components: {
      cp: {
        template: "#cp",
        data() {
          return {
            languages: ['java', 'javascript', 'css', 'html', 'vb', 'python']
          };
        }
      }
    }
  });
</script>
</body>
</html>
// ;是为了防止其他的导入js相互影响
;var xm01 = (function xiaoming01() {
  return {
    aa:"asdas",
    flag: true
  };
}())
//js文件2
;(function () {
  if (xm01.flag) {
    alert("xm01.flag:" + xm01.flag);
  }
}());
原文:https://www.cnblogs.com/zpyu521/p/12309560.html