Vue 基础

vue2学习

1.vue的基本概念

1.概念:Vue是一个用于 构建用户界面渐进式 框架

  • 构建用户界面:基于数据渲染出用户看到的界面
  • 渐进式:循序渐进
  • 框架:一套完整的项目解决方案

2.优缺点:

  • 可以提高开发效率,需要理解记忆规则
  • 响应式特性:数据变化,视图自动更新

2.核心包传统开发模式

1.常用指令

1.插值表达式
  • 概念:Vue的一种模版语法
  • 作用:利用 表达式 进行插值渲染
  • 表达式:可以被求值
  • 语法: {{ 表达式 }}

代码:

//语法:{{   表达式   }}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    //导入根目录下的  开发版本包
    <script src="./vue.js"></script>
</head>
<body>
   <div id="app">
    {{  count }}
   </div>
   
   <script>
    const app=new Vue({
        el:'#app',
        data:{
            count:100
        }
    })
   </script>
</body>
</html>

2.v-html指令
  • 作用:动态地设置元素的innerHTML,可以解析字符串标签
  • 语法:v-html=“表达式”

代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
</head>
<body>
   <div id="app" v-html="mgs">
   
   </div>
   
   <script>
    const app=new Vue({
        el:'#app',
        data:{
           mgs:' <a href="https://www.baidu.com/">百度官网</a>'
        }
    })
   </script>
</body>
</html>
3.v-show和v-if指令

v-show

  • 作用:控制元素的显示与隐藏
  • 语法:v-show=“表达式” 表达式值为 true 显示,为 false 隐藏
  • 原理:切换display:none 来控制显示与隐藏
  • 应用场景:适合于频繁切换显示与隐藏的场景

v-if

  • 作用:控制元素的显示与隐藏(条件渲染)
  • 语法:v-if=“表达式” 表达式值为 true 显示,为 false 隐藏
  • 原理:基于条件判断,是否 创建移除 元素节点
  • 应用场景:要么显示,要么隐藏,不频繁切换的场景

代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
    <style>
        .a1{
            width: 200px;
            height: 100px;
            background-color: aqua;
        }
        .a2{
            width: 200px;
            height: 100px;
            background-color: pink;
        }
    </style>
</head>
<body>
   <div id="app">
     <div class="a1" v-show="flag1">我是v-show指令盒子</div>
     <div class="a2" v-if="flag2">我是v-if指令盒子</div>
   </div>
   <script>
    const app=new Vue({
        el:'#app',
        data:{
          flag1:true,
          flag2:true
        }
    })
   </script>
</body>
</html>
4.v-else指令和v-else-if指令
  • 作用:辅助 v-if 进行判断渲染
  • 语法:v-else后面不加表达式 v-if-else=“表达式”
  • 注意:需要紧挨着v-if使用

代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>

</head>
<body>
   <div id="app">
     <span v-if="score >= 90">优秀</span>
     <span v-else-if="score >= 80 & score<90">良好</span>
     <span v-else-if="score >= 60 & score<80">合格</span>
     <span v-else>不合格</span>
   </div>
   <script>
    const app=new Vue({
        el:'#app',
        data:{
          score:85
        }
    })
   </script>
</body>
</html>
5.v-on指令
  • 作用:注册事件 = 添加监听 + 提供处理逻辑

  • 语法:

    • v-on:事件名 = “内联语句”

    • v-on:事件名 = “methods中的函数名”

      函数中可以设置形参

  • 简写:@事件名

代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>

</head>
<body>
   <div id="app">
      <button @click="count++">+</button>
      <span>{{ count }}</span>
      <button @click="fn">-</button>
   </div>
   <script>
    const app=new Vue({
        el:'#app',
        data:{
          count:100
        },
        methods:{
            fn(){
                this.count--
            }
        }
    })
   </script>
</body>
</html>
6.v-bind指令
  • 作用:动态的设置html的标签属性,如 src url title
  • 语法:v-bind:属性名=“表达式”
  • 简写::属性名=“表达式”

代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>
    <style>
        div{
            width: 300px;
            height: 400px;
            position: absolute;
            top: 0;
            bottom: 0;
            left: 0;
            right: 0;
            margin: auto;
        }
        button{
             margin-left: 60px;
        }
    </style>
</head>
<body>
    <!--  v-bind指令  动态的设置html标签的属性  -->
    
    <div id="app">
       <img v-bind:src="list[index]" v-bind:title="msg">
<!-- 另一种写法:
<img :src="imgUrl" :title="msg">
-->
<button @click="index--" v-show="index > 0">上一张</button>
  <button @click="index++" v-show="index < 3">下一张</button>

    </div>
    
    <script>
        const app=new Vue({
            el:'#app',
            data:{
                index:0,
                list:[
                './imges/1.png',
                './imges/2.png',
                './imges/3.png',
                './imges/4.png'
                ],
              msg:'小鸟飞呀飞~~~'
            }
        })
       </script>
