Vue3笔记_itheima

VUE笔记B站黑马程序员

webpack

05 webpack基础-隔行变色

{

Alt
}

06webpack基础-安装webpack

{
Alt
}
-S 是 --save的简写
-D 是 --save-dev的简写

07在项目中配置两个包

{
Alt
}

development 表示在开发阶段
production表示要上线的项目
none 表示‘无’

执行dev脚本后会在根目录下生成一个dist文件夹,里面包含了生成的main.js文件

,main.js文件大小取决于exports的参数

开发的是有一定要用development,因为最求的是打包的速度,而不是体积

上线的时候一定要用production,因为上线最求得是体积,而不是速度快

08指定webpack的entry和output

在webpack 4.X和5.X的版本中,有如下默认约定:
1.默认的打包入口为src -> index.js
2.默认的输出文件路径为 dist -> main.js

ps:可以在webpack.config.js中修改打包的默认约定

const path = require('path')
module.exports = {
    mode : 'none',  //mode 来指定构建模式 develoment 开发模式  production表示要上线的项目
    //entry: //指定要处理那个文件
    // __dirname表示该文件的绝对路径,拼接上要处理文件的相对路径
    entry: path.join(__dirname,'./src/index1.js'),
    // 指定生成的文件要放到哪里
    output: {
        //存放的目录
        path: path.join(__dirname,'dist'),
        // 生成的文件名
        filename: 'bundle.js'
    }
}

09安装和配置webpack-dev-server这个插件

在开发中使用插件自动打包

1.下载webpack-dev-server插件

npm install webpack-dev-server@3.11.2 -D

2.修改package.json ->scripts 的dev命令

"scripts": {
	//添加serve参数
    "dev": "webpack serve"
  },

3.重新运行npm run dev命令

4.重新访问http://localhost:8080地址

10介绍webpack-dev-server工作原理

「wds」: Project is running at http://localhost:8080/
表示项目运行的地址
「wds」: webpack output is served from /
生成的js在根目录,但是不会在硬盘中显示,而是生成在内存中,因为内存比硬盘快,所以应当把index.html里的js引用为内存生成的js

/**index.html中**/
<script src="../main.js"></script>

11安装和配置html-webpack-plugin插件

在实际运行中需要进入http://localhost:8080/src/这个路径里面,可以使用html-webpack-plugin插件把src/index.html页面复制到项目根目录里面

下载

npm install html-webpack-plugin@5.3.2 -D

配置html-webpack-plugin

const path = require('path')
//导入html-webpack-plugin这个插件,得到插件构造函数
const HtmlPlugin = require('html-webpack-plugin')
//new 构造函数,创建插件的实例对象
const htmlPlugin = new HtmlPlugin({
    //指定要复制哪个页面
    template: './src/index.html',
    //复制出来的路径以及存放路径
    filename: './index.html'
})
module.exports = {
     mode : 'none',  //mode 来指定构建模式 develoment 开发模式  production表示要上线的项目
    //entry: //指定要处理那个文件
    // __dirname表示该文件的绝对路径,拼接上要处理文件的相对路径
    entry: path.join(__dirname,'./src/index.js'),
    plugins: [htmlPlugin],
    //通过plugin节点,使htmlplugin插件生效
    // 指定生成的文件要放到哪里
    output: {
        //存放的目录
        path: path.join(__dirname,'dist'),
        // 生成的文件名
        filename: 'main.js',
    }
}

表示将复制的页面放到主目录里面(内存)

12了解html-webpack-plugin插件的特性

如11所讲

13了解devServer中的常用选项

devServer

module.exports = {
    mode : 'none',  //mode 来指定构建模式 develoment 开发模式  production表示要上线的项目
    //entry: //指定要处理那个文件
    // __dirname表示该文件的绝对路径,拼接上要处理文件的相对路径
    entry: path.join(__dirname,'./src/index.js'),
    plugins: [htmlPlugin],
    //通过plugin节点,使htmlplugin插件生效
    // 指定生成的文件要放到哪里
    output: {
        //存放的目录
        path: path.join(__dirname,'dist'),
        // 生成的文件名
        filename: 'main.js',
    },
    // devServer
    devServer: {
        open: true,//初次打包,自动打开浏览器
        port:80,//指定端口
        host: '127.0.0.2' //指定打开的地址
    }
}

在http协议中,端口号80表示默认端口,则端口号在浏览器省略不显示

14loader的作用

loader(加载器)
在实际开发过程中,webpack处理不了后缀不是.js结尾的模块,webpack默认是处理不了的,需要调用loader加载器才能正常的打包,否则会报错!

判断
将要被webpack打包处理的模块
是否为js模块
是否包含js语法
是否配置了对应loader
是否配置了babel
webpack进行处理
调用loader处理
报错
调用loader处理
报错

VUE

32.什么是VUE

1.构建用户页面

用vue往html页面填充数据

2.框架

