VUE自用搜索文档

选中后面所有的

Ctrl +D

点击修改按钮 实现编辑修改

contenteditable=“bianJi” 想修改哪里的文本内容就写在那个标签 默认值是false

@click=“Gai()”

Gai(){
this.bianJi=true
}

删除

步骤:注册点击事件 传id @click=“del(item.id)”
根据id删除 del(id){}

删除函数
methods:{
del(id){
this.list=this.list.filter(item=>item.id!==id)
}
}
filter( 保留项 => 保留条件)
filter:根据条件,保留满足条件的对应项,得到一个新数组,但是并不会直接取代旧数组,所以得赋值给原数组

离开页面时销毁

写在destoryed(){}

验证码 剩余x秒 或 发送验证码 标签中引用

{{ 判断语句(结果true或false) ? true执行 : false执行${引用某个变量} }}

接口 解构 变量定义

const {data : {接口属性1,接口属性2…}}

在当前组件下的template下

想使用该组件script 里的方法或变量,不需要加this.
但在同一个script里想用其他的变量和方法则需要加list

依赖冲突

依赖冲突: --legacy-peer-deps -

微信导航栏点击展示

//代替a标签使用,vant时在外部标签加个route,内部标签加 to:“/path的值”,再加个指定位置的出口标签即可实现

向下复制

Shift + Alt + 向下键

配置一级路由

@/views下新建以及每个路由文件(文件名全小写),
且在每个路由文件下再创建一个主核心文件index.vue(export default里加name,名字如LayoutIndex)

@/router/index.js里添加:
import (可现命名)组件名 from ‘@/views/.vue文件所在文件,可以省略.vue文件不写’(二级路由要写)
{path:‘设置地址栏路径比如/rearch’,component:上面import的组件名} */

Vuex模块化的使用小结

1.直接使用

  1. state --> $store.state.模块名.数据项名
  2. getters --> $store.getters[‘模块名/属性名’]
  3. mutations > $–store.commit(‘模块名/方法名’, 其他参数)
  4. actions --> $store.dispatch(‘模块名/方法名’, 其他参数)

2.借助辅助方法使用

1.import { mapXxxx, mapXxx } from ‘vuex’

computed、methods: {

​ // …mapState、…mapGetters放computed中;
​ // …mapMutations、…mapActions放methods中;
​ …mapXxxx(‘模块名’, [‘数据项|方法’]),

​ …mapXxxx(‘模块名’, { 新的名字: 原来的名字 }),

}

2.组件中直接使用 属性 {{ age }} 或 方法 @click="updateAge(2)"

动态路由传参 (优雅简洁,传单个参数比较方便)

  1. 配置动态路由:path: “/path/:参数名”
    /search/:words 表示,必须要传参数。如果不传参数,也希望匹配,可以加个可选符"?"

  2. 跳转:to=“/path/参数值”

  3. 获取:$route.params.参数名
    (path即地址路径)

注意:动态路由也可以传多个参数,但一般只传一个

健忘解释

route:[
{path:‘/find’,component:Find }
]

发现音乐//代替a标签使用,vant时在外部标签加个route,内部标签加 to:“/path的值”,再加个指定位置的出口标签即可实现

path:地址栏路径(跟a标签或者router-link
搭配使用,即 点击->跳转 )
component:跳转到的组件名(页面.vue)

lang="less"嵌套属性,减少代码量 */

子想改父里边的数据需要标签里加

:value=“value”

只展示其中一个

v-if 搭配 v-else

双击点击事件

@dblclick=“handleClick”

失去焦点隐藏

@blur="名 = false "
false看情况改

vue-test1

Project setup

npm install

打开运行台