</body>
</html>

对样式控制的增强——操作class

  • 语法::class=“对象/数组”
    • 对象:键就是类名,值就是布尔值,如果为true,就有这个类,如果为false,就没有这个类,适用于一个场景,类名来回切换
    • 数组:数组中所有的类都添加到盒子上,本质上是一个calss列表,适用于,批量的添加或删除类

代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        .a{
            background-color: red;
            color: white;
        }
        li{
            width: 100px;
            height: 50px;
            background-color: aqua;
            margin-bottom: 10px;
        }
    </style>
    <script src="./vue.js"></script>
</head>
<body>
    <div id="app">
        <ul>
            <li :class="{a: index == flag}" v-for="(item,index) in list" :key="item.id"  @click="flag=index">{{ item.name }}</li>
        </ul>
    </div>
    <script>
        const app=new Vue({
            el:'#app',
            data:{
                flag:0,
                list:[
                    {id:1,name:'A'},
                    {id:1,name:'B'},
                    {id:1,name:'C'}
                ]
            }
        })
    </script>

</body>
</html>
7.v-for指令
  • 作用:基于数据循环,多次渲染整个元素 数组、对象、数字
  • 遍历数组语法: v-for = “(item,index) in 数组名”
    • item 每一项
    • index 数组下标
  • v-for中key的用法
    • 作用:给列表项添加唯一的标识,便于Vue进行列表项的正确排序复用
    • 语法:key属性=“唯一标识”

代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>

</head>
<body>
   <div id="app">
    <ul>
        <li v-for="(item,index) in list" :key="item.id">
            <span> {{ item.name}} </span>
            <span>{{  item.score }}</span>
        </li>
    </ul>
   </div>
   <script>
    const app=new Vue({
        el:'#app',
        data:{
           list:[
            {id:1,name:'张三',score:80},
            {id:2,name:'李思',score:85},
            {id:3,name:'王五',score:75},
           ]
        }
    })
   </script>
</body>
</html>
8.v-model指令
  • 作用:给 表单元素 使用,双向数据绑定, 可以快速 获取 或 设置 表单元素内容
    • 数据变化 视图自动更新
    • 视图变化 数据自动更新
  • 语法:v-model=”变量“

代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="./vue.js"></script>

</head>
<body>
   <div id="app">
      账号:<input type="text" v-model="username">
      <br>
      密码:<input type="password" v-model="password">
      <br>
      <button @click="login">登录</button>
      <button @click="reset">重置</button>
   </div>
   <script>
    const app=new Vue({
        el:'#app',
        data:{
         username:'',
         password:''
        },
        methods:{
           login(){
            console.log(this.username,this.password)
           },
           reset(){
              this.username='',
              this.password=''
           }
        }
    })
   </script>
</body>
</html>

2.计算属性

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

语法:

  • 声明在computed配置项中,一个计算属性对应一个函数
  • 使用起来和普通属性一样 {{ 计算属性名 }}

计算属性就是将一段 求值的代码 进行封装

语法格式

          computed:{
           计算属性名(){
            基于现有的数据,编写求值逻辑
            return 结果
           }
          }

代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="./vue.js"></script>
</head>
<body>
  <div id="app">
       <table>
        <tr v-for="(item,index) in list" :key="item.id">
          <td>{{ item.id }}</td>
          <td>{{ item.name }}</td>
          <td>{{ item.price }}</td>
        </tr>
       </table>

       <p>统计:{{ totilprice }} 元</p>
  </div>

  <script>
         const app=new Vue({
          el:'#app',
          data:{
             list:[
              {id:1,name:'篮球',price:30},
              {id:2,name:'乒乓球',price:15},
              {id:3,name:'羽毛球',price:20},
              {id:4,name:'足球',price:25}
             ]
          },
          computed:{
           totilprice(){
            // 利用 reduce 函数对数组里的 price 进行求和
            let count = this.list.reduce((sum,item) => sum+item.price,0)
            return count;
           }
          }
        
         })
  </script>
</body>
</html>

计算属性的完整语法格式:

  • 计算属性默认的简写,只能读取,访问,不能 修改
  • 如果需要修改,需要写计算属性的完整写法

语法格式:

          computed:{
           计算属性名:{
            get(){
                计算逻辑
                return 结果
            },
            set(){
                 修改逻辑
            }
           }
          }

3.watch语法

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

语法:

  • 简单写法,简单类型数据,直接监视

    
    
  • 完整写法,添加额外的配置项

4.生命周期

  1. 创建阶段
    • before Create
    • created :可以发送初始化渲染请求
  2. 挂载阶段
    • before Mount
    • mounted:可以操作dom
  3. 更新阶段
    • before Update
    • updated
  4. 销毁阶段
    • before Destroy
    • destroyed