一套现成的解决方案,要遵守框架的规范

33.vue的特性

1.数据驱动视图

vue会监听数据的变化,从而重新渲染页面的结构DOM

OK:数据发生变化,页面重新渲染!

Note:数据驱动是 单向的数据绑定 \color{red}{单向的数据绑定} 单向的数据绑定

2.双向数据绑定

在网页中form负责采集数据,Ajax负责 “提交数据”

34.MVVM

MVVM 是 数据驱动视图 \color{red}{数据驱动视图} 数据驱动视图 双向数据 \color{red}{双向数据} 双向数据绑定的核心原理,MVVM是值指的Model、View和View Model它把一个页面拆分成三部分

35.Vue基础语法-初步使用Vue

这里我自己按照视频上面的代码识别不了Vue对象,下面代码贴的开发文档的

	 <!-- 希望vue控制这个div,数据填充div内部 -->
    <div id="app">{{ message }}</div>
    <!-- "username"两边加空格让格式更清晰 -->
    <!-- 通过cdn使用vue -->
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <!-- 创建Vue的实例对象 -->
    <script>
        //这里使用的vue开发文档来创建https://cn.vuejs.org/guide/quick-start.html#using-vue-from-cdn
        const { createApp } = Vue
  
        createApp({
        data() {
        return {
            message: 'Hello Vue!'
            }
        }   
    }).mount('#app')
    </script>

36Vue基础语法-体验Vue调试工具

Null

37Vue基础语法-内容渲染指令

1.指令的概念

指令(Directives)是vue为开发者提供的模板语法,用于辅助开发者渲染页面的基本结构。
vue中的指令按照不同的用途可以分为如下6大类:
内容渲染 \color{red}{内容渲染} 内容渲染指令
属性绑定 \color{red}{属性绑定} 属性绑定指令
事件绑定 \color{red}{事件绑定} 事件绑定指令
双向绑定 \color{red}{双向绑定} 双向绑定指令
条件渲染 \color{red}{条件渲染} 条件渲染指令
列表渲染 \color{red}{列表渲染} 列表渲染指令

①内容渲染指令(v-text , {{}} , v-html)

v − t e x t \color{pink}{v-text} vtext
缺点:会覆盖元素内部原有的内容

<p v-text="username"></p>

{ { } } 插值表达式 \color{pink}{\{\{\}\}插值表达式} {{}}插值表达式

用来解决覆盖原有内容的问题,实际开发中用的最多

但插值表达式只能用于内容节点,不能用于属性节点

v − h t m l \color{pink}{v-html} vhtml

可以渲染标签

v − o n c e \color{pink}{v-once} vonce

可以通过这个指令来一次性的插值,数据改变的时候,这个值不会更新

属性绑定指令

v − b i n d \color{pink}{v-bind} vbind

vue规定可以将v-bind:简写为":"(冒号)

在vue中绑定内容可以动态拼接

<div :title="'box'+index">这是一个div</div>

事件绑定指令

v − o n \color{pink}{v-on} von

语法格式为 v-on :事件名称=“事件处理函数名称”

由于v-on在开发中频率很高,简写为 @ \color{red}{@} @

<div id="app">
        <p>count的值是{{ count }}</p>
        <!-- 语法格式为 v-on :事件名称="事件处理函数名称" -->
        <button v-on:click="addCount">+1</button>
    </div>
    <script src="./vue.global.js"></script>
    <script>
        const { createApp } = Vue
        
        createApp({
        data() {
        return {
                count:0,
                
            }
        },
        // methods的作用就是定义事件的处理函数
        methods:{
            addCount: function(){
            //在实际开发中建议使用简写 addCount(){
                count++
            }
        }
    }).mount('#app')
    </script>

由于业务逻辑代码只有一行所以也可以简写为

		<button @click="message++">+1</button>
        <button @click="message--">-1</button>

301事件对象event

可以使用一个形参来接收

add(e){
       const nowBgc = e.target.style.background;
       e.target.style.background = nowBgc ==='red' ? '' : 'red'
       this.resu=nowBgc
       console.log(nowBgc);
}

$event

e v e n t 是 v u e 提供的特殊变量,表示原生事件参数对象 e v e n t 。 event是vue提供的特殊变量,表示原生事件参数对象event。 eventvue提供的特殊变量,表示原生事件参数对象eventevent可以解决事件对象event被覆盖的问题

事件修饰符

.prevent 阻止默认行为

----> 阻止a连接的跳转,阻止表单的提交

.stop 阻止事件冒泡

----> 内部盒子点击不会触发外层盒子

}在这里插入图片描述}

.capture

---->从外部开始向内部触发

.once

---->只触发一次

.self

---->如果通过冒泡,则不触发

按键修饰符

表按下了enter键则执行submit方法 && 按下了esc键则执行clearInput方法

<input type="text"@keyup.enter="submit"@keyup.esc="clearInput">

双向绑定指令

v-model数据绑定指令

