Vue第四天笔记

57 阅读2分钟

1.组件:减少代码冗杂,提高代码复用

image.png

image.png

Vant 4 - 轻量、可定制的移动端组件库

1.1 App.vue文件(单文件组件)的三个组成部分

三个组成部分:
template:结构(有且只能有一个根元素,若想设置多个相同标签,可将其嵌套在div标签中)
script:js逻辑;
style:样式(可支持less,需要装包)

image.png

image.png 注意:template是虚拟标签,只起到包裹作用,不会在网页显示
支持less,使嵌套的p标签生效 image.png

1.2 普通组件的注册使用

1.2.1 局部注册

App.vue中嵌套着HmFooter、HmHeader、HmMain组件

1.2.1.1 App.vue
<template>
  <div class="app">
    <!-- 在页面中使用组件 -->
     <!-- 可以使用单标签写:<HmHeader/> -->
     <!-- 也可以使用横杠标签写 <hm-header/>-->
     <HmHeader></HmHeader>
     <HmMain></HmMain>
     <HmFooter></HmFooter>

    
  </div>
</template>
<script>
// // 局部注册组件,三个步骤
// 1.导入
// 2.注册组件--注册成html标签(这样标签就代表组件了)
// 3.页面中使用组件(标签)about:blank#blocked
// <
// 导入组件
import HmHeader from './components/HmHeader.vue'; 
import HmMain from './components/HmMain.vue';
import HmFooter from './components/HmFooter.vue';


export default{
  // 注册组件
  components:{
    // 标签名:导入的变量
    HmHeader:HmHeader,
    HmMain:HmMain,
    HmFooter:HmFooter,

    // 或简写为标签名
    // HmHeader,
    // HmFooter,
    // HmFooter
  },

}</script>

<style lang="less" scoped>
.app{
padding: 10px;
background-color: #87ceeb;
}
</style>
1.2.2.2 HmHeader
<template>
  <div class="header">
    
  </div>
</template>
<script>
export default {
  name: 'HmHeader'
}
</script>

<style lang="less" scoped>
.header{
  height: 100px;
  background-color: #8064a2;
}
</style>
1.2.2.3 HmMain
<template>
  <div class="main">
    
  </div>
</template>
<script>
export default {
  name: 'HmMain'
}
</script>

<style lang="less" scoped>
.main{
  height: 300px;
  background-color: #f79646;
}
</style>
1.2.2.4 HmFooter

<template>
  <div class="footer">
    
  </div>
</template>
<script>
export default {
  name: 'HmFooter'
}
</script>

<style lang="less" scoped>
.footer{
  height: 100px;
  background-color:#4f81bd;
}
</style>

结果:

image.png

1.2.2 全局注册

全局组件:可以放在任何地方使用 需要再main文件中设置

1.2.2.1 HmButton
<template>
<button>按钮
</button>
</template>
<script>
export default {
  name: 'HmButton'
}
</script>

<style lang="less" scoped>

</style>

1.2.2.2 main.js
import Vue from 'vue' //导入Vue
// import App from './App.vue' //导入根组件(app是最大的组件)
import App from './App.vue'
// 全局注册组件,在main中注册
// 1.导入组件
import HmButton from './components/HmButton.vue'
// 2.全局注册组件
Vue.component('HmButton', HmButton)

Vue.config.productionTip = false //关闭温馨提示

new Vue({
  render: h => h(App), //渲染函数(渲染App组件)
}).$mount('#app')//创建Vue实例,功能等同于new Vue({el:'#app'})

结果:

image.png

1.3 scoped解决样式冲突

只要给script标签加一个scoped就可以解决不同组件的样式冲突了

image.png

1.4 data必须是函数(不能写为对象)

image.png

1.5 组件通行-父子通讯

1.4中提到为了保证在组件复用时,复用的组件之间数据为了不互相影响,data必须要是函数。但如果想要实现组件之间的通信(即数据传递)需引入以下概念

image.png

image.png

1.5.1 父传子

image.png

image.png

image.png 总结:

image.png

1.5.2 子传父

image.png

image.png

2.案例——小黑记事本

使用父传子传递list列表数据
使用子传父实现增删改查
image.png

2.1 APP.vue