3.工程化开发模式

1.基本环境的搭建

1.安装node.js

node.js 官网地址:Node.js (nodejs.org)

2.配置Vue脚手架

用cmd命令运行

  1. 全局安装:yarn global add @Vue/cli 或者 npm i @Vue/cli -g
  2. 查看Vue版本:vue - - version
  3. 创建项目架子:vue create 项目名称 (项目名不能用中文)
  4. 启动项目:yarn serve 或者 npm run serve

2.组件化开发

1.相关概念
  • 组件化:一个页面可以拆分为一个个组件,每个组件有着自己独立的 结构 样式 行为

    • 好处:便于维护,利于复用,提高开发效率
    • 组件分类:普通组件 根组件
  • 根组件:整个应用最上层的组件,包裹所有普通的小组件(App.vue)

  • 组件组成:

    <template> 
    //结构
    </template>
    
    <script>
       //行为
    export default {
    
    }
    </script>
    
    <style>
     //样式
    </style>
    

根组件的结构: 根组件 div盒子中放的是组件,而不是标签

<template>
  <div id="app">
    <!-- 头部组件 -->
    <DiyiHead></DiyiHead>
    
    <!-- 主体组件 -->
    <DiyiMain></DiyiMain>

    <!-- 底部组件 -->
    <DiyiFooter></DiyiFooter>
    
    <DiyiFooter></DiyiFooter>
  </div>
</template>
2.普通组件的局部注册

**作用范围:**只能在注册的组件内使用

步骤

  1. 在components文件夹下创建 .vue文件

  2. 在使用的组件内导入并注册

    <script>
        //导入需要注册的组件
        //import 组件对象 from '.vue文件的路径';
    import DiyiFooter from './components/DiyiFooter.vue';
    import DiyiHead from './components/DiyiHead.vue';
    import DiyiMain from './components/DiyiMain.vue';
    export default {
      components:{
          //局部注册
        //组件名:组件对象
        DiyiHead:DiyiHead,
        DiyiMain: DiyiMain,
        DiyiFooter:DiyiFooter
      }
    }
    </script>
    
  3. 使用:当成html标签使用 <组件名></组件名>

3.普通组件的全局注册

**作用范围:**所有组件都能使用

步骤:

  1. 在components文件夹下创建 .vue文件

  2. 在main.js中进行全局注册

    import Vue from 'vue'
    import App from './App.vue'
    //导入
    import DiyiQj from './components/DiyiQj'
    Vue.config.productionTip = false
    
    
    //Vue.component('组件名',组件对象)
    //进行全局注册,在所有组件范围内都能直接使用
    Vue.component('DiyiQj',DiyiQj)
    
    
    //.$mount('#app)  就相当于 el:'#app'
    new Vue({
      render: h => h(App),
    }).$mount('#app')
    
    
  3. 使用:当成标签使用

4.scoped样式冲突和data函数

样式冲突

  • 默认情况:写在组件中的样式会全局生效
  • 全局样式:默认组件中的样式会作用于全局
  • 局部样式:可以给组件加上scoped属性,可以让样式只作用于当前组件

代码:

<style scoped>

</style>

data函数:

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

  • 代码:

      <script>
      export default {
        //data 必须是一个函数 ,保证每个组件实例,维护独立性
         data(){
            return {
                count:100
            }
         }
      }
      </script>
    

3.组件通信

1.组件通信的作用
  • 组件通信就是指组件与组件之间的数据传递
  • 组件的数据是独立的,无法直接访问其他组件的数据
  • 想要使用其他组件的数据必须通过组件通信