可以帮助辅助开发者不操作DOM的前提下,快速获取表单的数据

		<p>用户名{{username}}</p>
        <input type="text"@keyup.enter="submit"@keyup.esc="clearInput" v-model="username">
        <p>选中的省份是:{{province}}</p>
        <select v-model="province">
            <option value="">请选择</option>
            <option value="1">重庆</option>
            <option value="2">广东</option>
            <option value="3">北京</option>
            <option value="4">上海</option>
        </select>

注意:v-model指令只能配合表单元素一起使用,不能和p标签a标签不能输入的标签所使用

v-model指令的修饰符

为了方便对用户内容的输入处理,v-model提供了三个修饰符

在这里插入图片描述
.lazy 当对象失去焦点的时候更新,而不是实时更新

条件渲染指令

v − i f \color{pink}{v-if} vif
v − s h o w \color{pink}{v-show} vshow
实现的效果

v-if会动态创建和移除DOM元素,从而控制元素在页面上的显示与隐藏
它有更高的性能消耗

v-show指令会动态的为元素添加或移除style="display:none"样式,来控制显示与隐藏
他会有更高的出事消耗开销

频繁的切换,使用v-show更好
反之,使用v-if更好

v-if&&v-else&&v-else-if

随机生成0.01~1的数

	num:Math.random(),

相当于if–else

	<p v-if="num>0.5">大于0.5</p>
    <p v-else>小于0.5</p>

v-else-if相当于switch case语句

列表渲染指令

v − f o r \color{pink}{v-for} vfor

语法格式:(item,index)in items

item和index都是形参,可更改

<li v-for="(user,i) in list">索引:{{i}}姓名是:{{user.name}}</li>

使用key列表维护

问题:

当列表的数据变化时,默认情况下,vue会尽可能的复用已存在的DOM元素,从而提升渲染的性能。但这种默认的性能优化策略,会导致有状态的列表无法被正确更新。

解决方案:给每一项给一个唯一的key 属性

key所绑定的值,只能是数字型或字符串型

<li v-for="(user,i) in list" :key="list.id">

过滤器

过滤器(Filter)常用于文本的格式化

“|”被称为管道符

在属性中添加|可以使用过滤器

<p>{{province | capitalize}}</p>

过滤器可以用在插值表达式和v-bind属性绑定

过滤器得通过与el节点平齐的filters节点来描述

filters: {
       capitalize(str){
       return str.charAt(0).toUpperCase()+str.slice(1)
}
}

私有过滤器和全局过滤器

私有过滤在不被控制的区域不会起作用

可以用下面的例子来声明全局过滤器

<script>
        Vue.filter('capitalize',(str)=>{//str是形参
            return str.charAt(0).toUpperCase()+str.slice(1)
        })
    </script>

其中,私有过滤器优先级高于全局过滤器

连续调用多个过滤器

可以调用多个过滤器

2.X的Vue是可以使用过滤器,但3.X则被剔除了