Ctrl + `

Compiles and hot-reloads for development

npm run serve

Compiles and minifies for production

npm run build

Lints and fixes files

npm run lint

Customize configuration

See Configuration Reference.

一次多光标(同一列)

Shift + Alt + 目的行数位置

所有的折叠

Ctrl + k ,Ctrl + 0(上面的)

所有的展开

Ctrl + k ,Ctrl + J

渲染“是否”时 对象属性 isSingle给true 变成“是”的方法

{isSingle ? ‘是’:‘否’}}

渲染数据

1.提供数据 -> 提供在公共的父组件 App.vue
2.通过父传子,将数据传递给 子组件
3.v-for渲染

点击添加数据:

1.收集表单数据 -> v-model=“todoName” (data加 todoName=‘’)
2.监听事件(回车,点击都添加) 回车:在input标签处添加 @keyup.enter=“添加事件”
3.子传父,将任务名称传递给父组件App.vue
4.进行添加unshift(自己的数据自己负责)
headleAdd(){
this.list.unshift({
id: +new Date(),
name:todoName
})

}

此内容包括:
第一阶段 Vue2核心技术 路由插件Vue Router 状态管理插件Vuex

  二阶   移动端智慧商城项目 vant ESlint

  三阶   Vue核心技术 

  四阶   PC端大事件管理系统  组件库:Element   

day01

一、为什么要学习Vue

1.前端必备技能

2.岗位多,绝大互联网公司都在使用Vue

3.提高开发效率

4.高薪必备技能(Vue2+Vue3)

二、什么是Vue

概念:Vue (读音 /vjuː/,类似于 view) 是一套 **构建用户界面 ** 的 渐进式 框架

Vue2官网:https://v2.cn.vuejs.org/

1.什么是构建用户界面

基于数据渲染出用户可以看到的界面

2.什么是渐进式

所谓渐进式就是循序渐进,不一定非得把Vue中的所有API都学完才能开发Vue,可以学一点开发一点

Vue的两种开发方式:
  1. Vue核心包开发

    场景:局部模块改造

  2. Vue核心包&Vue插件&工程化

    场景:整站开发

3.什么是框架

所谓框架:就是一套完整的解决方案

举个栗子

如果把一个完整的项目比喻为一个装修好的房子,那么框架就是一个毛坯房。

我们只需要在“毛坯房”的基础上,增加功能代码即可。

提到框架,不得不提一下库。

  • 库,类似工具箱,是一堆方法的集合,比如 axios、lodash、echarts等
  • 框架,是一套完整的解决方案,实现了大部分功能,我们只需要按照一定的规则去编码即可。

框架的特点:有一套必须让开发者遵守的规则或者约束

咱们学框架就是学习的这些规则 官网

总结:什么是Vue?

Vue是什么:

什么是构建用户界面:

什么是渐进式:

什么是框架:

三、创建Vue实例

我们已经知道了Vue框架可以 基于数据帮助我们渲染出用户界面

html文件写vue

核心步骤(4步):

  1. 准备容器 例如 div 想在html里写vue

  2. 引包(官网) — (开发版本 常用)/生产版本
    引入在线链接

  1. 创建Vue实例 new Vue({ })

  2. 指定配置项,渲染数据

    1. el:指定挂载点
    2. data提供数据

const app = new Vue({

		el: '#app',     

		data: {
     msg:"666"
  }

})

四、插值表达式 {{ }}

插值表达式是一种 Vue 的模板语法

利用 插值表达式 渲染出 Vue 0提供的数据

1.作用:利用表达式进行插值,渲染到页面中

表达式:是可以被求值的代码,JS引擎会讲其计算出一个结果

以下的情况都是表达式:

加减乘除:
    money + 100
    money - 100
    money * 10
    money / 10 

判断语句
    price >= 100 ? '真贵':'还行'

对象里的某个值
    obj.name
    data里的 对象名.变量名

列表索引
    arr[0]

函数
  fn()

obj.fn()

2.语法

插值表达式语法:{{ 表达式 }}

<h3>{{title}}<h3>

<p>{{nickName.toUpperCase()}}</p>  字母大写

<p>{{age >= 18 ? '成年':'未成年'}}</p>  判断语句

<p>{{obj.name}}</p>     data里的 对象名.变量名

<p>{{fn()}}</p>        方法名

3.错误用法

1.在插值表达式中使用的数据 必须在data中进行了提供
<p>{{hobby}}</p>  //如果在data中不存在 则会报错

2.支持的是表达式,而非语句,比如:if   for ...
<p>{{if}}</p>

3.不能在标签属性中使用 {{  }} 插值 (插值表达式只能标签中间使用)
<p title="{{username}}">我是P标签</p>

4.总结

{{ }}
1.插值表达式的作用是什么
利用表达式进行插值,将数据渲染页面中

2.语法是什么
{{表达式}}

3.插值表达式的注意事项

data中存在的数据才可以

if else之类的语句禁止

标签内禁用

五、响应式特性

Vue的核心特性之一:想要更新展示的视图,根据 业务核心逻辑 修改数据

1.什么是响应式?

​ 简单理解就是数据变,视图对应变。

2.如何访问 和 修改 data中的数据(响应式演示)

data中的数据, 最终会被添加到实例上

① 访问数据: 实例.属性名
实例即app.

② 修改数据: 实例.属性名 = 新值

3.总结

  1. 什么是响应式
    数据改变,视图自动更新

  2. 如何访问和修改data中的数据呢
    控制台:
    app.属性名
    app.属性名 = 新值
    这种方法有点麻烦,可以使用Vue开发者工具进行,如下

六、Vue开发者工具安装 新电脑安装 调试工具

  1. 通过谷歌应用商店安装(国外网站)

  2. 极简插件下载(推荐) https://chrome.zzzmh.cn/index
    下载步骤:搜索Vue 选择VueDevtools 推荐下载 下载解压

安装步骤: 下载
开发者模式 (打开Chrome 右上角三个点 更多工具 扩展程序 右上角打开开发者模式)
拖拽更新 (将下载好的.crx文件拖到大屏)
插件详情允许访问文件 (详情信息 打开允许访问文件网址)

安装之后可以F12后看到多一个Vue的调试面板,可以拖前面来

七、Vue中的常用指令

概念:指令(Directives)是 Vue 提供的带有
v- 前缀
的 特殊 标签
属性

为啥要学:提高程序员操作 DOM 的效率。

vue 中的指令按照不同的用途可以分为如下 6 大类:

  • 内容渲染指令(v-html、v-text)
  • 条件渲染指令(v-show、v-if、v-else、v-else-if)
  • 事件绑定指令(v-on)
  • 属性绑定指令 (v-bind)
  • 双向绑定指令(v-model)
  • 列表渲染指令(v-for)

指令是 vue 开发中最基础、最常用、最简单的知识点。

八、内容渲染指令 v-html=" "

  • v-html(类似 innerHTML) 可以解析 data里的标签属性,拼接在标签里的文字后面

    • 使用语法:

      hello

      ,意思是将 intro 值渲染到 p 标签中
    • 类似 innerHTML,使用该语法,会覆盖 p 标签原有内容
    • 类似 innerHTML,使用该语法,能够将HTML标签的样式呈现出来。
  <div id="app">
    <h2>个人信息</h2>
	// 既然指令是vue提供的特殊的html属性,所以咱们写的时候就当成属性来用即可
    <p v-text="uname">姓名:</p> 
    <p v-html="intro">简介:</p>
  </div> 

<script>
        const app = new Vue({
            el:'#app',
            data:{
                uname:'张三',
                intro:'

这是一个非常优秀的boy

' } }) </script>

九、条件渲染指令 显示与隐藏 v-show=" " v-if=" " v-else=" " v-else-if=" 判断语句 "

条件判断指令,用来辅助开发者按需控制 DOM 的显示与隐藏。条件渲染指令有如下两个,分别是:
区别:v-show是 虽然隐藏了但是还存在那个块
v-if是 一旦隐藏了就会彻底消失

  1. v-show

    1. 作用: 简单 控制元素显示隐藏
    2. 语法: v-show = “表达式” 表达式值为 true 显示, false 隐藏
    3. 原理: css 中的 display:none
    4. 场景: 频繁切换显示隐藏的场景 经常显示或者隐藏
      例如:鼠标悬停时展示的列表
  2. v-if

    1. 作用: 控制元素显示隐藏(条件渲染)
    2. 语法: v-if= “表达式” 表达式值 true显示, false 隐藏
    3. 原理: 基于条件判断,是否创建 或 移除元素节点
    4. 场景: 要么显示 ,要么隐藏 ,不频繁切换的场景
      例如:为方便您购买,请提前登录 立即登录 (根据有没有登陆出现该提示)
      <div id="app">
        <div class="box" v-show="flag">我是v-show控制的盒子</div>
        <div class="box" v-if="flag">我是v-if控制的盒子</div>
      </div>
    
      <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
      <script>
        const app = new Vue({
          el: '#app',
          data: {
            flag: false
          }
        })
      </script>
    
  3. v-else 和 v-else-if 多种条件判断时使用

    1. 作用:辅助v-if进行判断渲染
    2. 语法:v-else v-else-if=“表达式”
    3. 需要紧接着v-if使用
  <div id="app">
    <p v-if=" gender === 1 ">性别:♂ 男</p>
    <p v-else="gender === 2">性别:♀ 女</p>
    <hr>
    <p v-if=" score >= 90 ">成绩评定A:奖励电脑一台</p>
    <p v-else-if="   score >=70 ">成绩评定B:奖励周末郊游</p>
    <p v-else-if="score>=60">成绩评定C:奖励零食礼包</p>
    <p v-else> 成绩评定D:惩罚一周不能玩手机</p>
  </div>
  
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>

    const app = new Vue({
      el: '#app',
      data: {
        gender: 2,
        score: 95
      }
    })
  </script>

十、事件绑定指令 动态传参 v-on: 事件名 = “methods中的函数名”

v-on
作用:注册事件 = 添加监听 + 提供处理逻辑
语法:1. v-on: 事件名 = “内联语句” 内联语句:可执行的代码
2. v-on: 事件名 = “methods中的函数名”

  • v-on: 简写为 @

事件名:click 鼠标点击
mouseenter 鼠标划入

  1. 内联语句
  <div id="app">
      <button @click="count--">-</button>     
      <span>{{ count }}</span>
      <button v-on:click="count++">+</button>                /* v-on:事件名="内联语句" */
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
    <script>
      const app = new Vue({
        el: '#app',
        data: {
          count: 100
        }
      })
    </script>
  1. 事件处理函数
    注意:

    • 事件处理函数应该写到一个跟data同级的配置项(methods)中
    • methods中的函数内部的this都指向Vue实例

点击切换显示或隐藏 案例

<div id="app">
    <button @click="fn">切换显示隐藏</button>          事件处理函数
    <h1 v-show="isShow">黑马程序员</h1>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        isShow: true
      },
      methods{
        fn(){
          this.isShow = !this.isShow  /* 取反 */
  /* this.isShow  其实就是 app.isShow = 新值 ,不过为了防止上面的 const app 改变,则用this代替更好 */
        }
      }
    })
  </script>

3.给事件处理函数 传参

  • 如果不传递任何参数,则方法无需加小括号;methods方法中可以直接使用 e 当做事件对象
  • 如果传递了参数,则实参 $event 表示事件对象,固定用法。
 <style>
    .box {
      border: 3px solid #000000;
      border-radius: 10px;
      padding: 20px;
      margin: 20px;
      width: 200px;
    }
    h3 {
      margin: 10px 0 20px 0;
    }
    p {
      margin: 20px;
    }
  </style>

 <div id="app">
    <div class="box">
      <h3>小黑自动售货机</h3>
      <button @click="buy(5)">可乐5</button>
      <button @click="buy(10)">咖啡10</button>
      <button @click="buy(8)">牛奶8</button>
    </div>
    <p>银行卡余额:{{ money }}</p>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        money: 100
      },
      methods{
        buy(price){                       /* price会自动找到 v-on 的 buy参数 price此处名字随意 */
           this.money -= price
        }

      }

    })
  </script>

十一、属性绑定指令 动态标签属性 图片动态设置 v-bind : 属性名=“表达式” :url=" data里的url属性 "

  1. 作用:动态设置html的标签属性 不会写死的 比如:src、url、title
    还可以操作css类名哦…

  2. 语法:v-bind : 属性名=“表达式”

  3. v-bind:可以简写成只写一个 :

比如,有一个图片,它的 src 属性值,是一个图片地址。这个地址在数据 data 中存储。

则可以这样设置属性值:

  • (v-bind可以省略)
  <div id="app">
    <img v-bind:src="imgUrl" v-bind:title="msg" alt="">   {/* 此处图片和标题都动态设置了 */ }
    <img :src="imgUrl" :title="msg" alt="">            {/* (v-bind可以省略) */}
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        imgUrl: './imgs/10-02.png',
        msg: 'hello 波仔'
      }
    })
  </script>

十二、小案例-波仔的学习之旅 点击按钮 切换图片

需求:默认展示数组中的第一张图片,点击上一页下一页来回切换数组中的图片

实现思路:

1.data里边 数组存储图片路径 list : [‘url1’,‘url2’,‘url3’,…]

2.默认展示第一张 在标签处 v-bind:list[0]

3.想要改图片,设置一个变量index即可,将来点击时变量index ++或-- 即可

4.index写在data下,默认值为0(第一张) index:0

5.注册点击事件 上一页index++ 下一页-- @click=“index++”
此时发现到最后一页时还有下一页按钮…,不合理, index超出5或index小于0

6.v-show解决bug:index的取值要在数组的下标之间
v-show=“index > 0” 表示等于零隐藏上一页 v-show=“index < 5” 表示等于5隐藏下一页

7.将来可能有更多的图片 所以把index<5 优化成 index < list.length-1 (数组总数量 统计数量时也可以用到)

 <div id="app">
    <button @click="index--" v-show="index > 0">上一页</button>
    <div>
      <img :src=" list[index]" alt="">
    </div>
    <button @click="index++ v-show="index < list.length-1">下一页</button>
   </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        index:0,
        list: [
          './imgs/11-00.gif',
          './imgs/11-01.gif',
          './imgs/11-02.gif',
          './imgs/11-03.gif',
          './imgs/11-04.png',
          './imgs/11-05.png',
        ]
      }
    })
  </script>

十三、列表渲染指令 v-for

Vue 提供了 v-for 列表渲染指令,用来辅助开发者基于一个数组来循环渲染一个列表结构。

v-for 指令需要使用 (item, index) in arr 形式的特殊语法,其中:

  • item 每一项
  • index 下标,不需要可以省略
  • arr 数组名

此语法也可以遍历对象和数字

//遍历对象
<div v-for="(value, key, index) in object">{{value}}</div>
value:对象中的值
key:对象中的键
index:遍历索引从0开始

//遍历数字
<p v-for="item in 10">{{item}}</p>
item从1 开始

十四、小案例-小黑的书架 列表渲染 v-for

需求:

1.根据左侧数据渲染出右侧列表(v-for)

2.点击删除按钮时,应该把当前行从列表中删除(获取当前行的id,利用filter进行过滤)
注意:删除键 @click=“del(item.id)” 传过来的是item.id 下面methods里接收的是 del(id)

准备代码:

<div id="app">
    <h3>小黑的书架</h3>
    <ul>
      <li v-for="(item,index) in booksList":key="item.id">
        <span>{{item.name}}</span>
        <span>{{ item.author}}</span>
        <button @click="del(item.id)">删除</button>
      </li>
    </ul>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        booksList: [
          { id: 1, name: '《红楼梦》', author: '曹雪芹' },
          { id: 2, name: '《西游记》', author: '吴承恩' },
          { id: 3, name: '《水浒传》', author: '施耐庵' },
          { id: 4, name: '《三国演义》', author: '罗贯中' }
        ]
      },
      methods:{
        del(id){
             this.booksList=this.booksList.filter(item => item.id !== id) 
                                         {/* filter( 保留项 => 保留条件) */}
        }
      }
    })
  </script>

十五、v-for中的key

语法:key=“唯一值”

作用:给列表项添加的 唯一标识。便于Vue进行列表项的 正确排序复用。

为什么加key: Vue 的默认行为会尝试原地修改元素(就地复用

注意:

  1. key 的值只能是"字符串" 或 数字类型
  2. key 的值必须具有唯一性
  3. 推荐使用 id 作为 key(唯一),不推荐使用 index 作为 key(会变化,不对应)
    实例代码:
<ul>
  <li v-for="(item, index) in booksList" :key="item.id">
    <span>{{ item.name }}</span>
    <span>{{ item.author }}</span>
    <button @click="del(item.id)">删除</button>
  </li>
</ul>

十六、双向绑定指令 表单元素 (v-model=“变量” data里准备 变量=‘’ ) 账号密码输入框

所谓双向绑定就是:

  1. 用调试工具 将数据改变后,呈现的页面结果会更新
  2. 页面结果更新后,调试工具上的 数据也会随之而变

作用:表单元素(input、radio、select)使用,
双向绑定数据,可以快速 获取设置 表单元素内容

**语法:**v-model=“变量”

**需求:**使用双向绑定实现以下需求

  1. 点击登录按钮获取表单中的内容 双向绑定
  2. 点击重置按钮清空表单中的内容 变成 空’’
<div id="app">
    账户:<input type="text" v-model="username"> <br><br>
    密码:<input type="password" v-model="password"> <br><br>
    <button @click="login">登录<tton>
    <button @click="reset">重置<tton>
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
          /* 此处username与账户那行的v-model进行双向绑定  
             password与密码那行的v-model进行双向绑定       */
        username: '', 
        password: ''

      },
      methods:{
          login(){
              /* 想要拿到 账户 和  密码 的数据*/
          console.log(this.username,this.password)

          },
          reset(){
              /*重置数据 */
               this.username: '', 
               this.password: ''
          }
      }
    })
  </script>

十七、综合案例-小黑记事本 输入框添加 点击删除 合计(总的统计) 清空

功能需求:

  1. 列表渲染
    准备想要渲染的数据
    list:[ 对象 ]

v-for渲染 写在li里边
v-for=“( item,index ) in list”:key=" item.id "
{{ item.属性名 }}

  1. 删除功能

注册点击事件
@click=" del(item.id) "

方法:
methods:{
del(id){
this.list=this.list.filter(item => item.id!==id)
}
}

  1. 添加功能
    1.实现 v-model 双向绑定
    v-model=“task” 在input标签里记得加!!

data{
task=“”
}
2.点击添加 往最前面加:
@click=“add”

add(){

if(this.task.trim() ===‘’) {
alert(‘请输入任务’)
}else{
this.list.unshift({

id: +new Date( ),
name: this.task
})

this.task=""
}

}

  1. 底部统计 和 清空
    底部统计 统计总数量 即 list.length 数组个数 list.length-1是下标最大值
    {{ list.length }}

清空 即把原数组清空
@click=“clear()”
clear(){
this.list=[]
}
此时没有任务,可优化页面,把合计那行的内容隐藏掉
v-show=“判断条件”
v-show=" list.length > 1 "

day02

一、今日学习目标

1.指令补充

  1. 指令修饰符
  2. v-bind对样式增强的操作
  3. v-model应用于其他表单元素

2.computed计算属性

  1. 基础语法
  2. 计算属性vs方法
  3. 计算属性的完整写法
  4. 成绩案例

3.watch侦听器

  1. 基础写法
  2. 完整写法

4.综合案例 (演示)

  1. 渲染 / 删除 / 修改数量 / 全选 / 反选 / 统计总价 / 持久化

二、指令修饰符

1.什么是指令修饰符?

​ 所谓指令修饰符就是通过 “.” 指明一些指令后缀 不同的后缀封装了不同的处理操作 —> 简化代码

2.按键修饰符 回车键执行语句 @keyup.enter=" 事件 "

  • @keyup.enter —>当点击enter键的时候才触发
    一般和 输入框的某个按键 共用一种功能(方法)

代码演示:

  <div id="app">
    <h3>@keyup.enter  →  监听 键盘回车 事件</h3>
    <input v-model="username" type="text" @keyup.enter="add">{/* 例如回车添加 */}
  </div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        username: ''
      },
      methods: {
        
      }
    })
  </script>

3.v-model修饰符 .trim .number

  • v-model.trim —>去除首位空格 防止输入框空格占位置
  • v-model.number —>转数字 字符串转数字,比如年龄 qq账号 (a,b,c这种不可以)

4.事件修饰符 没遇到过

  • @事件名.stop —> 阻止冒泡
  • @事件名.prevent —>阻止默认行为
  • @事件名.stop.prevent —>可以连用 即阻止事件冒泡也阻止默认行为
 <style>
    .father {
      width: 200px;
      height: 200px;
      background-color: pink;
      margin-top: 20px;
    }
    .son {
      width: 100px;
      height: 100px;
      background-color: skyblue;
    }
  </style>

 <div id="app">
    <h3>v-model修饰符 .trim .number</h3>
    姓名:<input v-model.trim="username" type="text"><br>
    年纪:<input v-model.number="age" type="text"><br>

    
    <h3>@事件名.stop     →  阻止冒泡</h3>
    <div @click="fatherFn" class="father">
      <div @click="sonFn" class="son">儿子</div>
    </div>

    <h3>@事件名.prevent  →  阻止默认行为</h3>
    <a @click.stop href="http://www.baidu.com">阻止默认行为</a>
  </div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        username: '',
        age: '',
      },
      methods: {
        fatherFn () {
          alert('老父亲被点击了')
        },
        sonFn (e) {
          // e.stopPropagation()
          alert('儿子被点击了')
        }
      }
    })
  </script>

三、v-bind对样式控制的增强-操作class 通过布尔值动态控制css选择器

为了方便开发者进行样式控制, Vue 扩展了 v-bind 的语法,可以针对 class 类名style 行内样式 进行控制 。

1.语法:

<div> :class = "对象/数组">这是一个divdiv>

2.对象语法

当class动态绑定的是对象时,键就是类名选择器,值就是布尔值,如果值是true,就有这个类,否则没有这个类

<div class="box" :class="{ 类名选择器: 布尔值, 类名选择器: 布尔值 }">div>

​ 适用场景:一个类名选择器,来回切换
高亮导航栏:点击(@click=“activeIndex = index”) data写个activeIndex = 0 记录高亮的下标默认0
就切换某个类名 (:class=“{类名:记录高亮的下标activeIndex === v-for下标index}”) 实现高亮

3.数组语法

当class动态绑定的是数组时 → 数组中所有的类,都会添加到盒子上,本质就是一个 class 列表

<div class="box" :class="[ '类名选择器', '类名选择器2', '类名选择器3' ]">div>  一加上就使用这些选择器里的样式

使用场景:批量添加或删除类

4.代码练习

 <style>
    .box {
      width: 200px;
      height: 200px;
      border: 3px solid #000;
      font-size: 30px;
      margin-top: 10px;
    }
    .pink {
      background-color: pink;
    }
    .big {
      width: 300px;
      height: 300px;
    }
  style>


<div id="app">
    
    <div class="box" :class="{ pink:true,big:true }">黑马程序员div>
    
    <div class="box" :class="['pink','big']">黑马程序员div>
  div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {

      }
    })
  script>

四、京东秒杀-tab栏切换导航高亮 v-bind:class={ 选择器: 布尔值 } 点哪哪亮导航栏

1.需求:

​ 当我们点击哪个tab页签时,哪个tab页签就高亮
高亮导航栏:点击(@click=“activeIndex = index”) activeIndex = 0 记录高亮的下标默认0
就切换某个类名 (:class=“{类名:记录高亮的下标activeIndex === v-for下标index}”) 实现高亮

2.准备代码:

 <style>
    * {
      margin: 0;
      padding: 0;
    }
    ul {
      display: flex;
      border-bottom: 2px solid #e01222;
      padding: 0 10px;
    }
    li {
      width: 100px;
      height: 50px;
      line-height: 50px;
      list-style: none;
      text-align: center;
    }
    li a {
      display: block;
      text-decoration: none;
      font-weight: bold;
      color: #333333;
    }
    li a.active {
      background-color: #e01222;
      color: #fff;
    }

  style>

<div id="app">
    <ul>                                                
      <li v-for="(item,index) in list":key="item.id" @click="activeIndex = index">
        <a :class="{active:'activeIndex === index'}" href="#" >{{item.name}}a>
      li>
    ul>
  div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        activeIndex = 0,
        list: [
          { id: 1, name: '京东秒杀' },
          { id: 2, name: '每日特价' },
          { id: 3, name: '品类秒杀' }
        ]
      }
    })
  script>

3.思路:

1.基于数据,动态渲染tab(v-for)

2.准备一个下标 记录高亮的是哪一个 tab

3.基于下标动态切换class的类名

五、v-bind对有样式控制的增强-操作style v-bind:style=“{ CSS属性名1: ‘CSS属性值’, CSS属性名2: ‘CSS属性值’ }”

1.语法

<div class="box" :style="{ CSS属性名1: 'CSS属性值', CSS属性名2: 'CSS属性值' }">div>

注意有bg-color这种有 杠 的要引号引起来 ‘cg-color’
属性值要 ‘’,否则会报错

2.代码练习

<style>
    .box {
      width: 200px;
      height: 200px;
      background-color: rgb(187, 150, 156);
    }
 style>
 <div id="app">
    <div class="box" :style="{ width: '400px','background-color':'red' }">div>
  div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {

      }
    })
  script>

3.进度条案例 底层原理:大盒子里有小盒子,修改小盒子宽度即可

准备一个变量记录百分比,将来改那个变量即可

 <style>
    .progress {
      height: 25px;
      width: 400px;
      border-radius: 15px;
      background-color: #272425;
      border: 3px solid #272425;
      box-sizing: border-box;
      margin-bottom: 30px;
    }
    .inner {
      width: 50%;
      height: 20px;
      border-radius: 10px;
      text-align: right;
      position: relative;
      background-color: #409eff;
      background-size: 20px 20px;
      box-sizing: border-box;
      transition: all 1s;
    }
    .inner span {
      position: absolute;
      right: -20px;
      bottom: -25px;
    }
  style>

<div id="app">
    <div class="progress">
      <div class="inner" :style="{ width: percent + '%' }">
        <span>50%span>
      div>
    div>
    <button @click="schedule(25)">设置25%button>
    <button @click="schedule(50)">设置50%button>
    <button @click="schedule(75)">设置75%button>
    <button @click="schedule(100)">设置100%button>
  div>

  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
      percent:0,
      },
      methods:{
        schedules(value){
            this.percent = value
        }
      }
    })
  script>

六、v-model在其他表单元素的使用

  (v-model="变量"   data里准备 变量='' / 布尔值)      form表单里的都能用!!!
  表单元素的 获取 与 绑定

1.讲解内容:

常见的表单元素都可以用 v-model 绑定关联 → 快速 获取设置 表单元素的值

它会根据 控件类型 正确的方法 来更新元素

输入框  input:text   ——> value
文本域  textarea	 ——> value
复选框  input:checkbox  ——> checked
单选框  input:radio   ——> checked
下拉菜单 select    ——> value
...

2.代码准备

 <style>
    textarea {
      display: block;
      width: 240px;
      height: 100px;
      margin: 10px 0;
    }
  style>
 <div id="app">
    <h3>小黑学习网h3>
    姓名:
      <input type="text" v-model="username"> 
      <br><br>

      
    是否单身:
      <input type="checkbox" v-model="isSingle"> 
      <br><br>

    
    性别: 
      <input type="radio" name="gender" value:"1" v-model="gender"><input type="radio" name="gender" value:"2" v-model="gender"><br><br>

    
    所在城市:
      <select v-model="cityId">
        <option value='101'>北京option>
        <option value='102'>上海option>
        <option value='103'>成都option>
        <option value='104'>南京option>
      select>
      <br><br>
    自我描述:
    
      <textarea v-model="desc">textarea> 
    <button>立即注册button>
  div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        /* 姓名 */
        username:'',
        isSingle:ture,
        gender:1,
        cityId:102,
        desc:''
      }
    })
  script>

七、computed计算属性 动态灵活计算,设置自动计算的computed方法

1.概念

基于 现有 的数据,计算出来的 新属性。
依赖的数据变化,自动重新计算。

2.语法

  1. 声明在 computed 配置项中,一个计算属性对应一个函数
  2. 使用起来和普通属性一样使用 {{ 计算属性名}}
    computed()}{
    let 算的啥 = 算算算。。。
    算总数(总和,求和,求累积和)的方法名reduce( (sum,item) => 对参数进行计算xxx,起始值0)
  return 算的啥

}

3.注意

  1. computed配置项和data配置项是同级
    data:{},
    computed:{}

  2. computed中的计算属性虽然是函数的写法,但他依然是个属性
    所以引用时也是{{ computed方法名 }}

  3. computed中的计算属性

  4. 使用computed中的计算属性和使用data中的属性是一样的用法
    虽是方法,但是不加(),懂?

  5. computed中计算属性内部的 this 依然指向的是Vue实例
    比如找data中list的值num, this.list.num

  6. 计算出的东西要return
    computed()}{
    let 算的啥 = 算算算。。。
    算总数(总和)的方法名reduce( (sum,item) => 对参数进行计算xxx,起始值0)

  return 算的啥

}

4.案例

比如我们可以使用计算属性实现下面这个业务场景

5.代码准备

<style>
    table {
      border: 1px solid #000;
      text-align: center;
      width: 240px;
    }
    th,td {
      border: 1px solid #000;
    }
    h3 {
      position: relative;
    }
  style>

<div id="app">
    <h3>小黑的礼物清单h3>
    <table>
      <tr>
        <th>名字th>
        <th>数量th>
      tr>
      <tr v-for="(item, index) in list" :key="item.id">
        <td>{{ item.name }}td>
        <td>{{ item.num }}个td>
      tr>
    table>

    
    <p>礼物总数:{{totalNum}} 个p>
  div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        // 现有的数据
        list: [
          { id: 1, name: '篮球', num: 1 },
          { id: 2, name: '玩具', num: 2 },
          { id: 3, name: '铅笔', num: 5 },
        ]
      },
      computed:{
        totalNum(){
          /* 求累计和,算总数 */
         let total = this.list.reduce((sum,item) => sum+item.num,0) 
         return total
        }
      }
    })
  script>

八、computed计算属性 VS methods方法

1.computed计算属性

作用:封装了一段对于数据的处理,求得一个结果

语法:

  1. 写在computed配置项中
  2. 作为属性,直接使用
    • js中使用计算属性: this.计算属性
    • 模板中使用计算属性:{{计算属性}}

2.methods计算属性

作用:给Vue实例提供一个方法,调用以处理业务逻辑

语法:

  1. 写在methods配置项中
  2. 作为方法调用
    • js中调用:this.方法名()
    • 模板中调用 {{方法名()}} 或者 @事件名=“方法名”

3.计算属性的优势

  1. 缓存特性(提升性能)

    计算属性会对计算出来的结果缓存,再次使用直接读取缓存,

    依赖项变化了,会自动重新计算 → 并再次缓存

  2. methods没有缓存特性

  3. 通过代码比较

<style>
    table {
      border: 1px solid #000;
      text-align: center;
      width: 300px;
    }
    th,td {
      border: 1px solid #000;
    }
    h3 {
      position: relative;
    }
    span {
      position: absolute;
      left: 145px;
      top: -4px;
      width: 16px;
      height: 16px;
      color: white;
      font-size: 12px;
      text-align: center;
      border-radius: 50%;
      background-color: #e63f32;
    }
  style>

<div id="app">
    <h3>小黑的礼物清单<span>?span>h3>
    <table>
      <tr>
        <th>名字th>
        <th>数量th>
      tr>
      <tr v-for="(item, index) in list" :key="item.id">
        <td>{{ item.name }}td>
        <td>{{ item.num }}个td>
      tr>
    table>

    <p>礼物总数:{{ totalCount }} 个p>
  div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        // 现有的数据
        list: [
          { id: 1, name: '篮球', num: 3 },
          { id: 2, name: '玩具', num: 2 },
          { id: 3, name: '铅笔', num: 5 },
        ]
      },
      computed: {
        totalCount () {
          /* 算总数 累计和 reduce */
          let total = this.list.reduce((sum, item) => sum + item.num, 0)
          return total
        }
      }
    })
  script>

4.总结

1.computed有缓存特性,methods没有缓存

2.当一个结果依赖其他多个值时,推荐使用计算属性

3.当处理业务逻辑时,推荐使用methods方法,比如事件的处理函数

九、计算属性的完整写法 修改计算属性 全选反选

既然计算属性也是属性,能访问,应该也能修改了?

  1. 计算属性默认的简写,只能读取访问,不能 直接"修改"

  2. 如果要 “修改” → 需要写计算属性的完整写法( 获取get +设置set )

    computed:{
    计算属性名:{

    get() {
    计算逻辑
    return 结果 (结果赋值给计算属性名)
    },

    set(修改的值value){
    修改逻辑
    }
    }
    }

完整写法代码演示

 <div id="app">
    姓:<input type="text" v-model="firstName"> +
    名:<input type="text" v-model="lastName"> =
    <span>{{fullName}}span><br><br> 
    <button @click="change()">改名卡button>
  div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
 		    firstName: '刘',
        lastName: '备'
      },
      computed: {
       fullName:{
        get(){
        return this.firstname + this.lastname
        },
        set(value){  /* value即 上面的 return */
          this.firstname=value.slice(0,1)   /* 拆分字符串:下标0-1 下标1之后所有 */
          this.lastname=value.slice(1)
        }
       }
      },
      methods: {
          change(){
            this.fullName = '卢西奥'
          }
      }
    })
  script>

十、综合案例-成绩案例 渲染 删除 添加 求和、平均分(保留小数2)

功能描述:

1.渲染功能
v-for=“(item,index) in list”:key=“item.id”
list:[]
{{item…}}

2.删除功能
@click=“del(item.id)”
del(id){
this.list = this.list.fliter(item => item.id !== id)
}

3.添加功能
v-model=“subject”
v-model=“score”

subject=“”
score=“”

@click=“add”
add() {
if( !this.subject){
alert(‘请输入科目’)
return
}
if(typeof this.score !== ‘number’){
alert(‘请输入正确的分数’)
return
}
this.list.unshift({
id: +new Date(),
subject: this.subject,
score: this.score
}) ,

this.subject=“”
this.score=“”
}

4.统计总分,求平均分 求和函数
{{totalScore}}
{{avgScore}}

computed:{
totalScore(){
let score =this.list.reduce((sum,item) => sum+item.score,0)
return score
},
avgScore(){
if(this.list.length===0){
return 0
}
let avg = this.totalScore / this.list.length
return avg.toFixed
}保留两位小数
}

思路分析:

1.渲染功能 v-for :key v-bind:动态绑定class的样式

2.删除功能 v-on绑定事件, 阻止a标签的默认行为

3.v-model的修饰符 .trim、 .number、 判断数据是否为空后 再添加、添加后清空文本框的数据

4.使用计算属性computed 计算总分和平均分的值

十一、watch侦听器(监视器)

1.作用:

监视数据变化,执行一些业务逻辑或异步操作

2.语法:

  1. watch同样声明在跟data同级的配置项中

  2. 简单写法: 简单类型数据直接监视

  3. 完整写法:添加额外配置项

    
    v-model ="words"
    或
    v-model ="obj.words"
    
    data: { 
      words: '苹果',obj: {
        words: '苹果'
      }
    },
        M416
    watch: {
      // 该方法会在数据变化时,触发执行
      /* 数据属性名要与data里的名字同名,一旦上面变化下面也会 根据数据的变化 调用方法 */
      /* 不是对象写法 ,老值oldValue 根据需要写,一般不写*/
      数据属性名 (newValue, oldValue) {
        一些业务逻辑 或 异步操作。 
      },/* 对象写法 */
      '对象.属性名' (newValue, oldValue) {
        一些业务逻辑 或 异步操作。 
      }
    }
    

3.侦听器代码准备

 <style>
      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
        font-size: 18px;
      }
      #app {
        padding: 10px 20px;
      }
      .query {
        margin: 10px 0;
      }
      .box {
        display: flex;
      }
      textarea {
        width: 300px;
        height: 160px;
        font-size: 18px;
        border: 1px solid #dedede;
        outline: none;
        resize: none;
        padding: 10px;
      }
      textarea:hover {
        border: 1px solid #1589f5;
      }
      .transbox {
        width: 300px;
        height: 160px;
        background-color: #f0f0f0;
        padding: 10px;
        border: none;
      }
      .tip-box {
        width: 300px;
        height: 25px;
        line-height: 25px;
        display: flex;
      }
      .tip-box span {
        flex: 1;
        text-align: center;
      }
      .query span {
        font-size: 18px;
      }

      .input-wrap {
        position: relative;
      }
      .input-wrap span {
        position: absolute;
        right: 15px;
        bottom: 15px;
        font-size: 12px;
      }
      .input-wrap i {
        font-size: 20px;
        font-style: normal;
      }
    style>

 <div id="app">
      
      <div class="query">
        <span>翻译成的语言:span>
        <select>
          <option value="italy">意大利option>
          <option value="english">英语option>
          <option value="german">德语option>
        select>
      div>

      
      <div class="box">
        <div class="input-wrap">
          <textarea v-model="words">textarea>
          <span><i>⌨️i>文档翻译span>
        div>
        <div class="output-wrap">
          <div class="transbox">meladiv>
        div>
      div>
    div>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js">script>
    <script>
      // 接口地址:https://applet-base-api-t.itheima.net/api/translate
      // 请求方式:get
      // 请求参数:
      // (1)words:需要被翻译的文本(必传)
      // (2)lang: 需要被翻译成的语言(可选)默认值-意大利
      // -----------------------------------------------
      
      const app = new Vue({
        el: '#app',
        data: {
          words: ''
        },
        // 具体讲解:(1) watch语法 (2) 具体业务实现
        watch:{
          /* 第一种 */
          words (newValue){
            word变,执行这行的代码
          } 
          /* 第二种 */
          'obj.words' (newValue){
            obj.words变,执行这行代码
          }
        }
      })
    script>

SCART

十二、翻译案例-代码实现

  <script>
      // 接口地址:https://applet-base-api-t.itheima.net/api/translate
      // 请求方式:get
      // 请求参数:
      // (1)words:需要被翻译的文本(必传)
      // (2)lang: 需要被翻译成的语言(可选)默认值-意大利
      // -----------------------------------------------
      
      const app = new Vue({
        el: '#app',
        data: {
           //words: ''
           obj: {
            words: '',
            lang:'italy'
          },
          result: '', // 翻译结果
          // timer: null // 延时器id
        },
        // 具体讲解:(1) watch语法 (2) 具体业务实现
        watch: {
          // 该方法会在数据变化时调用执行
          // newValue新值, oldValue老值(一般不用)
          // words (newValue) {
          //   console.log('变化了', newValue)
          // }
         
          'obj.words' (newValue) {
            // console.log('变化了', newValue)
            // 防抖: 延迟执行 → 干啥事先等一等,延迟一会,一段时间内没有再次触发,才执行
            clearTimeout(this.timer)  /*解决bug: 一段时间内频繁输入,虽然延迟但是最终都执行了n多次 */
            this.timer = setTimeout(async () => {
              const res = await axios({
                url: 'https://applet-base-api-t.itheima.net/api/translate',
                params: {      /* get请求参数的名字 */
                  words: newValue
                }
              })
              this.result = res.data.data   
              console.log(res.data.data)  /* res是接口回复的内容 */
            }, 300)
          },
          AK47



       {/* 
           'obj.italy' (newValue){
            clearTimeout( this.timer )
            setTimeout( async () =>{
              const res = await axios({
              url:"https://applet-base-api-t.itheima.net/api/translate",
              method:'get',
              params:{
                lang:newValue
              }
            }),
            console.log( res.data.data )
            this.result = res.data.data
               },300) */}
            
          }

        }
      })
    </script>

十三、watch侦听器

1.语法

完整写法 —>添加额外的配置项

  1. deep:true 对复杂类型进行深度监听
  2. immdiate:true 初始化 立刻执行一次
data: {
  
  obj: {
    words: '苹果',
    lang: 'italy'
  },
},

watch: {// watch完整写法
  对象: {                       /* 不一定是对象,数组 包 对象也行 */
    deep: true, // 深度监视
    immediate:true,//立即执行handler函数  
    handler (newValue) {
      console.log(newValue) 
    }
  }
}

2.需求

  • 当文本框输入的时候 右侧翻译内容要时时变化
  • 当下拉框中的语言发生变化的时候 右侧翻译的内容依然要时时变化
  • 如果文本框中有默认值的话要立即翻译

3.代码实现

 <script> 
      const app = new Vue({
        el: '#app',
        data: {
          obj: {
            words: '小黑',
            lang: 'italy'
          },
          result: '', // 翻译结果
        },
        watch: {
          obj: {
            deep: true, // 深度监视
            immediate: true, // 立刻执行,一进入页面handler就立刻执行一次
            handler (newValue) {
              clearTimeout(this.timer)
              this.timer = setTimeout(async () => {
                const res = await axios({
                  url: 'https://applet-base-api-t.itheima.net/api/translate',
                  params: newValue
                })
                this.result = res.data.data
                console.log(res.data.data)
              }, 300)
            }
          } 
        }
      })
    </script>

4.总结

watch侦听器的写法有几种?

1.简单写法

watch: {
  数据属性名 (newValue, oldValue) {
    一些业务逻辑 或 异步操作。 
  },
  '对象.属性名' (newValue, oldValue) {
    一些业务逻辑 或 异步操作。 
  }
}

2.侦听器完整写法

watch: {// watch 完整写法
  数据属性名: {     // 例如obj,对象名,数组名
    deep: true, // 深度监视(针对复杂类型) 可以把对象里的所有属性都监视到
    immediate: true, // 是否立刻执行一次handler  例如默认翻译
    handler (newValue) {
      console.log(newValue)
    }
  }
}

十四、综合案例水果购物车 渲染 删除 修改个数 +1-1 全选反选 持久化到本地

购物车案例

需求说明:

  1. 渲染功能
    有俩块,有商品显示上面的商品块,无商品时出现空空如也,用到v-if v-else

选中状态 v-model=“item.isCheck”

可以直接在渲染处算小计 item.num *item.price

选中时才变暗 用到v-bind:class=“{ active : item.isCheck }”

list:[{}]
v-for=“(item,index) in list”:key=“item.id”

  1. 删除功能
    @click=“del(item.id)”
    del(id){
    this.list = this.list.filter( item => item.id !== id )
    }

  2. 修改个数 +1 -1
    @click = add(item.id)
    @click = sub(item.id)

add(id){
const fruit = this.list.find(item => item.id ===id )
fruit.num++
}

有bug: -1…
解决:减号按钮加禁用 :disabled =" item.num <= 1 "

  1. 全选反选 注意用computed完整写法 获取get + 设置set
    首先,确保渲染时双向绑定了 数组里的isChecked属性 (标签里有checked记得删除)
    v-model=“item.isChecked”

v-model=“isAll” 全选位置

computed:{

isAll:{
get(){
let allChoice = this.list.every( item => item.isCheck === true )
return allChoice
},
set(value){
let notAll = this.list.forEach( item => item.isCheck =value )
return notAll
}
}

}

  1. 统计 选中的 总价 和 总数量
    {{ totalNum }}
    {{ totalPrice }}

computed:{

totalNum(){
    let num = this.list.reduce((sum,item) =>sum + item.num,0)
    return num
}
totalPrice(){
    let price - this.list.reduce((sum,item) => sum+item.num * item.price,0)
}

}

  1. 持久化到本地 AK47
    存储本地 localStorage.setItem( 键,值 )

读取JSON语法: localStorage.getItem( )

键自定义,值如果是 对象就转成字符串JSON.stringifly(newValue)

字符串转成对象: JSON.parse( ‘fruitList’ )

watch:{
list:{
deep:true,
handler(newValue){
localStorage.setItem(‘fruitList’,Json.stringifly(newValue))

  }
}

}

const initData = [初始化的数据]

data:{
list:JSON.parse(localStorage.getItem(‘fruitList’)) || defaultArr

}

实现思路:

1.基本渲染: v-for遍历、:class动态绑定样式

2.删除功能 : v-on 绑定事件,获取当前行的id

3.修改个数 : v-on绑定事件,获取当前行的id,进行筛选出对应的项然后增加或减少

4.全选反选

  1. 必须所有的小选框都选中,全选按钮才选中 → every
  2. 如果全选按钮选中,则所有小选框都选中
  3. 如果全选取消,则所有小选框都取消选中

声明计算属性,判断数组中的每一个checked属性的值,看是否需要全部选

5.统计 选中的 总价 和 总数量 :通过计算属性来计算选中的总价和总数量

6.持久化到本地: 在数据变化时都要更新下本地存储 watch

day03

一、今日目标

1.生命周期

  1. 生命周期介绍
    vue生命周期:一个Vue实例从 创建 到 销毁 的过程
    new Vue( )

  2. 生命周期的四个阶段
    创建阶段
    挂载阶段
    更新阶段
    销毁阶段

  3. 生命周期钩子

  4. 声明周期案例

2.综合案例-小黑记账清单

  1. 列表渲染
  2. 添加/删除
  3. 饼图渲染

3.工程化开发入门 之前是引入官方链接 这里开始是建项目

  1. 工程化开发和脚手架
  2. 项目运行流程
  3. 组件化
  4. 组件注册

4.综合案例-小兔仙首页

  1. 拆分模块-局部注册
  2. 结构样式完善
  3. 拆分组件 – 全局注册

二、Vue生命周期

思考:什么时候可以发送初始化渲染请求?(越早越好)什么时候可以开始操作dom?(至少dom得渲染出来)

Vue生命周期:就是一个Vue实例从创建 到 销毁 的整个过程。

生命周期四个阶段:① 创建 ② 挂载 ③ 更新 ④ 销毁

1.创建阶段:创建响应式数据
data:{
title:‘数据’,
msg:‘数据1’
}

           1后 发送初始化渲染请求 (created钩子)

2.挂载阶段:渲染模板
{{ title }}
{{ msg }}

          2后 操作dom 渲染之后才可以  ( mounted钩子)

3.更新阶段:修改数据,更新视图(用户一般也是使用这个阶段) 会执行多次
例如计时器:

  • 100 +

4.销毁阶段:销毁Vue实例
例如 关闭浏览器

三、Vue生命周期钩子

Vue生命周期过程中,会自动运行一些函数,被称为【生命周期钩子】→ 让开发者可以在【特定阶段】运行自己的代码

<div id="app">
    <h3>{{ title }}h3>
    <div>
      <button @click="count--">-button>
      <span>{{ count }}span>
      <button @click="count++">+button>
    div>
  div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
  <script>
    const app = new Vue({
      el: '#app',
      data: {
        count: 100,
        title: '计数器'
      },
      // 1. 创建阶段(准备数据)
     beforeCreate(){
         console.log('beforeCreate 响应式数据准备好之前')
     },
           < 这个阶段创建响应式数据 >
     created(){
         console.log('beforeCreate 响应式数据准备好之前')
         发送初始化渲染请求 
     }
      // 2. 挂载阶段(渲染模板)
      beforeMount(){
        console.log('beforeMount 模版渲染之前')
      },
      < 这个时候数据已经渲染完成 >
     mounted(){
        console.log('mounted 模版渲染之后')
        操作dom  渲染之后才可以(操作dom:修改数据或者方法...}
      // 3. 更新阶段(修改数据 → 更新视图)
      beforeUpdate(){
         console.log('beforeUpdate 数据修改了,试图还没更新')
      },

      updated(){
         console.log('updated 数据修改了,试图已经更新')
      }
      // 4. 卸载阶段
     beforeDestroy(){
             console.log('beforeDestroy 卸载前')
               清除掉一些Vue以外的资源占用,定时器,延时器......(结合组件)
     },
     
     destroyed(){
         console.log('destroyed 卸载后')
     }

    })
  script>

四、生命周期钩子小案例

1.在created中发送数据 发送请求获取数据渲染列表 created(){}

 <style>
    * {
      margin: 0;
      padding: 0;
      list-style: none;
    }
    .news {
      display: flex;
      height: 120px;
      width: 600px;
      margin: 0 auto;
      padding: 20px 0;
      cursor: pointer;
    }
    .news .left {
      flex: 1;
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      padding-right: 10px;
    }
    .news .left .title {
      font-size: 20px;
    }
    .news .left .info {
      color: #999999;
    }
    .news .left .info span {
      margin-right: 20px;
    }
    .news .right {
      width: 160px;
      height: 120px;
    }
    .news .right img {
      width: 100%;
      height: 100%;
      object-fit: cover;
    }
  style>

 <div id="app">
    <ul>
      <li class="news" v-for="(item,index) in list":key="item.id">
        <div class="left">
          <div class="title">{{item.title}}div>
          <div class="info">
            <span>{{ source }}span>
            <span>{{ item.time }}span>
          div>
        div>
        <div class="right">
          <img v-bind:src="item.img" alt="">
        div>
      li>
    ul>
  div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js">script>
  <script>
    // 接口地址:http://hmajax.itheima.net/api/news
    // 请求方式:get
    const app = new Vue({
      el: '#app',
      data: {
        list: []
      },
      async  created(){
      /*  发请求 axios    async const res=awiat */
      const res = await axios.get('http://hmajax.itheima.net/api/news')
      console.log(res)
      /* 得到数据,更新到 data 中的 list */
      this.list = res.data.data
      },
      mounted(){
       /* (操作dom:修改数据或者方法...) */
      }
    })
  script>

2.在mounted中获取焦点 一进页面立即获取焦点 mounted(){}

 <style>
    html,
    body {
      height: 100%;
    }
    .search-container {
      position: absolute;
      top: 30%;
      left: 50%;
      transform: translate(-50%, -50%);
      text-align: center;
    }
    .search-container .search-box {
      display: flex;
    }
    .search-container img {
      margin-bottom: 30px;
    }
    .search-container .search-box input {
      width: 512px;
      height: 16px;
      padding: 12px 16px;
      font-size: 16px;
      margin: 0;
      vertical-align: top;
      outline: 0;
      box-shadow: none;
      border-radius: 10px 0 0 10px;
      border: 2px solid #c4c7ce;
      background: #fff;
      color: #222;
      overflow: hidden;
      box-sizing: content-box;
      -webkit-tap-highlight-color: transparent;
    }
    .search-container .search-box button {
      cursor: pointer;
      width: 112px;
      height: 44px;
      line-height: 41px;
      line-height: 42px;
      background-color: #ad2a27;
      border-radius: 0 10px 10px 0;
      font-size: 17px;
      box-shadow: none;
      font-weight: 400;
      border: 0;
      outline: 0;
      letter-spacing: normal;
      color: white;
    }
    body {
      background: no-repeat center /cover;
      background-color: #edf0f5;
    }
  style>

<div class="container" id="app">
  <div class="search-container">
    <img src="https://www.itheima.com/images/logo.png" alt="">
    <div class="search-box">
      <input type="text" v-model="words" id="inp">
      <button>搜索一下button>
    div>
  div>
div>

<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
<script>
  const app = new Vue({
    el: '#app',
    data: {
      words: ''
    },
    /* 想要操作dom,就得等dom渲染完成之后mounted(){} */
    mounted(){
      /* 获取输入框id,再加上一个focus()方法即可 */
      document.querySelector('#inp').focus()
    }
  })
script>

五、案例-小黑记账清单

vue组件中使用echarts
导入echarts
npm install echarts -S

main.js中引入
import echarts from ‘echarts’
Vue.prototype.$echarts = echarts

组件中引入
import * as echarts from “echarts”;

Vue组件导入axios:
npm install vue-axios --save

main.js引用
import Vue from ‘vue’
import axios from ‘axios’

Vue.prototype.$axios = axios  
Vue.prototype.qs = qs

1.引包大全:

echarts vue axios

2.需求分析

1.基本渲染 基本渲染 created(){} 价格保留两位小数 超过xx价格变红 算总价格

准备响应式数据 数组list:[] 准备接收数据!!

发请求获取数据get
axios{
url:‘地址’,
method:‘GET’,

params:{
creator:‘小黑’ 文档里那个creator:string不要直接复制,string表示自己取的名字
}
}
封装请求 async const res = await

得到回复res console.log(res)

将得到的数据交给list this.list = res.data.data

v-for=“(item,index) in list”:key=“item.id”
{{ item… }}

{{ item.price.toFixed(2) }}

:class=“{red : item.price>xx }”

{{totalPrice.toFixed(2)}}

computed:{
totalPrice(){
let totalPr = this.list.reduce((sum,item) => sum + item.price ,0)
return totalPr
}
}

2.俩输入框输入内容实现添加功能 操作dom mounted(){}

comName=‘’,
comPrice=‘’

v-model.trim=“comName”
v-model.number=“comPrice”

@click=“add”

发送添加请求post
methods:{
async add(){

if(!this.comName){
alert(‘请输入商品名称’)
return
}

if(typeof this.comPrice !== ‘number’){
alert(‘请输入商品价格’)
return
}
const res = axios({
url:‘地址’,
method:‘POST’,

   data:{
      "creator": "小黑",
      "name": this.comName,
      "price": this.comPrice
   }
}),
console.log(res)
this.xuanRan()   
this.comName=''
this.comPrice=''

},

async xuanRan(){

const res = axios({
url:‘地址’,
method:‘GET’,
params:{
creator:‘小黑’
}
}),
console.log(res.data.data)
this.list = res.data.data
}

}

3.删除功能 发请求,传id

@click=“del(item.id)”

async del(id){

const res= await axios({

url:地址..${id},
method:‘DELECT’
})
console.log(res)

this.xuanRan()
}

4.饼图渲染

1.初始化渲染
引包上面有
准备div盒子配上id=“main”
入门132写在mounted里边

mounted(){

this.myChart = echarts.init(document.getElementById(‘main’));

this.myChart.setOption(
{
title: {

text: ‘小黑记账清单’,

subtext: ‘’,

left: ‘center’
},

tooltip: {

trigger: ‘item’
},
legend: {

orient: ‘vertical’,
left: ‘left’
},
series: [
{
name: ‘小黑记账清单’,
type: ‘pie’,

radius: ‘50%’,
data: [ ],

emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: ‘rgba(0, 0, 0, 0.5)’
}
}
}
]
}
);
}

2.动态数据图

created的let myChart 改成 this.myChart
myChart.setOption 改成 this.myChart.setOption

渲染数据的
方法下继续加 this.myChart.setOption({
series: [
{
data: this.list.map(item => ({value:item.price,name:item.name}) ),


}/* 将数组里的每一个对象都进行转换处理
data: this.list.map((item) => ({value: item.price ,name:item.name })) /
/
返回的是对象会报错,系统判定对象是代码段,所以要加个括号 */
]
})

4.代码准备

 
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
    />
    <style>
      .red {
        color: red!important;
      }
      .search {
        width: 300px;
        margin: 20px 0;
      }
      .my-form {
        display: flex;
        margin: 20px 0;
      }
      .my-form input {
        flex: 1;
        margin-right: 20px;
      }
      .table > :not(:first-child) {
        border-top: none;
      }
      .contain {
        display: flex;
        padding: 10px;
      }
      .list-box {
        flex: 1;
        padding: 0 30px;
      }
      .list-box  a {
        text-decoration: none;
      }
      .echarts-box {
        width: 600px;
        height: 400px;
        padding: 30px;
        margin: 0 auto;
        border: 1px solid #ccc;
      }
      tfoot {
        font-weight: bold;
      }
      @media screen and (max-width: 1000px) {
        .contain {
          flex-wrap: wrap;
        }
        .list-box {
          width: 100%;
        }
        .echarts-box {
          margin-top: 30px;
        }
      }
    style>


  <div id="app">
      <div class="contain">
        
        <div class="list-box">

          
          <form class="my-form">
            <input type="text" class="form-control" placeholder="消费名称" />
            <input type="text" class="form-control" placeholder="消费价格" />
            <button type="button" class="btn btn-primary">添加账单button>
          form>

          <table class="table table-hover">
            <thead>
              <tr>
                <th>编号th>
                <th>消费名称th>
                <th>消费价格th>
                <th>操作th>
              tr>
            thead>

            <tbody>
              <tr>
                <td>1td>
                <td>帽子td>
                <td>99.00td>
                <td><a href="javascript:;">删除a>td>
              tr>
              <tr>
                <td>2td>
                <td>大衣td>
                <td class="red">199.00td>
                <td><a href="javascript:;">删除a>td>
              tr>
            tbody>
            <tfoot>
              <tr>
                <td colspan="4">消费总计: 298.00td>
              tr>
            tfoot>
          table>
        div>
        
        
        <div class="echarts-box" id="main">div>
      div>
    div>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/echarts.min.js">script>
    <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js">script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js">script>
    <script>
      /**
       * 接口文档地址:
       * https://www.apifox.cn/apidoc/shared-24459455-ebb1-4fdc-8df8-0aff8dc317a8/api-53371058
       * 
       * 功能需求:
       * 1. 基本渲染
       * 2. 添加功能
       * 3. 删除功能
       * 4. 饼图渲染
       */
      const app = new Vue({
        el: '#app',
        data: {

        },
      })
    script>

六、工程化开发和脚手架

1.开发Vue的两种方式

  • 核心包传统开发模式:基于html / css / js 文件,直接引入核心包,开发 Vue。
  • 工程化开发模式:基于构建工具(例如:webpack)的环境中开发Vue。
    比引包的好处是:把es6/TS less/sass 等语法转换成浏览器识别的语言js css…

工程化开发模式优点:

提高编码效率,比如使用JS新语法、Less/Sass、Typescript等通过webpack都可以编译成浏览器识别的ES3/ES5/CSS等

工程化开发模式问题:

  • webpack配置不简单
  • 雷同的基础配置
  • 缺乏统一的标准

为了解决以上问题,所以我们需要一个工具,生成标准化的配置

2.脚手架Vue CLI

基本介绍:

Vue CLI 是Vue官方提供的一个全局命令工具

可以帮助我们快速创建一个开发Vue项目的标准化基础架子。【集成了webpack配置】
其实就是项目目录,而且这文件帮咱配置好webpack,开袋即食

好处:
  1. 开箱即用,零配置
  2. 内置babel等工具
  3. 标准化的webpack配置
VueCli架子生成 使用步骤: 新电脑安装

PowerShell管理员身份打开

  1. 全局安装(只需安装一次即可) yarn global add @vue/cli 或者 npm i @vue/cli -g

  2. 查看vue/cli版本: vue --version

  3. 创建项目架子:vue create 项目名 (项目名不能使用中文)最好 cd 桌面文件夹路径再创
    选vue2

  4. 启动项目:yarn serve 或者 npm run serve
    (命令不固定,找package.json里的script 'serve’是哪个)
    浏览器搜索loalhost:8080 看到大V就是成功

七、项目目录介绍和运行流程

1.项目目录介绍 解释

项目名

  • node_modules 第三包文件夹

public 放 html 文件的地方
-favicon.ico 网站图标
-index . html

src 源代码目录→以后写代码的文件夹
L - assets 静态资源目录→存放图片、字体等
L - components 组件目录→存放通用组件
L - App.vue this.emit(‘changeTitle’,‘传智教育’) 2
}
}

c.父包子的标签 里边对子的数据进行监听 和 准备方法
@changeTitle = “changeFn” 2 3

d.父编写方法 实现子的请求
methods:{
changeFn(sonTitle){ 3
console.log( sonTitle )
this.myTitle = sonTitle
}
}

  1. 非父子关系(暂时没学)

6.父向子通信代码示例 父传子 子传父

父组件通过props将数据传递给子组件

父组件App.vue






子组件Son.vue






五、什么是props porops细节写法

传的是布尔值 渲染时可以写成{{ 布尔值 ? ‘是’ : ‘否’ }} 布尔值?真的输出这个:假的输这个

对象 {{ 对象名.属性名 }}

数组 {{ 数组.join(‘、’) }} 把数组中的元素分开,用 、 隔开 否则会输出数组的原始形态

1.Props 定义

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

2.Props 作用

向子组件传递数据

3.特点

  1. 可以 传递 任意数量 的prop
  2. 可以 传递 任意类型 的prop

4.代码演示

父组件App.vue






子组件UserInfo.vue






六、props校验 将props:[] 改成对象的写法

1.思考

组件的props可以乱传吗

2.作用

为组件的 prop 指定验证要求,不符合要求,控制台就会有错误提示 → 帮助开发者,快速发现错误

3.语法 将props:[] 改成对象的写法

  • 类型校验(最常用)
    props:{
    值:Number
    }

  • 非空校验

  • 默认值

  • 自定义校验
    写这三个要写完整写法

props: {
  校验的属性名: {  /* 也就是自定义 接收父给的数据 的名字,写在父里子 标签前面的 */
    type: 类型,  // Number String Boolean ...
    //required: true, // 是否必填
    default: 默认值, // 默认值给个0
    validator (value) {  /* value就是父传给子的值 */
      // 自定义校验逻辑
      if( ){
        return ture    /* 表示通过校验 */
      }else{
         console.error('传入的xxx 必须是...')
         return false
      }
    }
  }
},

default和required一般不同时写(因为当时必填项时,肯定是有值的)

4.代码演示 进度条 父传子props版

App.vue






BaseProgress.vue






七、props校验完整写法

1.语法

props: {
  校验的属性名: {
    type: 类型,  // Number String Boolean ...
    required: true, // 是否必填
    default: 默认值, // 默认值 0
    validator (value) {   /* value就是父传给子的值 */
      // 自定义校验逻辑
      return 是否通过校验
    }
  }
},

2.代码实例


3.注意

1.default和required一般不同时写(因为当时必填项时,肯定是有值的)

2.default后面如果是简单类型的值,可以直接写默认。如果是复杂类型的值,则需要以函数的形式return一个默认值

八、props&data、单向数据流:父的改,子的改

1.共同点

都可以给组件提供数据

2.区别

  • data 的数据是自己的 → 随便改
  • prop 的数据是外部的 → 不能直接改,要遵循 单向数据流

3.单向数据流:

父级props 的数据更新,会向下流动,影响子组件。这个数据流动是单向的

4.代码演示

App.vue 父组件






BaseCount.vue






5.口诀

谁的数据谁负责

九、综合案例-组件拆分版 小黑记事本 组件版

1.需求说明

- 拆分基础组件 拆积木

头部(TodoHeader)、
列表(TodoMain)、
底部(TodoFooter)

1.创组件写样式 main.js中导入css文件
import ‘./styles/index.css’ 导入了样式文件就不用再复制到组件里啦!!!

2.局部:App.vue中导入 + 注册 import 组件名 from ‘路径’ components:{组件名}

3.使用组件 < 组件名 >

- 渲染待办任务 数据 父传子 将来合计 列表都能用
  1. 父 提供数据 list:[{ id:1,name:‘打球’ }]

2.父传子 给列表组件 :sonList=list

3.子接收 props:{ sonList:Array } 规定传过来的要是个数组

3.渲染

- 组件添加任务 子传父添加请求 unshift不用赋值原数组

1.子注册 点击 和 回车 添加事件 v-model双向绑定输入框
v-model=“plan” @keyup.enter = “add”

@click=“add”

plan=‘’

2.向父发请求 ,将任务名称传给父
this.$emit( ‘wantAdd’, this.plan )

3.父监听 父添加
@wantadd = “dieAdd”
this.plan = “”

methods:{ ’

dieAdd(plan){
this.list.unshift({
id:+new Date(),
name:plan
})
}
}

- 组件删除任务 子传父删除请求 filter要赋值给原数组

1.子注册点击事件传id
@click = Del(item.id)

2.子发请求传id
Del( id) {
this.$emit(‘wantDel’, id)
}

3.父监听
@wantDel = “dieDel”

4.父删除方法
dieDel(id){
this.list = this.list.filter(item => item.id !== id)
}

- 底部合计 和 清空功能 算不是修改,所以不是子传父,父传子即可 清空是修改

a.底部合计 父传子数组,.length即可
1.父传子数据
:sonList = list

2.子接收数据
props:{
sonList:Array
}

3.子渲染个数
{{ list.length }}

b.清空 修改数据 子传父
1.子点击清空事件
@click = empty

2.子发想清空请求
this.$emit(‘wantEmpty’,)

3.父监听
@wantEmpty = dieEmpty

4.父清空数组 methods
dieEmpty(){
this.list = []
}

- 持久化存储 组件本地存储 watch深度监视 watch完整写法 在父里写

AK47
存储本地 localStorage.setItem( 键,值 )
读取 get ( )

键自定义,值如果是 对象就转成字符串 JSON.stringifly(newValue)
字符转对象 .parse( ‘存储的字符串名’ )
watch:{
list:{
deep:true,
handler( newValue ){
localStorage.getItem( ‘localObj’, JSON.stringifly(newValue) )
}
}
}

data:{
return{
list: JSON.parse(localStoage.getItem(‘localList’)) ||[ 默认对象的数据 ]
}
}

十四、非父子通信-event bus 事件总线 utils 同级关系传值

1.作用

非父子组件之间,进行简易消息传递。(复杂场景→ Vuex)

2.步骤

  1. 创建一个都能访问的事件总线 (空Vue实例) EventBus.js相当于中介
    往utils里创一个EventBus.js文件。直写:

    import Vue from 'vue'
    const Bus = new Vue()
    export default Bus
    
  2. A组件(发送方),触发事件的方式传递的参数(发布消息)点击按钮就发给A

    注册 点击事件
    @click = clickSend
    
    导入event bus
    import Bus from '../util/EventBus'
    
    发消息
    clickSend(){
       Bus.$emit('sendMsg', '这是一个消息')   /* 子想要修改父的数据也是用 $emit */
    }
    
    
  3. B组件(接受方)接收同级的请求消息,监听Bus的 $on事件 ( B可以有很多个 )

    导入 event bus
    import Bus from '../util/EventBus'
    
    created 接收数据  
    created () {
      /*在A中 监听Bus事件(订阅消息) */
      Bus.$on('sendMsg', (msg) => {
     /* $on:监听 'sendMsg':事件名,监听到消息后干啥 */
        console.log(msg)/* 查看有没有接收到消息 */
        this.msg = msg
      })
    }
    
    渲染
    data(){
        return{
        msg : ''
        /* 此时 msg = '这是一个消息'*/
        }
    }
    
    {{ msg }}
    
    

3.代码示例

EventBus.js 中介

import Vue from 'vue'
const Bus  =  new Vue()
export default Bus

BaseA.vue(发送方) 注册 导入 发消息

<template>
 <div class="base-b">
   <div>我是A组件(发布方)</div>  
   <button @click="clickSend" >发送消息</button>/* 注册事件 */
 </div>
</template>

<script>
import Bus from '../utils/EventBus'             /* 导入 */
export default {
    methods:{
        clickSend(){
          Bus.$emit('sendMsg', '这是一个消息')  /* 发消息 */
        }
    }
}
</script>

<style scoped>
.base-b {
 width: 200px;
 height: 200px;
 border: 3px solid #000;
 border-radius: 3px;
 margin: 10px;
}
</style>

BaseB.vue(接收方) 导入 接收 渲染

<template>
  <div class="base-a">
    我是B组件(接收方)
    <p>{{msg}}</p>                  /* 渲染 */
  </div>
</template>

<script>
import Bus from '../utils/EventBus' /* 导入 */

export default {
  data() {
    return {
      msg: '',                                  
    }
},
created () {    /* 接收数据 */
     /*在B中 监听Bus事件(订阅消息) */
     Bus.$on('sendMsg', (msg) => {
     /* $on:监听 'sendMsg':事件名,监听到消息后干啥 */
       console.log(msg)/* 查看有没有接收到消息 */
       this.msg = msg
    })
}

  
}
</script>

<style scoped>
.base-a {
  width: 200px;
  height: 200px;
  border: 3px solid #000;
  border-radius: 3px;
  margin: 10px;
}
</style>

App.vue






4.总结

1.非父子组件传值借助什么?
EventBus.js
import Vue from ‘vue’
const Bus = new Vue()
export default Bus

2.什么是事件总线
相当于 中介,一方发送 一方接受

3.发送方应该调用事件总线的哪个方法
Bus.$emit(‘事件名’ ,传值)

4.接收方应该调用事件总线的哪个方法
Bus.$on(( msg) => {
console.log( msg )
})

5.一个组件发送数据,可不可以被多个组件接收
可以

十五、非父子通信-provide&inject 爷孙级传数据 爷子孙级

1.作用

跨层级共享数据

2.场景

大块 包 中块 包 小块

3.语法

  1. 父组件 provide提供数据
export default {
  provide () {
    return {
       // 普通类型【非响应式】
       color: this.color, 
       // 复杂类型【响应式】  比如对象
       userInfo: this.userInfo, 
       obj:{ id:1, name:'牛木' }
    }
  }
}

2.子 、 孙组件 inject获取数据 在父子级中 inject 和 props 效果相同 ? 不同, inject里的 简单数据 不是响应式的 而父传子的props是

export default {
  inject: ['color','userInfo','obj'],
  created () {
    console.log(this.color, this.userInfo)
  }
}

3.子 、 孙渲染数据
{{ color }}
{{ obj.id }}
{{ obj.name }}

4.注意

  • provide提供的 , 复杂类型 数据是响应式。(推荐提供复杂类型数据) 通常包成对象
  • 子/孙组件通过inject获取的数据,不能在自身组件内修改

十六、v-model原理 在组件的用处

1.原理:

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

<template>
  <div id="app" >
    <input v-model="msg" type="text">
  =
    <input :value="msg" @input="msg = $event.target.value" type="text">
  </div>
</template>

<script>
export default{
  data(){
    return{
      meg : ''
    }
  }
} 
</script>

2.作用:

提供数据的双向绑定 v-model=‘绑定值’

  • 数据变,输入框视图跟着变 :value=“绑定值”
  • 输入框视图变,数据跟着变 @input="绑定值 = $event.target.value "

3.注意

$event 用于在模板中,获取事件的形参

4.代码示例

<template>
  <div class="app">
    <input type="text"  v-model="msg1"/>
    <br/> 
    <input type="text" :value="msg2"  @input="msg = $event.target.value" />
  </div>
</template>

<script>
export default {
  data() {
    return {
      msg1: '',
      msg2: '',
    }
  },
}
</script> 
<style>
</style>

5.v-model使用在其他表单元素上的原理

不同的表单元素, v-model在底层的处理机制是不一样的。比如给checkbox使用v-model

底层处理的是 checked属性和change事件。

不过咱们只需要掌握应用在文本框上的原理即可

十七、表单类组件封装 下拉框与v-model原理

曾经写法
北京
上海
成都
南京

子监听修改值 change

sonChange(e){ 拿到形参e
console.log(e.target.value) 拿到最新的值
this.$emit(‘wantChange’,e.target.value) 把最新的值传给父
}

父: @wantChange = "selectId = e v e n t " 有点特殊,此处是在组件标签处直接把父的 s e l e c t I d 修改成当前值 event" 有点特殊,此处是在组件标签处直接把父的selectId修改成当前值 event"有点特殊,此处是在组件标签处直接把父的selectId修改成当前值event

1.需求目标

实现子组件和父组件数据的双向绑定 (实现App.vue中的selectId和子组件选中的数据进行双向绑定)

2.代码演示

App.vue

<template>
  <div class="app">
    <BaseSelect :sonId="selectId" @wantChange="selectId=$event"></BaseSelect>
  </div>   {/* 简化v-model写法:v-model="selected" */}
</template>

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

<style>
</style>

BaseSelect.vue

<template>
  <div>  {/* 简化v-model写法: :value="value" ... */}
    <select :value="sonId" @change="sonChange">
      <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 {
  porps:{
    sonId:String  {/* 简化v-model写法:value:String */}
  },
  sonChange(e){
    cosole.log(e.target.value)
    this.$emit('wantChange',e.target.value)
  } {/* 简化v-model写法:'input',... */}
}
</script>

<style>
</style>

十八、v-model简化代码 下拉框代码简化版

1.目标:

父组件通过v-model 简化代码,实现子组件和父组件数据 双向绑定

2.如何简化:

v-model其实就是 :value和@input事件的简写

  • 子组件:props通过value接收数据,事件触发 input
  • 父组件:v-model直接绑定数据

3.代码示例

父组件

<BaseSelect v-model="selectId"></BaseSelect>

子组件

<select :value="value" @change="sonChange"> ... </select>
props: {
  value: String
},
/* 拿到输入框实时的值 */
methods: {
  sonChange (e) {
    this.$emit('input', e.target.value)
                      /* e.target表示选中下拉菜单 再.value表示拿到value值 */
  }
}

十九、.sync修饰符 按钮弹框 确认取消visible 不想用value名字 但想简化代码

步骤:
1.父传子一个布尔值,子进行v-show渲染 术语visible
isShow : false 父的值 默认不展示

:visible = isShow 父传值

props:{
visible:Boolean 子规定传来的要是布尔值
}

v-show = “visible” 弹窗块里加

2.父的按钮点击控制开关
@click =“isShow = true”

3.弹窗的各种操作反响

子想修改父的值,且不想是value,是其他的属性,加.sync
父的子标签 :visible.sync = isShow

取消 和 x按钮 关闭弹窗
@click=“close”

close(){
this.$emit(‘updata:visible’, false )
}
:visible.sync => :visible + @update:visible

1.作用

可以实现 子组件父组件数据双向绑定,简化代码

简单理解:子组件可以修改父组件传过来的props值

2.场景

封装弹框类的基础组件, visible属性 true显示 false隐藏

3.本质

.sync修饰符 就是 :属性名@update:属性名 合写

:visible.sync => :visible + @update:visible

4.语法

父组件

//.sync写法
<BaseDialog :visible.sync="isShow" />
--------------------------------------
//完整写法
<BaseDialog 
  :visible="isShow" 
  @update:visible="isShow = $event" 
/>

子组件

props: {
  visible: Boolean
},

this.$emit('update:visible', false)

5.代码示例

App.vue

<template>
  <div class="app">
    <button @click="isShow=true">退出按钮</button>
    <BaseDialog :visible.sync="isShow" ></BaseDialog>
  </div>
</template>

<script>
import BaseDialog from './components/BaseDialog.vue'
export default {
  data() {
    return {
      isShow: false,
    }
  },
 
}
</script>

<style>
</style>

BaseDialog.vue

<template>
  <div class="base-dialog-wrap" v-show="visible">
    <div class="base-dialog">
      <div class="title">
        <h3>温馨提示:</h3>
        <button class="close">x</button>
      </div>
      <div class="content">
        <p>你确认要退出本系统么?</p>
      </div>
      <div class="footer">
        <button>确认</button>
        <button class="close">取消</button>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  props: {
    visible: Boolean,
  },
  method:{
    close(){
      this.$emit('update:visible',false)
      /* :visible.sync =>  :visible + @update:visible */

    }
  }
}
</script>

<style scoped>
.base-dialog-wrap {
  width: 300px;
  height: 200px;
  box-shadow: 2px 2px 2px 2px #ccc;
  position: fixed;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  padding: 0 10px;
}
.base-dialog .title {
  display: flex;
  justify-content: space-between;
  align-items: center;
  border-bottom: 2px solid #000;
}
.base-dialog .content {
  margin-top: 38px;
}
.base-dialog .title .close {
  width: 20px;
  height: 20px;
  cursor: pointer;
  line-height: 10px;
}
.footer {
  display: flex;
  justify-content: flex-end;
  margin-top: 26px;
}
.footer button {
  width: 80px;
  height: 40px;
}
.footer button:nth-child(1) {
  margin-right: 10px;
  cursor: pointer;
}
</style>

6.总结

1.父组件如果想让子组件修改传过去的值 必须加什么修饰符?

2.子组件要修改父组件的props值 必须使用什么语法?

二十、ref和$refs 与querySelector区别 按钮在父组件操作dom

querySelector 是全网页获取dom元素
ref 和 $refs 是 在当前组件内获取(更精确稳定, 解决选择器重名问题)

this.$refs.son <组件名 ref="sonMethod"> this.$refs.sonMethod.方法名()

具体应用例如
输入账号密码框是子组件 获取数据,重置数据按钮在父组件
思路:双向绑定 子写方法父调用(ref=''与$refs.) 获取要return,重置要清空

想要操作输入的内容:
子 双向绑定获取内容
v-model=“username” v-model=“password”
username=“”
password=“”

 子  里边直接写 获取 和 清空数据的方法,将来父通过按钮 操作组件实例 即可

methods:{…}
huoQu(){
return{
username:this.username
password:this.password
}
},
chongZhi(){
this.username=‘’
this.password=‘’
}

 父  想要获取子的这俩方法
    父的子标签加
    ref = "sonMethod"   
    
    父按钮处加上点击事件
    @click="obtain"   
    @click="reset"

methods:{…}
obtain(){
this. r e f s . s o n M e t h o d . h u o Q u ( ) < ! − − 注: t h i s . refs.sonMethod.huoQu()
},
reset(){
this. r e f s . s o n M e t h o d . c h o n g Z h i ( ) < ! − − 注: t h i s . refs.sonMethod.chongZhi()
}

1.作用

利用ref 和 r e f s 可以用于获取 d o m 元素或组件实例一个绑一个用 r e f = " 绑名 " t h i s . refs 可以用于 获取 dom 元素 或 组件实例 一个绑 一个用 ref="绑名" this. refs可以用于获取dom元素或组件实例一个绑一个用ref="绑名"this.refs.绑名

2.特点:

查找范围 → 当前组件内(更精确稳定)

3.语法

1.给要获取的盒子添加ref属性

<div ref="chartRef">我是渲染图表的容器div>

2.获取时通过 $refs获取 this.$refs.chartRef 获取

mounted () {
  console.log(this.$refs.chartRef)
}

4.注意

之前只用document.querySelect(‘.box’) 获取的是整个页面中的盒子
如今直接取代所有 ref=“box” + this.$refs.box

5.代码示例

App.vue

<template>
  <div class="app">
    <BaseChart></BaseChart>
  </div>
</template>

<script>
import BaseChart from './components/BaseChart.vue'
export default {
  components:{
    BaseChart
  }
}
</script>

<style>
</style>

BaseChart.vue

<template>
  <div class="base-chart-box" ref="myBox">子组件</div>
</template>

<script>
// yarn add echarts 或者 npm i echarts 装Echarts包    

import * as echarts from 'echarts'

export default {
  mounted() {
    // 基于准备好的dom,初始化echarts实例
    var myChart = echarts.init(document.querySelect('.base-chart-box'))   曾经写法 

    let myChart = echarts.init(this.$refs.myBox)   如今写法 
    AK47 
    // 绘制图表
    myChart.setOption({
      title: {
        text: 'ECharts 入门示例',
      },
      tooltip: {},
      xAxis: {
        data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子'],
      },
      yAxis: {},
      series: [
        {
          name: '销量',
          type: 'bar',
          data: [5, 20, 36, 10, 10, 20],
        },
      ],
    })
  },
}
</script>

<style scoped>
.base-chart-box {
  width: 400px;
  height: 300px;
  border: 3px solid #000;
  border-radius: 6px;
}
</style>

二十一、异步更新& $nextTick(()=>{}) 点击编辑按钮,编辑框的input自动获取焦点 $nextTick:等dom更新完立即执行的函数体

Vue 是异步dom更新的

步骤:1.俩块 默认展示文本和编辑按钮
v-if=“show” (展示) v-else(编辑块隐藏) show默认值为false 点击后为true

  编辑按钮添加点击事件
  @click="showFocus"

 2. 隐藏的编辑块的 输入框绑定 ref  将来加方法获取焦点 
 ref="inp"  
 
 3.操作隐藏块的dom加方法   把展示的值变成true + 点开后获取焦点 focus()方法
       methods:{
         showFocus(){
  /* 把展示的值变成true  */
            show:true
          /* 点开后获取焦点 */
         this.$refs.inp.focus()
    /* 此时发现报错,因为vue是异步更新的,
         解决:通过vue独有的$nextTick,将上行代码改成 */ 
         this.$nextTick(()=>{
            this.$refs.inp.focus()
         })
         }
       }

1.需求

编辑标题, 编辑框自动聚焦

  1. 点击编辑,显示编辑框
  2. 让编辑框,立刻获取焦点

2.代码实现

<template>
  <div class="app">
    <div v-if="isShowEdit">
      <input type="text" v-model="editValue"  ref="inp" /> /* 帮 */
      <button>确认</button>
    </div>
    /* 这俩块不是同时出现的,点击编辑才会显示上面的块   */
    <div v-else>
      <span>{{ title }}</span>
      <button @click="editFn">编辑</button >
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      title: '大标题',
      isShowEdit: false,
      editValue: '',
    }
  },
  methods: {
    editFn() {
        // 显示输入框
        this.isShowEdit = true      点击后展示编辑块
        // 获取焦点  
        this.$nextTick(()=> {   /* 因为vue是异步更新的  $nextTick:等dom更新完立即执行的函数体 */
             this.$refs.inp.focus() /* 用 focus()方法获取焦点 */
        })
    }  },
}
</script> 

3.问题

“显示之后”,立刻获取焦点是不能成功的!

原因:Vue 是异步更新DOM (提升性能)

4.解决方案

input标签后加 ref=“inp”
$nextTick:等 DOM更新后,才会触发执行此方法里的函数体

语法: this.$nextTick(函数体)

this.$nextTick(() => {
  this.$refs.inp.focus()
})

注意:$nextTick 内的函数体 一定是箭头函数,这样才能让函数内部的this指向Vue实例

day05

一、学习目标

1.自定义指令

  • 基本语法(全局、局部注册)
  • 指令的值
  • v-loading的指令封装

2.插槽

  • 默认插槽
  • 具名插槽
  • 作用域插槽

3.综合案例:商品列表

  • MyTag组件封装
  • MyTable组件封装

4.路由入门

  • 单页应用程序
  • 路由
  • VueRouter的基本使用

二、自定义指令 自己的指令

v-focus自动获取焦点

v-loading控制加载效果

v-lazy图片加载

1.指令介绍

  • 内置指令:v-html、v-if、v-bind、v-on… 这都是Vue给咱们内置的一些指令,可以直接使用

  • 自定义指令:同时Vue也支持让开发者,自己注册一些指令。这些指令被称为自定义指令

    每个指令都有自己各自独立的功能

2.自定义指令

概念:自己定义的指令,可以封装一些DOM操作,扩展额外的功能

3.自定义指令语法

一进页面获取焦点 v-focus

自定义一个指令 将来都能用 1.全局注册main.js 2.局部注册在当前组件用

  • 全局注册 也就是在main.js中注册

    //             指令名 我的 v-focus
    Vue.directive('指令名', {
      inserted (el) {  /*  el可以拿到元素比如输入框*/  
         /* inserted表示 当指令绑定的元素 被添加到页面当中的时候会 自动调用 */
        // 可以对 el 标签,扩展额外功能 , 跟mounted类似
        el.focus()
      }
    })//自动获取焦点全局可用
    
  • 局部注册

    //在Vue组件的配置项中
    directives: {
      "指令名": {
        inserted () {
          // 可以对 el 标签,扩展额外功能
          el.focus()
        }
      }
    }
    
  • 使用指令

    注意:在使用指令的时候,一定要先注册再使用,否则会报错
    使用指令语法: v-指令名。如:

    注册指令时不用v-前缀,但使用时一定要加v-前缀

4.指令中的配置项介绍

inserted:被绑定元素插入父节点时调用的钩子函数

el:使用指令的那个DOM元素

5.代码示例

需求:当页面加载时,让元素获取焦点(autofocus在safari浏览器有兼容性

App.vue

  <div>
    <h1>自定义指令</h1>
    <input v-focus ref="inp" type="text">
  </div>

6.总结

1.自定义指令的作用是什么?

2.使用自定义指令的步骤是哪两步?

三、自定义指令-指令的值 v-color=“颜色值” 输入颜色就改某个块的字体颜色

1.需求

实现一个 color 指令 - 传入不同的颜色, 给标签设置文字颜色

2.语法

1.在绑定指令时,可以通过“等号”的形式为指令 绑定 具体的参数值

<div v-color="color1">我是内容div>

2.data里给颜色
data(){
return {
color1:‘red’
}
}

3.通过 binding.value 可以拿到指令值,指令值修改会 触发 update 函数

directive:{
        color:{/* 自定义指令名字 差v- */
        /* inserted 是元素加在页面中的效果,颜色初始化 */
           inserted (el,binding){
             /* blinding.value 就是指令的值,也就是颜色*/ 
             el.style.color = blinding.value 
           },
        /* update 是v-color的值 修改时触发,值变化后的效果,就是改颜色的意思 */
           update(el,binding){
               el.style.color = blinding.value 
           }
        }
      }

3.代码示例

App.vue






四、自定义指令-v-loading指令的封装(常用) 加载效果

1.场景

实际开发过程中,发送请求需要时间,在请求的数据未回来时,页面会处于空白状态 => 用户体验不好

2.需求

封装一个 v-loading 指令,实现加载中的效果

3.分析

1.本质 loading效果就是一个蒙层,盖在了盒子上

2.数据请求中,开启loading状态,添加蒙层

3.数据请求完毕,关闭loading状态,移除蒙层

4.实现

1.准备一个 loading类,通过伪元素定位,设置宽高,实现蒙层,将加载图片设为背景图
css
在块上class加上loading类即可

2.开启关闭 loading状态(添加移除蒙层),本质只需要添加 和 移除类即可
add 和 remove

3.结合自定义指令的语法进行封装复用 进入页面就加载,出现数据就渲染
v-loading=“isLoading” 在块标签加

data(){ return{ } }
isLoading:true

当数据请求完成移除 loading 类
this.list = res.data.data
this.isLoading = false

directives:{
loading:{
inserted(el,binding){
binding.value ? el.classList.add(‘loading’) : el.classList.remove(‘loading’)
},
update(el,binding){
binding.value ? el.classList.add(‘loading’) : el.classList.remove(‘loading’)
}
}
}

.loading:before {   /* before代表伪元素 */
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background: #fff url("./loading.gif") no-repeat center;
}
在块上加上loading类即可

5.准备代码

<template>
  <div class="main">
    <div class="box loading">
      <ul>
        <li v-for="item in list" :key="item.id" class="news">
          <div class="left">
            <div class="title">{{ item.title }}div>
            <div class="info">
              <span>{{ item.source }}span>
              <span>{{ item.time }}span>
            div>
          div>
          <div class="right">
            <img :src="item.img" alt="">
          div>
        li>
      ul>
    div> 
  div>
template>

<script>
// 安装axios =>  yarn add axios || npm i axios
import axios from 'axios'

// 接口地址:http://hmajax.itheima.net/api/news
// 请求方式:get
export default {
  data () {
    return {
      list: [],
      isLoading: false,
      isLoading2: false
    }
  },
  async created () {
    // 1. 发送请求获取数据
    const res = await axios.get('http://hmajax.itheima.net/api/news')
    
    setTimeout(() => { /* 延时器 ,这里是模拟得到数据较慢的情况*/
      // 2. 更新到 list 中,用于页面渲染 v-for
      this.list = res.data.data
    }, 2000)
  }
}
script>

<style>
.loading:before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  background: #fff url('./loading.gif') no-repeat center;
}

.box2 {
  width: 400px;
  height: 400px;
  border: 2px solid #000;
  position: relative;
}



.box {
  width: 800px;
  min-height: 500px;
  border: 3px solid orange;
  border-radius: 5px;
  position: relative;
}
.news {
  display: flex;
  height: 120px;
  width: 600px;
  margin: 0 auto;
  padding: 20px 0;
  cursor: pointer;
}
.news .left {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding-right: 10px;
}
.news .left .title {
  font-size: 20px;
}
.news .left .info {
  color: #999999;
}
.news .left .info span {
  margin-right: 20px;
}
.news .right {
  width: 160px;
  height: 120px;
}
.news .right img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
style>

五、弹窗插槽-默认插槽 弹窗内容自定义 slot MyDialog 只改变一个位置

1.作用

让组件内部的一些 结构 支持 自定义

2.需求

将需要多次显示的对话框,封装成一个组件

3.问题

组件的内容部分,不希望写死,希望能使用的时候自定义。怎么办

4.插槽的基本语法 站位 父内自定义

  1. 组件内需要定制的结构部分,
    改用****占位

  2. 使用组件时,固定组件名
    ****标签内部, 传入结构替换slot

  3. 给插槽传入内容时,可以传入纯文本、html标签、组件

5.代码示例

MyDialog.vue 子组件

<template>
  <div class="dialog">
    <div class="dialog-header">
      <h3>友情提示</h3>
      <span class="close">✖️</span>
    </div>

    <div class="dialog-content">
     <slot></slot>  /* 内容自定义用slot站位,将来父内子标签名字必须是,在该标签内写自定义内容, */
    </div>
    <div class="dialog-footer">
      <button>取消</button>
      <button>确认</button>
    </div>
  </div>
</template>

<script>
export default {
  data () {
    return {

    }
  }
}
</script>

<style scoped>
* {
  margin: 0;
  padding: 0;
}
.dialog {
  width: 470px;
  height: 230px;
  padding: 0 25px;
  background-color: #ffffff;
  margin: 40px auto;
  border-radius: 5px;
}
.dialog-header {
  height: 70px;
  line-height: 70px;
  font-size: 20px;
  border-bottom: 1px solid #ccc;
  position: relative;
}
.dialog-header .close {
  position: absolute;
  right: 0px;
  top: 0px;
  cursor: pointer;
}
.dialog-content {
  height: 80px;
  font-size: 18px;
  padding: 15px 0;
}
.dialog-footer {
  display: flex;
  justify-content: flex-end;
}
.dialog-footer button {
  width: 65px;
  height: 35px;
  background-color: #ffffff;
  border: 1px solid #e1e3e9;
  cursor: pointer;
  outline: none;
  margin-left: 10px;
  border-radius: 3px;
}
.dialog-footer button:last-child {
  background-color: #007acc;
  color: #fff;
}
</style>

App.vue

<template>
  <div>
    <MyDialog>
        你确定要删除吗               /* 内容自定义,将来该弹窗组件可多次复用,所以注册为全局注册 */
    </MyDialog>
  </div>
</template>

<script>
import MyDialog from './components/MyDialog.vue'
export default {
  data () {
    return {

    }
  },
  components: {
    MyDialog
  }
}
</script>

<style>
body {
  background-color: #b3b3b3;
}
</style>

6.总结

场景:组件内某一部分结构不确定,想要自定义怎么办
slot +

使用:插槽的步骤分为哪几步?
站位
内添加自定义内容

六、弹窗插槽-后备内容(默认值) slot内加弹窗默认内容,若自定义,则默认内容会被取代

1.问题

通过插槽完成了内容的定制,传什么显示什么, 但是如果不传,则是空白

能否给插槽设置 默认显示内容 呢?

2.插槽的后备内容

封装组件时,可以为预留的 插槽提供后备内容(默认内容)。

3.语法

在 标签内,放置内容, 作为默认显示内容

4.效果

  • 外部使用组件时,不传东西,则slot会显示后备内容

  • 外部使用组件时,传东西了,则slot整体会被换掉

5.代码示例

App.vue

<template>
  <div>
    <MyDialog></MyDialog>
    <MyDialog>
      你确认要退出么
    </MyDialog>
  </div>
</template>

<script>
import MyDialog from './components/MyDialog.vue'
export default {
  data () {
    return {

    }
  },
  components: {
    MyDialog
  }
}
</script>

<style>
body {
  background-color: #b3b3b3;
}
</style>

七、弹窗插槽-具名插槽 弹窗标题,内容,按钮自定义 弹窗 搭配父的子弹窗组件