vue2/3学习(4)

270 阅读4分钟

工程化开发和脚手架

屏幕截图 2024-01-24 204415.png

后续只需进行第3、4步骤

第四步中的 “serve” 是来自于 package.json 中的 屏幕截图 2024-01-24 204109.png

项目目录介绍和运行流程

屏幕截图 2024-01-24 220211.png

index.js

屏幕截图 2024-01-24 221232.png

main.js

//文件核心作用:导入 App.vue ,基于 App.vue 创建结构渲染 index.html
//1.导入 Vue 核心包
import Vue from 'vue'
//2.导入 App.vue 根组件
import App from './App.vue'

//提示:当前处于什么环境(生产环境 / 开发环境)
Vue.config.productionTip = false

// Vue 实例化,提供 render 方法  作用:基于 App.vue 创建结构渲染 index.html
new Vue({
  // el:'#app',作用:和 $mount('#app') 作用一致,用于指定 Vue 所管理容器
  //render: h => h(App),   简写
  render:(createElement) => {
    // 基于 App 创建元素结构   完整写法
    return createElement(App)
  }
}).$mount('#app')

小结

屏幕截图 2024-01-24 223623.png

组件化开发和根组件

组件化

组件化

  1. 含义:一个页面可以拆分成一个个组件,每个组件都有自己独立的结构样式行为
  2. 好处:便于维护,利于复用 —— 提升开发效率
  3. 组件分类:普通组件、根组件

屏幕截图 2024-01-24 230811.png

根组件

根组件:整个应用最上层的组件,包括所有普通的小组件 屏幕截图 2024-01-24 231241.png

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

  1. 三部分组成:
  • template:结构(有且只能一个根元素)
  • script:行为(js 逻辑)
  • style:样式(可支持 less)
  1. 让组件支持 less
  • style标签,lang="less"   开启 less 功能

屏幕截图 2024-01-24 231405.png

普通组件的注册使用

局部注册

屏幕截图 2024-01-27 212710.png

屏幕截图 2024-01-27 213010.png

<template>
  <div class="App">
    <!--头部组件-->
    <IopHeader></IopHeader>
    <!--主体组件-->

    <!--底部组件-->
  </div>
</template>

<script>
import IopHeader from './components/IopHeader.vue'  
export default {
  components:{
    //组件名:组件对象
    //IopHeader:IopHeader
    //如果组件名和组件对象同名,可以直接写:
    IopHeader  
  }
}
</script>

<style>
  .App{
    width: 600px;
    height: 700px;
    background-color: #8cbcf3;
    margin: 0 auto;
    padding: 20px;
  }
</style>
<template>
  <div class="iop-header">
    我是iop-header
  </div>
</template>

<script>
export default {

}
</script>

<style>
.iop-header{
  height: 100px;
  line-height: 100px;
  text-align: center;
  font-size: 30px;
  background-color: bisque;
  color: aquamarine;
}
</style>
屏幕截图 2024-01-27 213953.png

全局注册

屏幕截图 2024-01-27 222409.png

屏幕截图 2024-01-27 230805.png

<template>
  <button class="iop-button">通用按钮</button>
</template>

<script>
export default {

}
</script>

<style>
.iop-button{
    height: 50px;
    line-height: 50px;
    padding: 0 20px;
    background-color: #c27b7b;
    border-radius: 5px;
    color: white;
    border: none;
    vertical-align: middle;
    cursor: pointer;
}
</style>
import Vue from 'vue'
import App from './App.vue'
//编写导入的代码,往代码的顶部去编写(规范)
import IopButton from './components/IopButton.vue'
Vue.config.productionTip = false

//进行全局注册 —— 在所有的组件范围内都能直接使用
//Vue.component(组件名,组件对象)
Vue.component('IopButton',IopButton)

new Vue({
  render: h => h(App),
}).$mount('#app')
  <div class="iop-header">
    我是iop-header
    <IopButton></IopButton>
  </div>
</template>

<script>
export default {

}
</script>

<style>
.iop-header{
  height: 100px;
  line-height: 100px;
  text-align: center;
  font-size: 30px;
  background-color: bisque;
  color: rgb(112, 155, 141);
}
</style>
屏幕截图 2024-01-27 230746.png

组件拆分的页面开发思路:

scoped 样式冲突

默认情况下:写在组件中的样式会全局生效 → 因此很容易造成多个组件之间的样式冲突问题。

  1. 全局样式:默认组件中的样式都会作用到全局
  2. 局部样式:可以给组件加上scoped属性,让样式只作用于当前组件

原理:

  1. 当前组件内标签都被添加 data-v-hash 值的属性,比如data-v-5f6a9d56
  2. css选择器都被添加 [data-v-hash值]的属性选择器
    最终效果:必须是当前组件的元素,才有这个自定义属性,才会被这个样式作用

data 是一个函数

一个组件的data 选项必须是一个函数。→ 保证每个组件实例,维护独立的一份数据对象。

每次创建新的组件实例,都会新执行一次 data函数,得到一个新对象。

  data: function () {
    return {
      count: 100,
    }
  }

<template>
<div class="base-count">
    <button @click="count--">-</button>
    <span>{{ count }}</span>
    <button @click="count++">+</button>
  </div>
</template>

<script>
export default {
  data: function () {
    return {
      count: 100,
    }
  },
}
</script>

<style scoped>
 .base-count {
  margin: 20px;
}
</style>

组件通信