品牌列表案例

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <!-- 导入 bootstrap 的样式表 -->
    <!-- https://v4.bootcss.com/docs/components/forms/#switches -->
    <link rel="stylesheet" href="./lib/bootstrap.css" />
    <style>
      :root {
        font-size: 13px;
      }

      body {
        padding: 8px;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <!-- 卡片区域 -->
      <div class="card">
        <h5 class="card-header">添加品牌</h5>
        <div class="card-body">
          <!-- 添加品牌的表单 -->
          <!-- vue在做表单提交的时候,需要用到一些自定义的验证规则,这个时候就需要阻止表单默认的提交方式。 -->
          <form class="form-inline" @submit.prevent>
            <div class="input-group mb-2 mr-sm-2">
              <div class="input-group-prepend">
                <div class="input-group-text">品牌名称</div>
              </div>
              <!-- 文本输入框 -->
              <input type="text" class="form-control" v-model.trim="brandname" @keyup.esc="brandname=''"/>
            </div>

            <!-- 提交表单的按钮 -->
            <button type="submit" class="btn btn-primary mb-2" @click="addNewBrand">添加品牌</button>
          </form>
        </div>
      </div>

      <!-- 品牌列表 -->
      <table class="table table-bordered table-striped mt-2">
        <thead>
          <tr>
            <th>#switches</th>
            <th>品牌名称</th>
            <th>状态</th>
            <th>创建时间</th>
            <th>操作</th>
          </tr>
        </thead>
        <!-- 表格的主体区域 -->
        <tbody>
          <!-- TODO:循环渲染表格的每一行数据 -->
          <tr v-for="(item,index) in brandlist" :key="item.id">
            <td>{{item.id}}</td>
            <td>{{item.brandname}}</td>
            <td>
              <div class="custom-control custom-switch">
                <!-- //v-model双向绑定绑定初始值  -->
                <input type="checkbox" class="custom-control-input" :id="item.id" v-model="item.state">
                <label class="custom-control-label" :for="item.id" v-if="item.state">已开启</label>
                <label class="custom-control-label" :for="item.id" v-else>已禁用</label>
              </div>
            </td>
            <td>{{item.addtime | dateFormat}}</td>
            <td>
              <a href="#" @click.prevent="removeBrand(item.id)">删除</a>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
    <script src="../../vue-2.6.14/dist/vue.js"></script>
    <script>
      //创建全局的过滤器
      
      Vue.filter('dateFormat', (dateStr)=>{
        return dateStr
      })
      const vm = new Vue({
        el: '#app',
        data: {
          brandname:'',
          nextId:'5',
          brandlist:[
            { id: 1,brandname: '宝马', state: true, addtime:new Date() },
            { id: 2,brandname: '奥迪', state: true, addtime:new Date() },
            { id: 3,brandname: '奔驰', state: true, addtime:new Date() },
            { id: 4,brandname: '山崎', state: true, addtime:new Date() },
          ]
        },
        methods: {
          // 添加新的品牌数据
          addNewBrand(){
            if(!this.brandname)
              return alert("品牌名不能为空!");
            // 添加操作
            this.brandlist.push({
              id:this.nextId,
              brandname:this.brandname,
              state:true,
              addtime:new Date()
            })
            this.nextId++,
            this.brandname = ''
          },
          // 根据id删除对应的数据
          removeBrand(id){
            // 过滤旧数组,形成新数组
            this.brandlist=this.brandlist.filter(x => x.id !==id )
          }
        },
      })
    </script>
  </body>
</html>

什么是单页面应用程序

是指一个web网站中只有唯一一个html页面,所有的功能和交互都在这一个页面完成

单页面应用程序将所有的功能局限于一个web页面中,仅在该web页面初始化时加载相应的资源(HTML、Javascript和CSS)。

一旦页面加载完成了,SPA不会因为用户的操作而进行页面的重新加载或跳转。而是利用JavaScript动态地变换HTML的内容,从而实现页面与用户的交互

Vite项目结构

Vite根目录

{
在这里插入图片描述
}

node_modules 目录用来存放第三方依赖包

public 是公共的静态资源目录

srC是项目的源代码目录(程序员写的所有代码都要放在此目录下)

.gitignore是Git的忽略文件

index.html是SPA单页面应用程序中唯一的HTML页面

package.json 是项目的包管理配置文件

Vite src目录

{
在这里插入图片描述

}
assets目录用来存放项目中所有的静态资源文件(css、fonts等)

components目录用来存放项目中所有的自定义组件

App.vue是项目的根组件

index.css是项目的全局样式表文件

main.js是整个项目的打包入口文件

运行流程

{
在这里插入图片描述

}

App.vue用来编写待渲染的模板结构

index.html中需要预留一个el区域

main.js把App.vue 渲染到了index.html所预留的区域中

组件化开发的思想

根据封装的思想,把页面上可重用的部分封装为组件,从而方便项目的开发和维护。

例如:Ibootstrap就契合了组件化开发的思想。用户可以通过拖拽组件的方式,快速生成一个页面的布局结构。

Vue是完全支持组件化,开发的,其中后缀名为 . v u e \color{red}{.vue} .vue的文件为组件

template组件模板结构
script组件的javascript行为
css 组件的样式

template节点

template不会被渲染成DOM元素,只会起到包裹的作用

在vue3版本中<template>支持多个根节点

script节点

可以使用export default导出一个组件

可以通过name指定名称

<script>
export default{
  name: 'MyApp1',
}
</script>

在这里插入图片描述

script中的data节点

指定组件的数据

<template>
  <div>
    <h1>这是一个vue组件</h1>
    <h3>MyName:{{username}}</h3>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'
export default{
  name: 'MyApp1',
  data(){
    return {
      username:'晓刘'
    }
  }
}
</script>

script中的methods节点

methods方法节点,与data同级

<template>
  <div>
    <h1>这是一个vue组件</h1>
    <h3>MyName:{{username}}</h3>
    <p>count的值是:{{count}}</p>
    <button @click="add">+1</button>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'
export default{
  name: 'MyApp1',
  data(){
    return {
      username:'晓刘',
      count:0
    }
  },
  methods: {
    add(){
      this.count++
    }
  },
}
</script>

style节点

style节点与script节点同级

......
<script>
......
</script>
<style>
h1{
  color:red;
}
</style>

让style中支持less语法

①运行npm install less -D命令安装依赖包,从而提供less 语法的编译支持
②在<style>标签上添加lang="less"属性,即可使用less 语法编写组件的样式

<style lang="less">
h1{
  color:red;
  i{
    color:blue;
  }
}
</style>

组件的注册

组件的引用原则 先注册,后引用 \color{red}{先注册,后引用} 先注册,后引用

vue中注册组件的方式分为“全局注册”和“局部注册”两种,其中:
被全局注册的组件,可以在全局任何一个组件内使用
被局部注册的组件,只能在当前注册的范围内使用

全局注册:

main.js:

//导出需要被全局注册的组件
import Swiper from './Swiper.vue'
//调用app.component方法注册全局组件
const app = createApp(App)
// 调用createApp函数,创建spa应用实例
app.component('mySwiper',Swiper)

Swiper:

<template>
    <h1>这是一个组件</h1>
</template>
<script>
    export default{
        name:'myswiper'
    }
</script>

在这里插入图片描述
局部注册:

import Search from './test.vue';
export default{
  components: {
    'myTest': Search,
  },
.....
}

如果某些组件在开发期间的使用频率很高,推荐进行全局注册;

如果某些组件只在特定的情况下会被用到,推荐进行局部注册。

组件命名时的大小写问题

短横线命名法 \color{pink}{短横线命名法} 短横线命名法的特点:
·必须严格按照短横线名称进行使用

帕斯卡命名法 \color{pink}{帕斯卡命名法} 帕斯卡命名法的特点:
·既可以严格按照帕斯卡名称进行使用,又可以转化为短横线名称进行使用

在实际开发中,建议使用帕斯卡命名法来命名,适用性更好

解决样式冲突的问题

style节点的scoped属性

快速选择相同的字符Ctrl+D

scoped的原理就是生成一个带有随机数的自定义属性
scoped

deep样式穿透

由于添加了scoped属性父组件不能给子组件进行样式声明,则需要 / d e e p / \color{red}{/deep/} /deep/深度选择器
vue2/deep/
如上, / d e e p / \color{red}{/deep/} /deep/是vue2所特有的写法,在vue3推荐使用 : d e e p ( X X X ) \color{red}{:deep(XXX)} :deep(XXX)来替代

组件的props

props的作用:父组件通过props 向子组件传递要展示的数据。

props的好处:提高了组件的复用性。

使用props

父组件:

<mytest title="kukud_"></mytest>

子组件:

<script>
    export default{
        props: ['title'],
        ......
        ......
    },
    ......
</script>

封装者定义了props数组,相当于留了一个形参api

无法使用未声明的props

在子组件中无法使用未声明的props

以对象语法绑定HTML的class

使用 数组语法 \color{red}{数组语法} 数组语法动态绑定classs会导致模板结构臃肿,使用对象语法来简化

<template>
  <div>
    <h2 class="thin" :class="classObj">MyStyle组件</h2>
    <button @click="classObj.italic=!classObj.italic">Togge italic</button>
    <button @click="classObj.delete=!classObj.delete">Togge Delete</button>
  </div>
</template>

<script>
export default{
  name: 'MyApp1',
  data(){
    return {
      // 是否倾斜
      isItalic: false,
      isDelete: false,
      classObj :{
        italic: false,
        delete: false
      }
    }},
  methods: {

  }
}
</script>
<style lang="less" scoped>
.italic{
  font-style: italic;
}
.thin{
  font-weight: 200;
}
.delete{
  text-decoration: line-through;
}
</style>

以对象语法绑定内联的style

:style的对象语法十分直观——看着非常像CSS,但其实是一个JavaScript对象。CSS property名可以用驼峰式(camelCase)或短横线分隔(kebab-case,记得用引号括起来)来命名:

<h2 class="thin" :class="classObj" :style="{fontSize: fsize + 'px',color: active}">MyStyle组件</h2>

封装组件的案例

Null 过时…

props验证

props多个可能的值

当类型不唯一的时候,可以用数组来表示可能的类型

<script>
export default {
    name: 'MyHeader',
    props:{
        count: Number,
        state: Boolean,
        // 数组表示可能的类型,可以使Number,可以使Boolean类型
        info: [Number,Boolean]
    }
}
</script>

props必填项校验

可以用 r e q u i r e d \color{red}{required} required属性来表示该值是否必填

<script>
export default {
    name: 'MyHeader',
    props:{
        count: {
            type: Number,
            required: true
        }
        ......
    }
}
</script>

props默认值

可以使用 d e f a u l t \color{red}{default} default属性来表示默认值

<script>
export default {
    name: 'MyHeader',
    props:{
        count: {
            type: Number,
            default: 100
        },
        ......
    }
}
</script>

自定义验证函数

可以用自定义验证函数来判断

<script>
export default {
    name: 'MyHeader',
    props:{
        count: {
            valdata(value){
                // 判断是否属于数组中的一个
                return ['success','warning','denger'].indexOf(value) !== -1
            }
        }
    }
}
</script>

计算属性

计算属性本质上就是一个function函数,它可以实时监听 data中数据的变化,并return一个计算后的新值,供组件渲染DOM时使用。

声明计算属性

计算属性以function函数的形式声明到computed选项中,且计算属性结果会被缓存,性能好

<script>
export default {
    name: 'MyHeader',
    props:{
        ......
    },
    data() {
        return {
            count: 5,
        }
    },
    computed: {
        plus(){
            return this.count*2;
        }
    }
}
</script>

计算属性必须定义在computed节点中
计算属性必须是一个function函数
计算属性必须有返回值
计算属性必须当做普通属性使用

动态计算水果案例

<!-- 结算区域 -->
    <div class="settle-box">
      <!-- TODO: 1. 动态计算已勾选的商品的总数量 -->
      <span>总数量:{{total}}</span>
      <!-- TODO: 2. 动态计算已勾选的商品的总价 -->
      <span>总价:{{amount}}</span>
      <!-- TODO: 3. 动态计算按钮的禁用状态 -->
      <button type="button" class="btn btn-primary" :disabled="isDisabled ? true : false">结算</button>
    </div>
  </div>
</template>

<script>
export default {
  name: 'FruitList',
  data() {
   ......
  },
  computed:{
    // 动态计算
    total(){
      let t=0
      this.fruitlist.forEach(x =>{
        if(x.state==true){
          t+=x.count
        }
      })
      return t
    },
    amount(){
      let a=0
   	  //循环state属性为true的所有price单价*count数量
      this.fruitlist.filter(x => x.state).forEach(x =>{
        a+=x.price*x.count
      })
      return a
    },
    isDisabled(){
      return this.total===0
    }
  },
  methods: {
  ......
  }
}
</script>

watch侦听器

异步编程async/await语法

javascript从设计之初就是单线程的语法,单线程的异步编程方式有诸多优点,比如无需考虑线程同步,资源竞争,线程切换开销的问题,为避免回调地狱设计了promise

fetch函数会返回一个promise(承诺在某个时间返回数据)

async关键字会将该函数标记为异步函数(返回值为promise对象的函数)

await语法等待promise完成后最终的结果

Promise ,async,await

安装axios

终端输入:

cnpm i axios -S
<template>
  <div>
    <h3>Watch侦听器用法</h3>
    <input type="text" class="form-control" v-model="username">
  </div>
</template>

<script>
import axios from 'axios'
export default {
    name:'MyWatch',
    data(){
        return{
            username:''
        }
    },
    watch:{
        // 声明这是一个异步处理函数
        async username(newVal,oldVal){
            console.log(newVal,oldVal)
            const {data:res} =await axios.get('https://www.escook.cn/api/finduser/'+newVal)
            console.log(res);
        }
    }
    
}
</script>

<style lang="less" scoped>

</style>

immedidate选项

在组件第一次被渲染后立即被调用,加入immedidata: true


<script>
import axios from 'axios'
export default {
    name:'MyWatch',
    data(){
        return{
            username:'admin'
        }
    },
    watch:{
        // 声明这是一个异步处理函数
        // async username(newVal,oldVal){
        //     console.log(newVal,oldVal)
        //     const {data:res} =await axios.get('https://www.escook.cn/api/finduser/'+newVal)
        //     console.log(res);
        // }
        username:{
            async handler(newVal,oldVal){
            const {data:res} =await axios.get('https://www.escook.cn/api/finduser/'+newVal)
            console.log(res);
            },
            //这里立即出发watch组件
            immediate:true
        }
    }
    
}
</script>

deep选项

当watch侦听的是一个对象,当对象中的属性发生了变化,则无法监听到,此时需要使用deep选项

<template>
  <div>
    <h3>Watch侦听器用法</h3>
    <input type="text" class="form-control" v-model="info.username">
  </div>
</template>

<script>
import axios from 'axios'
export default {
    name:'MyWatch',
    data(){
        return{
            username:'admin',
            info:{
                username:'admin'
            }
        }
    },
    watch:{
        // 声明这是一个异步处理函数
        // async username(newVal,oldVal){
        //     console.log(newVal,oldVal)
        //     const {data:res} =await axios.get('https://www.escook.cn/api/finduser/'+newVal)
        //     console.log(res);
        // }
        // username:{
        //     async handler(newVal,oldVal){
        //     const {data:res} =await axios.get('https://www.escook.cn/api/finduser/'+newVal)
        //     console.log(res);
        //     },
        //     //这里立即出发watch组件
        //     immediate:true
        // }
        info:{
            async handler(newVal,oldVal){
            const {data:res} =await axios.get('https://www.escook.cn/api/finduser/'+newVal)
            console.log(res);
            },
            immediate:true,
            deep:true
        }
    }
    
}
</script>

<style lang="less" scoped>

</style>

watch选项监听单个属性

如上笔记所示,如果对象中的每一个属性发生变化时,都会触发

<template>
  <div>
    .......
    <input type="text" class="form-control" v-model="info.username">
  </div>
</template>

<script>
import axios from 'axios'
export default {
    .......
    data(){
        return{
            .......
            info:{
                username:'admin'
            }
        }
    },
    watch:{
    	//这里改为属性,用单引号包裹
        'info.username':{
            async handler(newVal,oldVal){
            const {data:res} =await axios.get('https://www.escook.cn/api/finduser/'+newVal)
            console.log(res);
            }
        }
    }
    
}
</script>

<style lang="less" scoped>

</style>

计算属性vs侦听器

计算属性和侦听器侧重的应用场景不同:

计算属性侧重于监听多个值的变化,最终计算并返回一个新值

侦听器侧重于监听单个数据的变化,最终执行特定的业务处理,不需要有任何返回值

组件的运行过程

{
在这里插入图片描述
}
vue框架为组件内置了不同时刻的生命周期函数,生命周期函数会伴随着组件的运行而自动调用。例如:

①当组件在内存中被创建完毕之后,会自动调用created函数

②当组件被成功的渲染到页面上之后,会自动调用mounted函数

③当组件被销毁完毕之后,会自动调用unmounted函数

当组件被重新渲染的时候,会自动调用updatad函数

.......
<script>
export default {
    name:'lifeCycle',
    created(){
        console.log('created');
    },
    mounted() {
        console.log('mounted');
    },
    updated(){
        console.log('updated');
    },
    unmounted(){
        console.log('unmounted');
    }
}
</script>

.......

{
在这里插入图片描述
}

全部的生命周期函数

{
在这里插入图片描述
}

全局配置axios

在main.js 入口文件中,通过app.config.globalProperties全局挂载axios
{
在这里插入图片描述
}

什么是ref引用

ref用来辅助开发者在不依赖于jQuery的情况下,获取DOM元素或组件的引用。

每个vue的组件实例上,都包含一个$refs对象,里面存储着对应的DOM元素或组件的引用。默认情况下,组件的$refs指向一个空对象。

相当于打一个锚点,并操作 \color{red}{相当于打一个锚点,并操作} 相当于打一个锚点,并操作

让文本框自动获得焦点的方法: . f o c u s ( ) \color{red}{.focus()} .focus()

Dom更新是异步的,因此获取引用对象的时候会出现未定义,因此需要延迟执行,比如方法

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

动态组件

在vue3中,可以声明动态组件 c o m p o n e n t \color{red}{component} component来让组件动态的展示,其中 i s \color{red}{is} is参数可以指明现在的所展示的组件

<template>
  <div>
    <button @click="ckHome">首页</button>
    <button @click="ckMovie">电影</button>
    <hr>
    <component :is="conName"></component>
  </div>
</template>

<script>
import movie from './components/movie.vue';
import home from './components/home.vue';
export default {
  name:'App',
  components:{
    movie,
    home,
  },
  data() {
    return {
      conName:'home'
    }
  },
  methods:{
    ckHome(){
      this.conName = 'home'
    },
    ckMovie(){
      this.conName = 'movie'
    }
  }

}
</script>

<style>

</style>

但是有一个弊端,当组件被切换时,默认将会销毁旧组件,里面的值也会随之被销毁,解决办法就是在 c o m p o n e n t \color{red}{component} component外添加 < k e e p − a l i v e > \color{red}{<keep-alive>} <keepalive>组件保持动态组件的状态

<template>
<div>
    <button @click="ckHome">首页</button>
    <button @click="ckMovie">电影</button>
    <hr>
    <keep-alive>
      <component :is="conName"></component>
    </keep-alive>
  </div>
  .......
</template>

插槽

如果没有预留插槽,那么自定义的任何内容都将被遗弃

具名插槽

如果在封装组件的时候预留了多个插槽并声明了具体的name名称

<slot name="xxx"></slot>

如果只有一个插槽,且未命名,则默认名称为 d e f a u l t \color{red}{default} default

向具名插槽传递

App.vue:

<template>
  <div>
    <button @click="ckHome">首页</button>
    <button @click="ckMovie">电影</button>
    <hr>
    <keep-alive>
      <component :is="conName">
        <template v-slot:header>
            <h1>滕王阁序</h1>
        </template>
        <template v-slot:body>
          唧唧复唧唧,木兰当不知
          《懒得打,乱编的》
        </template>
        <template v-slot:footer>
          <h4>
            王博
          </h4>
        </template>
      </component>
    </keep-alive>
  </div>
</template>

<script>
import movie from './components/movie.vue';
import home from './components/home.vue';
export default {
  name:'App',
  components:{
    movie,
    home,
  },
  data() {
    return {
      conName:'home'
    }
  },
  methods:{
    ckHome(){
      this.conName = 'home'
    },
    ckMovie(){
      this.conName = 'movie'
    }
  }

}
</script>

<style>

</style>

movie.vue:

<template>
  <div>
    <header>
        <slot name="header"></slot>
    </header>
    <main>
        <slot name="body"></slot>
    </main>
    <footer>
        <slot name="footer"></slot>
    </footer>
  </div>
</template>

<script>
export default {
    name:'move'
}
</script>

<style>

</style>

具名插槽 v − s l o t : \color{red}{v-slot:} vslot:可以替换成 # \color{red}{\#} #

作用域插槽

相当于子传父
父组件 — App.vue:

<template v-slot:body="info">
          唧唧复唧唧,木兰当不知
          {{info}}
        </template>

在插槽后面跟一个 = " i n f o " \color{red}{="info"} ="info"可以传递一个对象,info可以看做形参

子组件 — movie.vue:

<template>
 <div>
  ......
   <main>
       <slot name="body" :info="da" :msg="ya"></slot>
   </main>
  ......
 </div>
</template>

<script>
export default {
   name:'move',
   data() {
       return {
           da:'这是一条数据',
           ya:'这是第二条数据'
       }
   },
}
</script>

......

所显示:
在这里插入图片描述

插槽的结构赋值

在default之后可以直接指定数据,更加方便
在这里插入图片描述

私有自定义指令

vue 官方提供了v-for、v-model、v-if等常用的内置指令。除此之外vue还允许开发者自定义指令。

vue中的自定义指令分为两类,分别是:

私有自定义指令 \color{red}{私有自定义指令} 私有自定义指令&&& 全局自定义指令 \color{red}{全局自定义指令} 全局自定义指令

使用自定义指令必须以’v-’开头,声明不需要开头

这里使用了mounted钩子函数

钩住我感兴趣的函数,只要它执行,我就先执行。

{

<template>
    <div>
        directives!!
        自动获得焦点
        <h1>
            
            <input type="text" v-focuss >
        </h1>
        <slot name="header"></slot>
    </div>
</template>

<script>
export default {
    name:'directives',
    data() {
        return {
        }
    },
    directives:{
        focuss:{
            // 被绑定到的函数渲染后自动触发mounted这个函数
            mounted(el) {
                // 用focus获取焦点
                el.focus();
            },
        }
    }
}
</script>

<style lang="less" scoped>

</style>

}

全局自定义指令

在项目的main.js中:
{

import { createApp } from 'vue'
import App from './App.vue'
import './index.css'
import './assets/bootstrap-3.4.1-dist/css/bootstrap.css'

const app = createApp(App)

app.directive('focus',{
    mounted(el){
        el.focus()
    }
})

app.mount('#app')
}

}

