vue 组件+组件化开发

313 阅读6分钟

一.组件

1.什么是组件

拥有专属的HTML和CSS+JS+数据的可重用的页面独立功能区域

2.为什么使用组件

因为重用!

3.何时使用组件

只要页面中出现可能反复使用的功能区域,都要封装为组件,再反复使用组件

4.如何使用:2步

(1).定义组件

Vue.component("组件名",{//强调:组件名名不要用驼峰命名,多个英文单词要用-分割
     //和new Vue()中几乎完全一样!每个组件其实就是new Vue()一个功能完全相同的小的分身而已,new Vue()负责监控整个页面,而组件负责监控自己负责的小范围区域而已,没有el了,取而代之的是一个
     //组件的template中只能有一个唯一的父元素包裹
     template:`HTML代码片段`,     //因为这里是为将来反复使用这个组件定义的统一样式模板,将来使用这个组件时,反复创建的副本,和这里的HTML片段完全一样!
     //data不再是一个对象,而变成一个可反复调用的函数
     data(){ //将来每使用一次这个组件,就调用一次data()函数
             return { //每次调用data()函数,就返回一个新创建的模型对象给当前这个组件的一个副本专属----保证组件虽然可反复使用,但是数据是彼此隔离,互不影响!
                     组件模板中所需的变量
         }
     },
     //以下内容和new Vue()就完全一样
     methods:{....}
     conputed:{....}
     生命周期钩子函数
     .... ....     
})

(2).如何使用自定义的组件

组件其实就是一个可反复使用的自定义HTML元素而已,组件名其实就是元素的标签<组件名></组件名>

5.原理

(1).new Vue()扫描页面时,碰到不认识的元素标签,就会去Vue家找有没有同名的自定义组件
(2).如果找到同名的自定义组件,则先用组件对象的templateHTML片段代替页面上组件元素的位置
(3).自动调用一次data()函数,为本次组件的副本创建一个全新的专属的模型对象副本--保证这个组件副本中操作模型变量,不影响其他组件副本中的数据
(4).最后为这次组件副本创建一个小快递员对象,保持组件范围内模型对象与界面之前的同步

图片1 .png

<!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>
  <script src="js/vue.js"></script>
  <script>
    // 想定义一个计数器组件,点+-号,可更改数量
    // 1.创建组件对象,定义组件名称,多个英文单词用-分割
    Vue.component("my-counter", {
      // 每个组件的制作过程和new Vue()制作过程几乎完全一样
      // 2.定义界面模板:template
      // 要求唯一父元素包裹
      // 本例中:两个button可点击执行+-计算,所以@click标记
      template: `<div>
      <button @click="minus">-</button><span>{{n}}</span><button @click="add">+</button>
      </div>`,
      // 3.创建模型对象
      // 本例中:共需要1个变量n
      data() {//将来会被自动反复调用
        return {//反复创建模型对象副本-这里相当于new Vue()中的data对象
          n: 1
        }
      },
      // 其余的和new Vue()就完全一样了
      //本例中共需要minus和add两个函数
      methods: {
        minus() { if (this.n > 1) { this.n-- } },
        add() { this.n++ }
      }
    })
  </script>
</head>
<body>
  <div id="app">
    <ul>
      <li>
        <my-counter></my-counter>
      </li>
      <li>
        <my-counter></my-counter>
      </li>
      <li>
        <my-counter></my-counter>
      </li>
    </ul>
  </div>
  <script>
    var vm = new Vue({
      el: "#app"
    })
  </script>
</body>
</html>

二.组件化开发

1.什么是组件化开发

一个HTML页面其实都是由多个组件拼接起来的,拿到页面后,第一件事应该是划分组件区域,然后在由多个人分头编写一个页面的不同区域,最后再将每个编写的组件拼接到一起形成一个HTML页面展示给我们看!

2.为什么组件化开发

(1).便于大项目的分工协作,并行开发,效率高!
(2).松耦合!组件与组件之间相对独立,互不影响,一个出错,不影响大家!

3.何时使用

几乎所有项目都采用将组件化开发!

4.如何

(1).拿到页面图片,划分组件结构,2个依据
    a.按功能
    b.按是否重用

2021-06-11_121120.png

(2).划分了几个组件,就要创建几个独立的js文件,在独立的js文件中定义组件对象

2021.png (3).将所有组件引入到HTML页面中,由new Vue()经过反复扫描和替换过程,将所组件内容最终拼接到一起给用户显示

5.子组件

(1)问题:Vue.component()创建的组件,称为全局组件,可在页面中任何位置随意使用,
       但是有些组件明显不能超过父组件的范围使用
(2).解决:如果限制一个子组件只能在父组件范围内使用,就应该定义子组件,而不应该
        使用全局组件

(3).如何使用:2步

a.定义子组件对象:
     1).子组件对象的内容应该和定义全局组件内容的要求完全一致!
     2).但是不能用Vue.component()创建,应该仅仅保存在一个普通的js变量里
     3).变量名应该是子组件名称的驼峰命名方式!