<template>
  <!-- 主体区域 -->
  <section id="app">
    <!-- 输入框 -->
     <!-- 1.3.将子组件导入页面中 -->
      <TodoHeader @add="handelAdd"></TodoHeader>
      <!-- 2.2父传子,将App中的数据传递给子组件TodoMain -->
       <!-- 2.3 子传父 将子组件数据传给父组件 (del是子组件的事件名,handelDel是方法名) -->
      <TodoMain :list="list" @del="handleDel"></TodoMain>
      <!-- 5.3 清空功能,直接把list清空,设置为空数组 -->
      <TodoFooter :list="list" @clear="handleClear"></TodoFooter>

  </section>
</template>

<script>
// 建立父子关系,将父组件和子组件进行关联
// 1.1.将子组件导入App.vue中
import TodoHeader from './components/TodoHeader.vue';
import TodoMain from './components/TodoMain.vue';
import TodoFooter from './components/TodoFooter.vue';

export default {
  data() {
    // 2.1 创建数据
    return {
      // 使用本地数组,若没有本地数据,则使用后面的数据
      list:JSON.parse(localStorage.getItem('todoList')) || [
        {id:1,name:'吃饭'},
        {id:2,name:'睡觉'},
        {id:3,name:'打代码'}
      ]
    }
  },
  // 6.1 使用监听器进行本地存储
  watch:{
    // 存储之前要转为JSON格式
    list:{
      handler(val) {
        localStorage.setItem('todoList',JSON.stringify(val))

      },
      deep:true

    }
  },
  methods: {
        // 2.3 子传父,将子组件数据传递给父组件
        // id是子组件传递的id属性
    handleDel(id) {
      // 2.4 删除数据
      // filter():是JavaScript的内置数组方法,用于过滤数组,并返回一个新的数组。
      // 如果当前的ID不等于当前遍历的item的ID,则返回true,表示保留该元素。
      this.list = this.list.filter(item => item.id !== id)
    },
    // 4.2 添加数据(子传父)
    handelAdd(todoname){
      this.list.unshift({
        id:Date.now(),
        name:todoname,
      })
    },
    // 5.3 清空数据(子传父)
    handleClear() {
      console.log('清空所有任务');
      this.list = [];
    }
  },
  // 1.2.注册子组件
  components: {
    TodoHeader,
    TodoMain,
    TodoFooter
  }
}
</script>

<style>

</style>

2.2 TodoHeader




<template>
    <header class="header">
      <h1>小黑记事本</h1>
      <!-- 4.1 添加功能-双向绑定 -->
      <input placeholder="请输入任务" class="new-todo" v-model="todoname"/>
      <button class="add" @click="post">添加任务</button>
    </header>

</template>
<script>
export default {
  data() {
    return {
      todoname:'' //输入框的值
    }
  },
  methods:{
    post(){
      this.$emit('add',this.todoname) //子传父
      this.todoname = '' //清空输入框
    }
  }
  }


</script>


<style lang="scss" scoped>

</style>

2.3 TodoMain


<template>
  <!-- 列表区域 -->
    <section class="main">
      <ul class="todo-list">
        <!-- 2.4 遍历数据 -->
        <li class="todo" v-for="(item,index) in list" :key="item.id">
          <div class="view">
            <span class="index">{{index+1}}.</span> 
            <label>{{item.name}}</label>
            <!-- 删除按钮 -->
            <button class="destroy" @click="$emit('del',item.id, index)"></button>
            <!-- 3.1 删除 按钮(使用子传父) -->


          </div>
        </li>
      </ul>
    </section>

</template>

<script>
export default {
  // 注意:只有App才有数据修改权,而此处的props是用来接收数据的
  // 2.3 接收从App.vue传过来的数据
  props:['list'],
  
  methods: {
    handleDelete(id, index) {
      console.log('TodoMain - 点击删除按钮');
      console.log('TodoMain - item.id:', id);
      console.log('TodoMain - index:', index);
      
      // 触发父组件事件
      this.$emit('del', id, index);
    }
  }
}
</script>


<style lang="scss" scoped>

</style>

2.4 TodoFooter

<template>
    <!-- 统计和清空 -->
    <footer class="footer">
      <!-- 统计 -->
       <!-- 5.1父传子,将数组list传递给子组件todofooter -->
      <!-- <span class="todo-count">合 计:<strong> {{list.length}}</strong></span> -->
      <span class="todo-count">合 计:<strong> {{list ? list.length : 0}}</strong></span>
      <!-- 清空 -->
       <!-- 5.3 点击按钮清空 -->
      <button @click="$emit('clear')" class="clear-completed">
        清空任务
      </button>
    </footer>

    
</template>
<script>
export default {
// 5.2 子组件接收父组件数据
props:['list']
}
</script>


<style lang="scss" scoped>

</style>