update函数

在上面的z局部自定义函数中的代码有一个不足之处,当mounted 函数只在元素第一次插入DOM时被调用,当点击+1后,会失去焦点
请添加图片描述

当DOM更新时 m o u n t e d 函数 \color{red}{mounted函数} mounted函数不会被触发。updated函数会在每次DOM更新完成后被调用。
添加update函数后
请添加图片描述

自定义指令两个注意点:

在vue2项目中,名称有所不同【mounted -> bind】【updated -> update】

mounted和updated的业务逻辑如果相同可以使用简写形式

app.directive('focus',(el)=>{
    el.focus();
})

指令的参数值

在自定义指令中可以通过 = " X X X " \color{red}{="XXX"} ="XXX"来传递参数值

在vue自检中:

<input type="text" v-focus v-color="'red'">

main.js中:

app.directive('color',(el,binding)=>{
	//第二个参数为形参
    el.style.color=binding.value;
})

table案例的一些问题

input输入框change和blur事件区别

blur与change事件在绝大部分的情况下表现都非常相似,输入结束后,离开输入框,会先后触发change与blur,唯有两点例外。

1、没有进行任何输入时,不会触发change

在这种情况下失焦后,输入框并不会触发change事件,但一定会触发blur事件。在判断表单的修改状态时,这种差异会非常有用,通过change事件能轻易地找到哪些字段发生了变更以及其值的变更轨迹。