b.必须在父组件对象中的components属性中,将子组件对象包含进来.
         父组件对象:{
            template:`........`,
            data(){
               return {....}
            },
            .. ..,
            components:{驼峰命名的组件变量名,... ...}
         }

(4).结果:凡是出现在这个父组件components中的子组件对象,就只能在当前父组件内使用,出了当前父组件使用,会报错!

(5).问题:子组件定义时的变量名时驼峰命名,在父组件模板中使用子组件标签时,应该用驼峰?还是-
(6).答:用-分割多个单词!因为components会自动将驼峰命名的组件变量名,翻译为-分割的名字

(7).强调:将多个子组件引入到页面时,组件间必须在父组件之前引入!

20.png

6.不考虑数据情况下,将待办事件列表拆分为父子组件

todo-add.js

  var todoAdd={
       template:`<div>
           <input><button></button>
       </div>`
  }
todo-item.js

var todoItem={
     template:`<li>
         1 吃饭 <a href="javascript:;">×</a>
     </li>`
}
todo-list.js

var todoList={
    template:`<ul>
        <todo-item></todo-item>
        <todo-item></todo-item>
        <todo-item></todo-item>
    </ul>`
    components:{todoItem}
}
todo.js

Vue.compon("todo",{
    template:`<div>
      <h1>代办事项列表</h1>
      <todo-add></todo-add>
      <todo-list><todo-list>
    </div>`,
    components:{todoAdd,todlList}
})
todo.html
<!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"></script>
  <script src="4_todo-add.js">
    //var todoAdd={ ... }
  </script>
  <script src="4_todo-item.js">
    //var todoItem={ ... }
  </script>
  <script src="4_todo-list.js">
    //var todoList={ 
    //  ... 
    //  components:{ todoItem }
    //}
  </script>
  <script src="4_todo.js">
    //Vue.component("todo",{ 
    //  ...
    //  components:{ todoAdd, todoList } 
    //})
  </script>
</head>
<body>
  <div id="app">
    <todo></todo>
  </div>
  <script>
    new Vue({
      el:"#app"
    })
  </script>
</body>
</html>

7.组件间数据传递

(1).问题:vue组件开发中,子组件无权直接使用父组件的变量!

(2).解决:采用专门的方法,让父组件将自己的一个变量传递给子组件才行

(3).如何:(父传子)2步:

a.父亲放数据:父组件在template中
     <子组件 :自定义属性="父要给予的变量">
     父把自己的一个变量值放到孩子身上一个指定名称的兜里
b.孩子接收数据:子组件对象中:
     子组件对象:{
        props:["自定义属性"],//孩子从父亲放东西的同名兜里取出父给的数据继续使用
        template:`...子组件的模板中使用自定义属性名等效于使用父组件的变量值...`
     }

强调:

1).通常为了保证一个东西在程序中只有一个统一的名称,便于维护,避免歧义,都在将父组件变量名和自    定义属性起相同的名字,但不是必须
2).props中的属性名 VS data中的变量
i.相同点:都即可用于HTML中的绑定和指令,又可用于js中通过this.xxx访问
ii.不同点:data中变量的值是组件内定义的,props中的属性值是外部给的!

2021-06-16_162634.png

8.实例:实现代办事项列表的任务列表和添加功能

todo.js

Vue.component("todo",{
     template:`<div>
        <h1>代办事项列表</h1>
        <todo-add :tasks="tasks"></todo-add>
        <todo-list :tasks="tasks"></todo-list>
        <div>`,
     data(){
        return {
           tasks:["吃饭","睡觉","打豆豆"]
        }
     },
     components: { todoAdd,todoList}
     })

todo-add.js

var todoAdd={
     props:["tasks"],
     template:`<div>
        <input v-model="newTask"><button @click="add">+</button>
       </div>`,
     data(){
     return {
       newTask:""
       }
     },
     methods:{
       add() {
         this.tasks.push(this.newTask);
         //添加完新任务后,清空文本框
         this.newTask="";//双向绑定
       }
     }
   }

todo-lsit

var todoList={
    props:["tasks"],
    template:`<ul>
      <todo-item v-for="(t,i) of tasks" :key="i" :task="t" :i="i">
    </ul>`,
    components:{todoTtem}
}

todo-item.js

var todoItem={
    props:["task","i"],
    template:`<li>
       {{i+1}}  {{task}} <a href="javascript:;">×</a>
    </li>`
}

todo.html

<!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"></script>
  <script src="4_todo-add.js">
    //var todoAdd={ ... }
  </script>
  <script src="4_todo-item.js">
    //var todoItem={ ... }
  </script>
  <script src="4_todo-list.js">
    //var todoList={ 
    //  ... 
    //  components:{ todoItem }
    //}
  </script>
  <script src="4_todo.js">
    //Vue.component("todo",{ 
    //  ...
    //  components:{ todoAdd, todoList } 
    //})
  </script>
</head>
<body>
  <div id="app">
    <todo></todo>
  </div>
  <script>
    new Vue({
      el:"#app"
    })
  </script>
</body>
</html>