2.“父子”通信
  • 父组件通过props将数据传递给子组件

    • 在父组件内 , 给子组件以添加属性的方式传值
    <template>
      <div id="app">
       我是父组件
        <NoeSon :shuju="Fu"></NoeSon>
      </div>
    </template>
    
    • 在子组件内 , 通过props接收数据
    • 在模版中直接使用
    <template>
      <div id="zi">我是子组件
        <p>{{ shuju }}</p>
      </div>
    </template>
    
    <script>
    export default {
       props:['shuju']
    }
    </script>
    
  • 子组件利用$emit通知父组件修改更新

    • $emit触发事件,给父组件发送消息通知
    <template>
      <div id="zi">我是子组件
        <p>{{ shuju }}</p>
        <br>
        <button @click="dianji">点我呀</button>
      </div>
    </template>
    
    <script>
    export default {
       props:['shuju'],
       methods:{
        dianji(){
            this.$emit('change','好的,爸爸!')
        }
       }
    }
    </script>
    
    • 父组件监听事件
    <template>
      <div id="app">
       我是父组件
        <NoeSon :shuju="Fu" @change="geibian"></NoeSon>
      </div>
    </template>
    

    ( @后面监听的事件名要与父组件中$emit中触发的事件名相同 )

    • 提供处理函数,形参中获取参数
    <script>
        export default {
        methods:{
        geibian(newValue){
          this.Fu=newValue
        }
        }
    </script>
    
  • props的详解

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

    • 作用:给子组件传递数据

    • 特点:可以传递 任意数量 任意类型 的props

    • props和data的区别

      • props和data都可以给组件提供数据
      • data是自己的数据可以修改,而props是别人的数据不能直接修改
      • props是单向数据流
    • 代码演示:

//在父组件内


```vue
//在子组件内
<template>
<div id="zi">
  <p>姓名:{{ username }}</p>
  <p>年龄:{{ age }}</p>
  <p>兴趣爱好:{{ love.join("、") }}</p>
</div>
</template>

<script>
export default {
 props:['username','age','love']
  
 }
</script>
  • props的校验

    • 为组件中的props指定验证要求,不符合要求,控制台就会提示错误

    • 语法

      • 类型校验
      • 非空校验
      • 默认值
      • 自定义校验
    • 代码

      一般写法:

    <script>
    export default {
       props:{
           校验的属性名:类型
       }
        
       }
    </script>
    

    完整写法:

    <script>
    export default {
       props:{
           校验的属性名:{
               type:类型,//
               required:true,//是否必填
               default:默认值,
               validator(value){
                   //自定义校验逻辑
                   return 是否通过校验
               }
           }
       }
        
       }
    </script>
    
3.非父子通信

event bus 事件总线

  • 创建一个都能访问到的事件总线(空的Vue实例) 首先在src下创建一个utils文件夹,然后在文件夹中创建一个EventBus.js文件,内容如下:
import Vue from 'vue'

const Bus=new Vue()

export default Bus
  • 在消息接收方组件,监听Bus实例的事件
  <script>
  import Bus from '../utils/EventBus'
  export default {
     created(){
       Bus.$on('FaSong',(msg) =>{
        //  console.log(msg)
        this.title=msg
       })
     },
     data(){
        return {
            title:''
        }
     }
  }
  </script>
  • 在消息发送方组件,触发Bus实例的事件
<template>
  <div id="zi">
    <span>我是组件1</span>
    <br>
    <button  @click="Fn">发送消息</button>
  </div>
</template>

<script>
import Bus from '@/utils/EventBus';
export default {
  methods:{
   Fn(){
    Bus.$emit('FaSong','hello word')
   }
  }
}
</script>
  • 注意:监听的事件名应和触发的事件名保持一致,且消息的传递可以是一对多的关系

provide 和 inject

  • 父组件provide提供数据
<script>
import NoeSon1 from './components/NoeSon1.vue';
import NoeSon2 from './components/NoeSon2.vue';
export default {
  components:{
    NoeSon1,
    NoeSon2
  },
  data(){
    return {
      username:'张三',//简单类型(非响应式)
      users:{//复杂类型
        age:18,
        sex:'男'
      }
    }
  },
  provide(){
     return{
      username:this.username,
      users:this.users
     }
  }
}
  • 子组件/孙组件 inject 取值
<script>
export default {
  inject:['username','users']
}
</script>
4.子组件与父组件的数据绑定

v-model的原理

  • 原理:本质上是value属性和input事件的合写
  • 作用:实现数据的双向绑定
<template>
  <div id="app">
     <input type="text" v-model="msg1">
     <br>
     <input type="text" :value="msg2" @input="msg2=$event.target.value">
  </div>
</template>

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

<style>

</style>
  • 注意:$event用于在模版中,获取事件的形参
  • 利用v-model简化 组件数据绑定 代码
//父组件中直接使用v-model指令
<template>
  <div id="app">
    <OneSon v-model="msg"></OneSon>
  </div>
</template>

//子组件中
<template>
  <div id="zi">
    <select :value="value" @change="FN">
        <option value="001">武汉</option>
        <option value="002">黄冈</option>
        <option value="003">襄阳</option>
        <option value="004">宜昌</option>
        <option value="005">十堰</option>
        <option value="006">荆门</option>
    </select>
  </div>
</template>

<script>
export default {
  props:{
    value:String
  },
  methods:{
    FN(e){
    this.$emit('input',e.target.value)
    }
  }

}
</script>

<style>

</style>

.sync修饰符

  • 作用:实现子组件和父组件数据的双向绑定,简化代码
  • 特点:props属性名可以自定义,非固定为value
  • 场景:封装弹窗类的 基础组件
  • 本质:就是 属性名 和 updata : 属性名的合写
  • 语法:
//父组件
<template>
  <div id="app">
    <OneSon :visible.sync="msg"></OneSon>
  </div>
</template>

//子组件
<script>
export default {
  props:{
    value:Boolean
  },
  methods:{
    FN(e){
    this.$emit('updata:visible',true)
    }
  }

}
</script>

4.dom元素的获取

1.ref 和 $refs
  • 作用:利用ref和$refs可以用于获取 dom元素组件实例
  • 特点:在当前组件范围内查找(更加精确)
  • 代码演示:
<template>
  <div id="main" ref="mychart">

  </div>
</template>

<script>
import * as echarts from 'echarts'
export default {
  mounted(){
    const myChart = echarts.init(this.$refs.mychart);
    var option = {
        title: {
          text: 'ECharts 入门示例'
        },
        tooltip: {},
        legend: {
          data: ['销量']
        },
        xAxis: {
          data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
        },
        yAxis: {},
        series: [
          {
            name: '销量',
            type: 'bar',
            data: [5, 20, 36, 10, 10, 20]
          }
        ]
      };

      // 使用刚指定的配置项和数据显示图表。
      myChart.setOption(option);
  },
}
</script>

<style>
  #main{
    width: 600px;
    height: 400px;
    border: 3px black solid;
  }
</style>
2.Vue异步更新和$nextTick
  • 同步交互:指发送一个请求,需要等待返回,然后才能够发送下一个请求,有个等待过程;
  • 异步交互:指发送一个请求,不需要等待返回,随时可以再发送下一个请求,即不需要等待。
  • 区别:一个需要等待,一个不需要等待,在部分情况下,我们的项目开发中都会优先选择不需要等待的异步交互方式。
  • Vue在更新DOM 时是异步执行的
  • 想要在dom更新完成之后再执行某件事情,可以使用==$nextTick==
  • 具体语法:
   this.$nextTick(() => {
        //业务逻辑
      })
3.自定义指令
  • 作用:自己定义的指令可以封装一些dom操作,扩展额外的功能
  • 全局注册:可以在任意组件内使用
//main.js 文件中进行全局注册
Vue.directive('focus',{
//inserted  是生命周期钩子, 会在 指令所在元素,被插入到页面中时触发
  inserted(el){
//el就是指令所绑定的元素
    el.focus();
  }
})

//在使用的组件中,直接加上   v-“指令名”
<template>
  <div id="zi">
    <h1>自定义指令</h1>
    <input type="text" ref="inp" v-focus>
  </div>
</template>
  • 局部注册:只能在当前组件内使用
<script>
export default {
    //在directives中可以设置多个指令
directives:{
    //指令名:{指令配置项}
    focus:{
        inserted(el){
          el.focus()
        }
    }
}
}
</script>
  • 指令的值:在绑定指令时,可以通过“等号”的形式伪指令 绑定具体的参数值
<template>
  <div id="zi">
    <h1>自定义指令</h1>
    <h2 v-color="color1">指令的值测试1</h2>
    <h2 v-color="color2">指令的值测试2</h2>
  </div>
</template>

<script>
export default {
    //在directives中可以设置多个指令
directives:{
    //指令名:{指令配置项}
    color:{
        inserted(el,binding){
            //binding.value  就是指令的值
          el.style.color=binding.value
        }
    }
},
data(){
    return {
        color1:'red',
        color2:'pink'
    }
}
}
</script>

<style>
  
</style>

5.插槽

1.默认插槽

作用:让组件内的一些 结构 支持 自定义

只有一个定制位置

使用步骤:

  • 现在组件内用slot占位
  • 使用组件时,传入具体标签内容插入

代码:

//先占位
<template>
  <div id="zi">
    <h1>提示框</h1>
    <span>友情提示:</span>
    <div class="cz">
      <slot></slot>
    </div>
  </div>
</template>

//使用时传入具体的值
<template>
  <div id="app">
    <OneSon>
      <span>不要玩手机</span>
    </OneSon>
    <OneSon>不要打游戏</OneSon>
  </div>
</template>

2.默认值

可以在slot标签内部传入默认值

如果在组件内部没有传入具体的值,默认值生效

如果在组件内部传入了具体的值,则显示的是具体的值

代码演示:

  <div class="cz">
      <slot>我是默认值</slot>
    </div>
3.具名插槽
  • 需求:一个组件内部有多处结构,需要外部传入标签,进行定制
  • 语法结构:

多个slot使用name属性区分名字

<template>
  <div id="zi">
    <h1>提示框</h1>
    <span>友情提示:</span>
    <div class="cz1">
      <slot name="no1"></slot>
    </div>
    <div>
        <slot name="no2"></slot>
    </div>
  </div>
</template>

template配合 v-slot:插槽名字 来分发对应标签

v-slot:插槽名字 可以简写为 #插槽名

<template>
  <div id="app">
    <OneSon>
      <template v-slot:no1>
        我是传入值1
      </template>
      <template v-slot:no2>
        我是传入值2
      </template>
    </OneSon>
  </div>
</template>
4.作用域插槽

作用:定义slot插槽 的同时,是可以传值的,给插槽上可以绑定数据,将来使用组件时可以用

应用场景:封装表格组件

使用步骤:

  • 给slot标签,以添加属性的方式传值
  • 所有添加的属性,都会被收集到一个对象中
  • 在template中,通过 #插槽名=“obj”接收,默认插槽名为default

6.路由

1.路由模块封装

路由的基本使用:

  • 下载Vuerouter模版到当前工程,版本3.6.5
yarn add vue-router@3.6.5
  • 引入
  • 安装注册
  • 创建路由对象
  • 注入,将路由对象注入到new Vue实例中,建立关联
  • 创建需要的组件,并放在views文件夹下,配置路由规则
//在src下创建router文件夹
//在router文件夹中创建index.js文件
import OneSon from '@/views/OneSon'
import TwoSon from '@/views/TwoSon'
import ThreeSon from '@/views/ThreeSon'
import VueRouter from 'vue-router'
import Vue from 'vue'
Vue.use(VueRouter)

const router =new VueRouter({
    routes:[
        {path:'/one',  component:  OneSon},
        {path:'/two',  component:  TwoSon},
        {path:'/three',  component: ThreeSon},
    ]
})
//导出路由对象
export default  router


//main.js 文件中
//将路由对象注入到Vue实例中
import Vue from 'vue'
import App from './App.vue'
import router from './router/index.js'

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
  router
}).$mount('#app')
  • 配置导航,配置路由出口(路径匹配的组件显示的位置)
<template>
  <div id="app">
    <div id="biao">
      <router-link  to="one">我的</router-link>
      <router-link  to="two">我的喜欢</router-link>
      <router-link  to="three">我的收藏</router-link>
    </div>
      <div id="xia">
          //路由出口
        <router-view></router-view>
      </div>
      
  </div>
  
</template>
2.声明式导航 跳转传参
  • 目的:在跳转路由时,进行传参

1.查询参数传参(多个参数)

  1. 语法:to=“/path?参数名=值”
<template>
  <div id="app">
    <div id="biao">
      <router-link to="/one?key=首页">首页</router-link>
      <router-link  to="/two?key=购物车">购物车</router-link>
      <router-link  to="/three?key=我的喜欢">我的喜欢</router-link>
    </div>
      <div id="xia">
        <router-view></router-view>
      </div>
  </div>
  
</template>

对应页面组件接收传递过来的值 :$route.query.参数名

<template>
  <div>
     <h1>这里是我的喜欢</h1>
     <h2>输入的是:{{ $route.query.key }}</h2>
  </div>
</template>

2.动态路由传参(简洁优雅)

  1. 设置动态路由
  2. 配置导航链接
  3. 对应页面组件接收传递过来的值
设置动态路由
path:'/path/:参数名'
配置导航链接
to="/path/参数值"
对应页面组件接收传递过来的值
$route.params.参数名

注意:动态路由参数可选符,‘/path/:参数名’,表示必须要传参数,如果不传参数,也希望匹配,可以加一个可选符 “?”

3.路由——重定向

1.重定向

  • 问题:网页打开,URL默认是 / 路径,未匹配到组件时,就会出现空白
  • 说明:匹配path后,强制跳转path路径
  • 语法:{path:匹配路径,redirect重定向到的路径}

2.Vue路由 404

  • 作用:当路径找不到匹配时,给一个提示页面
  • 位置:配在路由最后
  • 语法:{path:“*” (任意路径)前面不匹配就命中最后这个}

3.Vue路由——模式设置

  • 问题:路由的路径看起来不自然,有#,能否切成真正的路径形式

  • hash路由(默认) 路径中有#

  • history路由(常用) 没有# (以后上线需要服务器端支持)

  • 语法:

    const router =new VueRouter({
        routes:[
            {path:'/',  redirect: '/one'},
            {path:'/one',  component:  OneSon},
            {path:'/two',  component:  TwoSon},
            { name: 'three' , path:'/three/:key?',  component: ThreeSon},
        ],
        mode:'history',
        // linkActiveClass:'active',
        // linkExactActiveClass:'exact-active'
    })
    
4.编程式导航——基本跳转

1.path路径跳转(简易方便)

      this.$router.push({
        // path:'路由路径'
        path:'/one'
      })
  1. name 命名路由跳转(适合与path 路径长的场景)
//首先给路由设置名字
     { name: 'three' , path:'/three/:key?',  component: ThreeSon},
         
//然后跳转
     this.$router.push({
        // name:'路由名'
       name:'three'
      })

3.路由传参

  1. path路径跳转传参
//1.查询参数传参
   this.$router.push({
        path:'路由路劲',
        query:{
          参数名1:'参数值1',
          参数名2:'参数值2',
        }
   接收:$route.query.参数名
   
//2.动态路由传参
      this.$router.push({
        path:'/路径/参数值',
      })
   接收:$route.params.参数名  (动态路由传参需要配置路由)

2.name路径传参

   this.$router.push({
        name:'路由名',
        query:{
          参数名1:'参数值1',
          参数名2:'参数值2',
      /* params:{
          参数名1:'参数值1',
          参数名2:'参数值2',*/
        }
       接收:用什么传参就用什么接收,用query传参就用,$route.query.参数名接收
       用params传参就用,$route.params.参数名接收
5.组件缓存

原因:路由跳转后。组件被销毁了、返回回来组件又被重构了,所以数据重新被加载了

解决:利用Keep-alive 将组件缓存下来

优点:减少加载时间以及性能消耗,提升用户体验性

代码:

      <div id="xia">
        <keep-alive>
          <router-view></router-view>
        </keep-alive>
      </div>

7.vue cli自定义创建项目

1.创建项目

1.创建项目

PS D:\ProgrammingLanguage\vscode\HTml\vue\demo> vue create moble

2.选择自定义

Vue CLI v5.0.8
? Please pick a preset:
  Default ([Vue 3] babel, eslint)
  Default ([Vue 2] babel, eslint)
> Manually select features//自定义

3.添加项目需要那些特性:Babel / Router / CSS Pre-processors / Linter / Formatte

? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection, and
<enter> to proceed)
 (*) Babel
 ( ) TypeScript
 ( ) Progressive Web App (PWA) Support
 (*) Router
 ( ) Vuex
>(*) CSS Pre-processors
 (*) Linter / Formatter
 ( ) Unit Testing
 ( ) E2E Testing

4.选择Vue的版本:vue2

? Choose a version of Vue.js that you want to start the project with
  3.x
> 2.x

5.是否使用路由的history模式:no

? Use history mode for router? (Requires proper server setup for index fallback in production) No

6.选择一个css的预处理器:Less

? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default):
  Sass/SCSS (with dart-sass)
> Less
  Stylus

7.选择采用哪一套 ESLint规范: ESLint + Standard config 无符号规范(标准化)

? Pick a linter / formatter config:
  ESLint with error prevention only
  ESLint + Airbnb config
> ESLint + Standard config
  ESLint + Prettier

8.你需要什么时候校验: Lint on save 保存时校验

? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection, and <enter> to
proceed)
>(*) Lint on save
 ( ) Lint and fix on commit (requires Git)

9.你想要将配置文件放在哪里? In dedicated config files 放在单独的配置文件中

? Where do you prefer placing config for Babel, ESLint, etc.? (Use arrow keys)
> In dedicated config files
  In package.json

10.是否需要保存?不保存

? Save this as a preset for future projects? (y/N) n

最后整个的步骤:

Vue CLI v5.0.8
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, CSS Pre-processors, Linter
? Choose a version of Vue.js that you want to start the project with 2.x
? Use history mode for router? (Requires proper server setup for index fallback in production) No
? Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default): Less
? Pick a linter / formatter config: Standard
? Pick additional lint features: Lint on save
? Where do you prefer placing config for Babel, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No
2. ESLint 代码规范

其中一小部分规则:

  • 字符串使用单引号
  • 无分号
  • 关键字后面加空格
  • 函数名后加空格
  • 坚持使用 === 放弃使用 ==

代码规范说明:https://standardjs.com/rules-zhcn.html

查找错误:进入上面网页 Ctrl + F 直接搜索错误原因

8.vuex

1.vuex概述
  1. 是什么:vuex是一个插件,可以帮助我们管理Vue通用的数据(多组件共享的 数据)
  2. 应用场景:
    1. 某个状态 在很多个组件 来使用(个人信息)
    2. 多个组件 共同维护 一份数据(购物车)
  3. 优势:
    • 共同维护一一份数据,数据集中化管理
    • 响应式变化
    • 操纵简洁(vuex提供了一些辅助函数)
2.创建一个空仓库
  • 安装vuex
yarn add vuex@3
  • 在src文件夹下,新建store文件夹,在store文件夹下新建index.js文件,专门存放vuex
  • 创建仓库
// 这里面就是存放vuex的相关的核心代码
import Vue from 'vue'
import Vuex from 'vuex'

// 插件安装
Vue.use(Vuex)

// 创建仓库
const store = new Vuex.Store()

// 导出给main.js使用
export default store

  • 在main.js 中导入挂载
import Vue from 'vue'
import App from './App.vue'
import store from '@/store/index'

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
  store
}).$mount('#app')

3.访问vuex的数据

1.提供数据

state提供唯一的 公共数据源,所有共享的数据都要统一放在store中的state中存储

在state对象中可以添加我们需要共享的数据

const store = new Vuex.Store({
  state: {
    count: 100
  }
})

2.使用数据

通过store直接访问

获取store:

  • this.$store
  • import 导入 store

在模版中:

{{ $store.state.xxx }}

组件逻辑中:

this.$store.state.xxx

js模块中:

store.state.xxx

通过辅助函数(化简)

mapState是辅助函数,帮助我们把store中的数据 自动 映射到组件的计算属性中

  1. 导入mapState : import { mapState } from ‘vuex’
  2. 数组方式引入state
  3. 展开运算符映射
<script>
import { mapState } from 'vuex'
export default {

  computed: {
    ...mapState(['count'])
  }
}
</script>
4.mutations的基本使用

作用:来修改state中的数据(state中的数据的修改只能通过mutations)

语法:

const store = new Vuex.Store({
  state: {
    count: 100
  },
  // 通过mutations可以提供  修改数据的方法
  mutations: {
    add (state, n) {
      state.count += n
    }
  }
})

在mutations中提供修改数据的方法

方法中的第一个参数为state

在组件中只需要调用mutations中的方法就可以修改state中的数据

   this.$store.commit('add', 5)

mutations中方法的参数只能有一个,如果需要多个参数可以包装成一个对象

    this.$store.commit('add', {
        count: 10,
        title: 'hello word!'
      })
5.辅助函数mapMutations

作用:把位于mutations中的方法提取出来,映射到组件中methods中

语法:

<script>
import { mapMutations } from 'vuex'
export default {
  name: 'SonTwo',
  methods: {
    ...mapMutations(['add']),
    jia () {
      this.add(5)//调用
    }
  }
}
</script>
6.action

作用:用于处理异步操作

说明:mutations必须是同步的(便于监测数据变化,记录调试)

语法:

const store = new Vuex.Store({
  state: {
    count: 100
  },
  // 通过mutations可以提供  修改数据的方法
  mutations: {
    add (state, n) {
      state.count += n
    }
  },
  actions: {
    change (context, n) {
      setTimeout(() => {
        context.commit('add', n)
      }, 2000)//模拟异步
    }
  }
})

mapActions辅助函数
作用:mapActions把位于action中的方法提取出来,映射到组件methods 中

语法:

<script>
import { mapActions } from 'vuex'
export default {
  name: 'SonOne',
  methods: {
    ...mapActions(['change']),
    cn () {
      this.change(10)
    }
  }
}
</script>

getters

作用:类似于计算属性

语法:

getters: {
    //1.getters函数中的第一个参数必须是state
    //getters函数必须有返回值
   fn (state) {
       return state.list.filter(item => item > 5)
   }
}
7.modules模块

1.模块的创建

在store文件夹下新建modules文件夹,在modules文件夹下新建user.js文件

// user模块

const state = {
  userInfo: {
    username: '',
    age: 18
  },
  score: 80
}
const mutations = {}
const actions = {}
const getters = {}

// 导出挂载
export default {
  namespaced: true,
  state,
  mutations,
  actions,
  getters
}

在index.js中导入使用

导入
import uesr from './modules/uesr'
  modules: {
    uesr
  }

2.模块中数据的使用

State中的数据

直接通过模块名访问

语法:

  <p>{{ $store.state.uesr.userInfo.username }}</p>

通过mapState映射

  • 默认根级别的映射

    就是将先子模块当做根模块的一个属性,然后用子模块这个属性拿到里面的值

//导入
import { mapState } from 'vuex'
//映射
computed: {
    ...mapState(['uesr'])
  }
//使用
<p>{{ uesr.userInfo.age }}</p>
  • 子模块的映射

    需要开启命令空间

    语法:

//首先,在子模块中开启命令空间
export default {
  namespaced: true, // 开启命令空间
  state,
  mutations,
  actions,
  getters
}
//映射
  computed: {
    ...mapState('uesr', ['score'])
  }
//使用
 <p>{{ score }}</p>

Getters的访问

直接通过模块名访问

$store.getters['模块名/xxx']

通过mapGetters映射

  • 默认根级别的映射
mapGetters(['xxx'])
  • 子模块的映射 需要开启命名空间
mapGetters('模块名',['xxx'])

mutation的调用语法

直接通过store调用 $store.commit(‘模块名/xxx’,额外参数)

通过mapMutations映射

  • 默认根级别的映射
mapMutations(['xxx'])
  • 子模块的映射 需要开启命名空间
mapMutations('模块名',['xxx'])

4.小结

项目打包

将多个文件压缩成一个文件

打包命令:

yarn build

结果:根目录会自动创建一个dist文件夹,dist文件夹中的文件就是打包后的文件,只需要放在服务器中即可

配置:默认情况下,需要放在服务器根目录打开,如果希望双击打开,需要配置publicPath配成相对路径

//在vue.config.js中加上   publicPath: './',
const { defineConfig } = require('@vue/cli-service')
module.exports = defineConfig({
  publicPath: './',
  transpileDependencies: true
})
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值