2、输入后值并没有发生变更

这种情况是指,在没有失焦的情况下,在输入框内进行的删除与输入操作,但最终的值与原值一样,这种情况下失焦后,keydown、input、keyup、blur都会触发,但change依旧不会触发。

路由

路由前导

后端路由

后端路由指的是:请求方式、请求地址与function 处理函数之间的对应关系。

SPA项目中的前端路由

SPA指的是一个web网站只有唯一的一个HTML页面,所有组件的展示与切换都在这唯一的一个页面内完成。
此时,不同组件之间的切换需要通过前端路由来实现。

前端路由

Hash地址与组中的联系

前端路由工作方式

用户点击了页面上的路由链接

导致了URL地址栏中的Hash值发生了变化

前端路由监听了到Hash地址的变化

前端路由把当前Hash地址对应的组件渲染都浏览器中

安装Vue-router

cnpm i vue-router@next -S

自定义Router高亮连接

后面为类名

linkActiveClass:‘XXXX’,

动态路由的概念

通过冒号(:)可以定义后面的参数是可变的
如/home/:XXX
参数值可以通过 $ r o u t e . p a r a m s \color{red}{route.params} route.params来获取XXX


也可通过prop传参
(1)在动态路由规则开启动态传参 props:true
在这里插入图片描述
(2)在子组件使用props数组进行接收
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值