组件通信就是指 组件与组件 之间的 数据传递

  • 组件的数据是独立的,无法直接访问其他组件的数据
  • 想用其他组件的数据 → 组件通信

组件关系的分类:

  • 父子关系
  • 非父子关系

组件通信解决方案

父子关系

父 → 子

  1. 如果子组件中需要用到父组件的数据,那么就需要 父组件通过props将数据传递给子组件
  2. 子组件利用 $emit ,通知父组件修改更新

如果想把父组件‘学前端,来黑马!’这个 title 用在子组件中,目前理论上这样是实现不了的

正确的流程如下:

  1. 父组件中的子组件添加自定义属性并传值
  2. 在子组件的vue中通过props接受冒号的内容
  3. 直接在子组件上面模板中使用 ​

子 → 父

如果想通过点击按钮来修改上面的 title

 <div class="son" style="border: 3px solid #000; margin: 10px">
    我是 Son 组件 {{ title }}
    <button @click="changeFn">修改title</button>

正确的流程如下:

  1. 先在子组件的template里写好你的按钮,并给它注册了一个点击事件,并在下面写了一个methods方法。但是你此时在methods里直接写是没有用的
<button @click="changeFn">修改title</button>
  1. 通过this.$emit() 向父组件发送通知
methods: {
   changeFn() {
     // 通过this.$emit() 向父组件发送通知
     this.$emit('changTitle','传智教育')
   },
 },
  1. 父组件为了收到消息,需要在子组件上绑上监听
<Son :title="myTitle" @changTitle="handleChange"></Son>
  1. 在父组件中提供对应的处理函数,提供逻辑

props 详解

  1. 定义:组件上注册的一些自定义属性

  2. 作用:向子组件传递数据

  3. 特点:可以传递任意数量的prop

  4. 校验:

    • 类型校验
    • 非空校验
    • 默认值
    • 自定义
// 类型校验
props:{
校验的属性名:类型  // Number、String、Boolean、Function...
}

// 完整校验
props:{
校验的属性名:{
    type: 类型,  // Number String Boolean Function...
   required:true// 是否必填
  default:默认值, //设置默认值
    validator (value) {
        //自定义校验逻辑
        参数为传过来的值    
        return true/false
    }
}
}

prop & data、单向数据流

  1. 共同点:都可以给组件提供数据。
  2. 区别:
    data 的数据是自己的 → 随便改
    prop 的数据是外部的 → 不能直接改,要遵循单向数据流
    单向数据流:父级prop的数据更新,会向下流动,影响子组件。

v-model 详解

原理: v-model 本质上是一个语法糖。例如应用在输入框上,就是 value 属性和 input 事件的合写

作用:提供数据的双向绑定

  1. 数据变,视图跟着变 :value 
  2. 视图变,数据跟着变 @input 
    注意:$event 用于在模板中,获取事件的形参

表单类组件封装

  1. 父传子::value  数据应该是父组件 props 传递过来的,v-model 拆解绑定数据
  2. 子传父:@input  监听输入,子传父传值给父组件修改
<template>
  <div class="app">
    <BaseSelect
      :cityId="selectId"
      @change="selectId=$event" 
    ></BaseSelect>
  </div>
</template>

<script>
import BaseSelect from './components/BaseSelect.vue'
export default {
  data() {
    return {
      selectId: '102',
    }
  },
  components: {
    BaseSelect,
  },
}
</script>

<style>
</style>
<template>
  <div>
    <select :value="cityId" @change="selectCity">
      <option value="101">北京</option>
      <option value="102">上海</option>
      <option value="103">武汉</option>
      <option value="104">广州</option>
      <option value="105">深圳</option>
    </select>
  </div>
</template>

<script>
export default {
  props: {
    cityId: String,
  },
  methods: {
    selectCity(e) {
      this.$emit('changeId', e.target.value)
    },
  },
}
</script>

<style>
</style>

v-model简化代码

  1. 子组件中:props 通过 value 接收,事件触发 input
  2. 父组件中:v-model 给组件直接绑数据

sync修饰符

  1. 作用:可以实现子组件与父组件数据的双向绑定,简化代码

  2. 特点:prop 属性名,可以自定义,非固定为 value

  3. 场景:封装弹框类的基础组件, visible 属性 —— true显示 false隐藏

  4. 本质:属性名 和@update:属性名 合写

<BaseDialog :visible.sync="isShow" />
// <BaseDialog :visible="isShow"  @update:visible="isShow = $event"/>

ref 和 $refs 获取 dom 和组件

用于获取 dom元素 ,或 组件实例

  • 获取dom

    1. 目标标签添加 ref属性

      <div ref="chartRef"> </div>
      
    2. 恰当事件,通过 this.$refs.xxx 获取目标标签

      mounted () {
         console.log(this.$refs.chartRef)
      }
      
  • 获取组件实例

    1. 目标组件添加ref属性

      <BaseForm ref="baseForm"> </BaseForm>
      
    2. 适当时机,通过this.$refs.xxx,获取目标组件,就可以调用组件对象里面的方法

      this.$refs.baseForm.组件方法()
      

Vue 异步更新和 $nextTick

需求:点击编辑,编辑标题,编辑框自动聚焦

$nextTick :等dom更新后,才会触发执行此方法里的函数体

  • 语法:this.$nextTick(函数体)
this.$nextTick(() => {
  代码
})

需求:

  1. 点击编辑,显示编辑框
  2. 让编辑框,立刻获取焦点
this.$nextTick(() => {
 this.$refs.inp.focus ()
})