Vue3

Vue3

1.Vue简介

1.Vue的特点

  • 采用组件化模式,提高代码复用率、且让代码更好维护。
  • 声明式编码,让编码人员无需直接操作Dom,提高开发效率。
  • 使用虚拟Dom+优秀的Diff算法,尽量复用Dom节点。

2.入门案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="../js/vue3.js"></script>
</head>
<body>
    <div id="counter">
        <h1> counter:{{ num }}</h1>
    </div>

    <script>
        // const Counter={
        //     data(){
        //         return{
        //             num:0
        //         }
        //     }
        // }

        const Counter={
            data:function(){
                return {
                    num:0
                }
            }
        }
        //创建一个应用,将配置的对象counter的内容渲染到选择器#counter的元素上
        let app = Vue.createApp(Counter).mount("#counter")
        console.log(app)
    </script>
</body>
</html>

可以用 app.num = 10修改值

image-20220315143856843

2.用 Vite来创建一个vue项目

使用 npm:(在控制台终端输入)

npm init vite-app vue3demo03  //vue3demo03 项目名称
cd vue3demo03
npm install
npm run dev    
最新创建步骤
# npm 6.x
$ npm init vite@latest <project-name> --template vue

# npm 7+,需要加上额外的双短横线
$ npm init vite@latest <project-name> -- --template vue

$ cd <project-name>
$ npm install
$ npm run dev

创建好后生成:

image-20220315192810891

3.Vue声明式语法与数据双向绑定(v-model)

App.vue

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <!-- <HelloWorld msg="Hello Vue 3.0 + Vite" /> -->
  <h2 @click="changeMsg"> {{msg}}</h2>
  <!-- v-model来进行绑定 -->
  <input type="text" v-model="msg"  />  
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

//命令式
//document.querySelector("h1").innerHTML="helloworld"

//声明式
export default {
  name: 'App',
  // components: {
  //   HelloWorld
  // }
  data(){
    return{
      msg:"helloword"
    }
  },
  methods:{
    changeMsg(){
    this.msg = "jihu,真帅"
    }
  }

}
</script>

运行结果:

改变输入框的值,上面的值就会改变,这就是双向绑定

image-20220315193113497

单击后,会改变值

image-20220315193219008

4.模板语法常用指令

插值

1.文本 (v-once指令)

数据绑定最常见的形式就是使用“Mustache” (双大括号) 语法的文本插值:

<span>Message: {{ msg }}</span>

Mustache 标签将会被替代为对应组件实例中 msg property 的值。无论何时,绑定的组件实例上 msgproperty 发生了改变,插值处的内容都会更新。

通过使用 v-once 指令,你也能执行一次性地插值,当数据改变时,插值处的内容不会更新。但请留心这会影响到该节点上的其它数据绑定:

<span v-once>这个将不会改变: {{ msg }}</span>
<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <!--双括号语法 Mustache -->
  <h2 >{{msg}}</h2>
  <!-- v-once指令,使得内容只渲染一次 -->
  <h2 @click="changeMsg" v-once> {{msg}}</h2>
</template>
<script>
import HelloWorld from './components/HelloWorld.vue'

//声明式
export default {
  name: 'App',
  data(){
    return{
      msg:"helloword"
    }
  },
  methods:{
    changeMsg(){
    this.msg = "jihu,真帅"
    }
  }

}
</script>

2.原始 HTML Attribute (v-html指令 、v-bind指令)

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <!-- <HelloWorld msg="Hello Vue 3.0 + Vite" /> -->
  <!--双括号语法 Mustache -->
  <h2 >{{msg}}</h2>
  <!-- v-once指令,使得内容只渲染一次 -->
  <h2 @click="changeMsg" v-once> {{msg}}</h2>

  <!-- v-html指令,使得内容插入html的代码 -->
<div>{{content}}</div>
<div v-html="content"></div>

<!-- v-bind指令,绑定属性的内容 -->
<div :id="id" :class="id"></div>
<div v-bind:id="id" v-bind:class="id"></div>

</template>
<script>
import HelloWorld from './components/HelloWorld.vue'
//声明式
export default {
  name: 'App',
  data(){
    return{
      msg:"helloword",
      content:"<h1>标题1</h1><h2 style='color:red'>标题2</h2>",
      id:"d1"
    }
  },
  methods:{
    changeMsg(){
    this.msg = "jihu,真帅",
    this.id= "d2"

    }
  }

}
</script>

<style >
  #d1{
    width: 100px;
    height: 100px;
    background: red;
  }
  #d2{
    width: 100px;
    height: 100px;
    background: green;
  }
</style>

展示结果:

image-20220315211319613

点击helloword后:

image-20220315211329207

3.使用 JavaScript 表达式

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <h2 >{{msg}}</h2>
  <!-- javascript表达式可以在模板语法里使用 -->
<h1>{{msg.split('')}}</h1>
<h1> {{ msg.split('').reverse() }}</h1>
<h1>{{msg.split('').reverse().join('')}}</h1>
<div v-bind:id="msg.split('').reverse().join('')" v-bind:class="id"></div>
<div>{{color=='绿色'?'开心':'难过'}}</div>

<div v-html="content" ></div>
<div :id="color1">{{msg}}</div>

</template>

<script>  
//声明式
export default {
  name: 'App',
  data(){
    return{
      msg:"helloword",
      color:'绿色',
      color1:'color',
      content:"<h1 style='color:red'>红黑树</h1>"
    }
  }

}
</script>

<style >
#color{
color: orange;
}
</style>

展示结果:

image-20220315211107510

动态指令

<template>
  <!-- 动态指令  -->
<div v-bind:[attributeName]="d1"></div>
<button @click="changeName">点击 切换颜色</button>
<button @[eventName]="changeName">点击切换颜色</button>

</template>

<script>  
//声明式
export default {
  name: 'App',
  data(){
    return{
      attributeName:'class',
      d1:'color',
      eventName:'click'
    }
  },
 methods:{
   changeName:function(){
     this.attributeName='id'
   }
  
 }

}
</script>

<style >
#color{
  width: 100px;
  height:100px;
  background: yellow;
}
.color{
 width: 100px;
  height:100px;
  background: blue;
}
</style>

5.计算属性和监听器

1.计算属性

<template>
  <!-- 计算属性  -->
<div  class="d1">{{msg.split('').reverse().join('')}}</div>
<div  class="d1">{{reverseMsg}}</div>

</template>

<script>  
//声明式
export default {
  name: 'App',
  data(){
    return{
      msg:'helloworld'
      
    }
  },
  computed:{
    reverseMsg:function(){
     return  this.msg.split('').reverse().join('')
    }
  }
 
 }
}
</script>

<style >
.d1{
 width: 100px;
  height:100px;
  background: blue;
}
</style>

展示结果:

image-20220315210943247

2.监听器 (监听数据的变化)

<template>
  <!-- 计算属性  -->
<div  class="d1">{{msg.split('').reverse().join('')}}</div>
<div  class="d1">{{reverseMsg}}</div>

<!-- 监听 -->
<input type="text" v-model="msg" />
<h1>{{msg}}</h1>

</template>

<script>  
//声明式
export default {
  name: 'App',
  data(){
    return{
      msg:'helloworld'
    }
  },
  computed:{
    reverseMsg:function(){
     return  this.msg.split('').reverse().join('')
    }
  },
  watch:{
    //监听值的变化
    msg:function(newValue,oldValue){
      console.log('newValue',newValue)
      console.log('oldValue',oldValue)
      if(newValue.length<10){
        alert("输入的值太少了!")
      }

    }
  }
  

}
</script>

<style >
#id{
  width: 100px;
  height:100px;
  background: yellow;
}
.d1{
 width: 100px;
  height:100px;
  background: blue;
}
</style>

展示结果

image-20220315210922100

6.Class与Style绑定

1.Class类名的多种操作方式

<template>
  <!-- 类class  -->
  <!-- 第一种写法,放置字符串 -->
<h1 :class="msg">hello</h1>
<!-- 第二种写法,放置对象 -->
<h1 :class="{active:isActive}" >hello2</h1>
<button @click="tochangeActive">切换Active</button>
<!-- 第三种写法, 放置数组 -->
<h1 :class="attr"> hello3</h1>
<!-- 第四种写法, 数组和对象的结合 -->
<h1 :class="['abc',{active:true}]">hello4</h1>
<h1 :class="[classname,{active:isActive}]">hello5</h1>

</template>

<script>  
//声明式
export default {
  name: 'App',
  data(){
    return{
      msg:'helloworld',
      isActive:true,
      attr:['swiper','active'],
      classname:'abc'
    }
  },
methods:{
  tochangeActive:function(){
    this.isActive = !this.isActive,
    this.attr.pop(), //pop() 用来删除attr:['swiper','active']中的值,一次删一个,从后往前删
    this.classname='cba'
  }
}  
}
</script>

<style >
.active{
  background: blue;
}
</style>

输出结果:

image-20220315220223852

2.Style样式的多种操作方式

<template>
  <!-- style  -->
  <!-- 第一种写法,放置字符串 -->
<h1 :style="msg">hello</h1>
<!-- 第二种写法,放置对象 -->
<h1 :style="{background:'purple'}" >hello2</h1>
<button @click="tochangeActive">切换Active</button>
<!-- 第三种写法, 放置数组 -->
<h1 :style="styleObj"> hello3</h1>
<!-- 第四种写法, 数组和对象的结合 -->
<h1 :style="[styleObj,{width:'500px'}]">hello4</h1>

</template>
<script>  
//声明式
export default {
  name: 'App',
  data(){
    return{
      msg:"background:yellow;",
      isActive:true,
      styleObj:{
        //如果遇到需要多个单词组成的样式,可以使用引号   例如:'background-color':'pink'
        //也可以使用驼峰命名法  例如: backgroundColor:'pink',
       
        background:'pink',
        border:'1px solid orange',
        boxSizing:"border-box"
      }
    }
  },
methods:{
  tochangeActive:function(){
    this.styleObj.backgroundColor='skyBlue'
   
  }
}  
}
</script>
<style >
.active{
  background: blue;
}
</style>

展示效果

image-20220315222322146

点击后

image-20220315222342874

7.条件渲染 v-if 与v-show

<template>
<h1 v-if="user=='超级vip'" >欢迎金主爸爸</h1>
<h1 v-else-if="user=='vip'">欢迎会员登录</h1>
<h1 v-else>充值会让你更强大!</h1>
<button @click="changhestatus">vip过期</button>

<!-- 设置1个内容切换显示 -->
<h1 v-show="isShow">切换显示内容</h1>
<button @click="toggleShow"> 切换</button>

</template>
<script>  
//声明式
export default {
  name: 'App',
  data(){
    return{
      user:'超级vip',
      isShow:true
      }    
  },
methods:{
  changhestatus:function(){
    this.user='普通用户'
  },
  toggleShow:function(){
    this.isShow  = !this.isShow
  }
}
}

展示结果:

image-20220316093233634

点击按钮后:

image-20220316093304658

总结:v-if vs v-show

v-if 是“真正”的条件渲染,因为它会确保在切换过程中,条件块内的事件监听器和子组件适当地被销毁和重建。

v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。

相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。

一般来说v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。

8.列表渲染 v-for

<template>
<div>
  <ol>
    <!-- item是里面一行一行的字符串 , i是它的索引值 -->
    <!-- :key="i" 相当于给每个班级做上标号  不写也行 -->
    <li v-for="(item,i) in news" :key="i">{{item}}-->{{i}}</li>
  </ol>

  <ol>
    <li v-for="(item,i) in news1"  :key="i">{{ item.title }}--{{item.tag}}--{{item.num}}-->{{i}}</li>
  </ol>
<!-- item 是值,i相当于key -->
  <ol>
    <li v-for="(item,i) in jihu"  :key="i">{{item}}--{{i}}</li>
  </ol>
  <!-- of 和in的效果一样 -->
  <ol>
    <li v-for="(item,i) of jihu"  :key="i">{{item}}--{{i}}</li>
  </ol>

</div>

</template>

<script>  
//声明式
export default {
  name: 'App',
  data(){
    return{
     news:[
       '2022值得期待的生活新变化',
       '昨日新增本土“1860+1194”',
       '吉林省15小时内增本土“1139+370”',
       '乌总统:不入北约是必须承认的事实'
     ],
     news1:[
       {
         title:'2022值得期待的生活新变化',
         tag:"沸",
         num:"450万"
       },
       {
         title:'昨日新增本土“1860+1194”',
         tag:"新",
         num:"110万"
       },
       {
         title:'吉林省15小时内增本土“1139+370”',
         tag:"热",
         num:"550万"
       }
     ],
     jihu:{
       name:'jihu',
       age:27,
       type:'sport'
     }
    }    
  }
}
</script> 

展示结果:

image-20220316100551922

9.事件处理

我们可以使用 v-on 指令 (通常缩写为 @符号) 来监听 DOM 事件,并在触发事件时执行一些 JavaScript。用法为 v-on:click="methodName" 或使用快捷方式 @click="methodName"

1.事件与参数和事件修饰符

<template>
<div>
  <!-- 绑定事件,不需要参数 -->
 <h1 @click="changenumcount">{{num}}</h1>
 <!-- 绑定事件,直接处理表达式 -->
<h1 @click="num+=2">{{num}}</h1>
<!-- 绑定事件,传递参数 -->
<h1 @click="addNumEvent(10)">{{num}}</h1>
<!-- 绑定事件传递事件对象和参数 -->
<h1 @click="addNumEvent1(20,$event)">{{num}}</h1>
<!-- v-on是全称指令  ,@是缩写的指令 -->
<h1 v-on:click="addNumEvent1(20,$event)">{{num}}</h1>
<!-- 一个事件绑定多个处理函数 -->
<h1 :style="{background:color}" @click="addNumEvent1(20,$event),changeColor($event)">{{num}}</h1>

<!-- 事件的修饰符 -->
<!-- 
  常用的事件修饰:
   阻止事件冒泡.stop
   阻止默认事件.prevent
   事件只会触发一次.once
 -->
<h1 :style="{background:color}" @click.once="addNumEvent1(20,$event),changeColor($event)">{{num}}</h1>
<!-- 
  按键修饰符 
     enter/tab/delete/esc/space/up/down/left/right
  系统修饰符:
     .ctrl/.alt/.shift/.meta
   鼠标按键的修饰符
    .left/.right/.middle  
 -->
<input type="text" @keydown.enter="searchEvent" />

</div>

</template>

<script>  
//声明式
export default {
  name: 'App',
  data(){
    return{
      num:0,
     color:'red'
    }    
  },
  methods:{
    changenumcount:function(){
      this.num += 2;  
      //this.num ++;
    },
    addNumEvent:function(number){
      console.log(number);
      this.num += number; 
    },
    addNumEvent1:function(number,event){
      console.log(event);
      this.num += number; 
    },
    changeColor:function(){
      this.color='purple';
    },
    searchEvent:function(){
      console.log("执行了回车的搜索事件")
    }

  }

}
</script> 

展示结果

image-20220316105015199

点击后

image-20220316105037834

10.表单的输入绑定

基础用法

你可以用 v-model 指令在表单 <input><textarea><select> 元素上创建双向数据绑定。它会根据控件类型自动选取正确的方法来更新元素。尽管有些神奇,但 v-model 本质上不过是语法糖。它负责监听用户的输入事件来更新数据,并在某种极端场景下进行一些特殊处理。

1.表单的数据双向绑定 v-model与修饰符

<template>
<div>

<input v-model="searchKey"   type="text" @keydown.enter="searchEvent" />
<h1>{{searchKey}}</h1>
<textarea v-model="lineText" name="textarea" id="" cols="30" rows="10"></textarea>
 <h1>{{lineText}}</h1>
 <!-- 表单获取的是是否选中内容  value值到时候会提交给后台-->
 <input type="checkbox" name="like"  v-model="checked"  value="123">[true,false]
  <h1>{{checked}}</h1>
<!--表单获取的是是否选中内容  -->
 <input type="checkbox" name="like"  v-model="checked1"  true-value="喜欢" false-value="不喜欢"> [喜欢,不喜欢]
  <h1>{{checked1}}</h1>

 <!-- 复选框多个值的情况 -->
  <input type="checkbox" name="likes"  v-model="fruits"  value="苹果">苹果
 <input type="checkbox" name="likes"  v-model="fruits"  value="雪梨">雪梨
 <input type="checkbox" name="likes"  v-model="fruits"  value="香蕉">香蕉
<h1>{{fruits}}</h1>
<!-- 单选框 -->
<input type="radio" name="sex" v-model="picked" value="man">man
<input type="radio" name="sex" v-model="picked" value="woman">woman
<h1>{{picked}}</h1>
<!-- 选项框 -->
<select name="city" v-model="city" >
  <option value="广州">广州</option>
  <option value="北京">北京</option>
  <option value="上海">上海</option>
  <option value="深圳">深圳</option>
</select>
<h1>{{city}}</h1>

<!-- 选项框  多选-->
<select name="city" v-model="cities" multiple>
  <option value="广州">广州</option>
  <option value="北京">北京</option>
  <option value="上海">上海</option>
  <option value="深圳">深圳</option>
</select>
<h1>{{cities}}</h1>

<!-- 修饰符 -->
<!-- .lazy/input变为change时间改变值 (当改变输入框的值时,searchkey的值不会自动跟着变化,只有回车 或点击外部才会改变)-->
<input v-model.lazy="searchKey"   type="text" @keydown.enter="searchEvent" />
<h1>{{searchKey}}</h1>
<!-- number修饰符 转为数字  -->
<input v-model.lazy.number="searchKey"   type="text" @keydown.enter="searchEvent" />
<h1>{{searchKey}}</h1>
<!-- trim修饰符 去掉空格  -->
<input v-model.trim="searchKey"   type="text" @keydown.enter="searchEvent" />
<h1>{{searchKey}}</h1>

</div>

</template>

<script>  
//声明式
export default {
  name: 'App',
  data(){
    return{
     searchKey:'百度一下',
     lineText:"",
     checked:false,
     checked1:"",
     fruits:[],
     picked:"",
     city:"",
     cities:[]
    }    
  },
  methods:{
    searchEvent:function(){
      console.log("执行了回车的搜索事件"),
      console.log(this.searchKey)
    }

  }

}
</script> 

展示结果:

image-20220316113535572

image-20220316113557997

11.组件

1.组件与父组件传递数据给子组件方式props

<template>
<div>
<Header></Header>
<Main></Main>
<Main></Main>
<Footer></Footer>
<!-- 通过props传递子组件数据 -->
<News :content="newsContent"></News>
<!-- <News :content="newsContent"  /> -->

</div>

</template>
<script>  
//声明式
import Header from './components/Header.vue'
import Main from './components/Main.vue'
import Footer from './components/Footer.vue' 
import News from './components/News.vue'
export default {
  name: 'App',
  data(){
    return{
     newsContent:'振兴中华1'
    }    
  },
  methods:{
    searchEvent:function(){
      console.log("执行了回车的搜索事件"),
      console.log(this.searchKey)
    }
  },
  components:{
    Header, Main,Footer,News
  }
}
</script> 
<!-- Header.vue -->
<template>
    <div>
        <h1>这是头部组件</h1>
    </div>
</template>
<!--Footer.vue-->
<template>
    <div>
        <h1>这是Footer组件</h1>
    </div>
</template>
<!-- Main.vue -->
<template>
    <div>
        <h1> {{msg}} 这是Main组件</h1>
    </div>
</template>

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

<!--News.vue-->
<template>
    <div>
        <h1>新闻内容是:{{content}}</h1>
    </div>
</template>

<script>
export default {
     props:['content']

}
</script>

2.通过自定义事件将子组件数据传递给父组件

<!-- App.vue -->
<template>
<div>
<!-- 通过props传递子组件数据 -->
<News :content="newsContent" :msg1="msg"></News>
<!-- <News :content="newsContent"  /> -->

<!-- 子组件数据传递给父组件,自定义事件 -->
<Login @sendParentMsg="getChildMsg"></Login>
<h1>从子组件获取到的值: {{msg}}</h1>

</div>
</template>

<script>  
//声明式
import News from './components/News.vue'
import Login from './components/Login.vue'
export default {
  name: 'App',
  data(){
    return{
     newsContent:'振兴中华1',
     msg:""
    }    
  },
  methods:{
    getChildMsg(value){
      console.log(value);
      this.msg = value;
    }
  },
  components:{
    News,Login
  }
}
</script> 
<!-- Login.vue -->
<template>
    <div>
        <input type="text" v-model="username">
        <button @click="sendMsg">将数组提交给父组件</button>
    </div>
</template>
<script>
export default {
    data(){
        return{
            username:""
        }
    },
    methods:{
        sendMsg:function(){
            //触发自定义事件, 语法: $emit(事件名称,发送的事件的参数)
            this.$emit('sendParentMsg',this.username)
        }
    }
}
</script>

<!-- News.vue -->
<template>
    <div>
        <h1>新闻内容是:{{content}}</h1>
        <h1>父组件获取到的数据,传递给子组件: {{msg1}}</h1>
    </div>
</template>
<script>
export default {
     props:['content','msg1']
}
</script>

12.vue3声明周期函数

<script setup>
// This starter template is using Vue 3 <script setup> SFCs
// Check out https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup
import HelloWorld from './components/HelloWorld.vue'
</script>

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <!-- <HelloWorld msg="Hello Vue 3 + Vite" /> -->
  <h1 >{{msg}}</h1>
  <button @click="msg='陈陈脸皮真厚! '"> 点击修改msg值</button>
  
</template>

<script>
export default {
  data(){
    return{
      msg:'陈陈真帅!'
    }
  },
  components:{
    HelloWorld
  },
  beforeCreate(){
    console.log("beforeCreate: 初始化数据之前")
  },
 created(){
   console.log("created: 数据初始化之后")
 },
 beforeMount(){
   console.log("beforeMount: 挂载渲染之前")
 },
 mounted(){
   console.log("mounted: 挂载渲染之后")
 },
 beforeUpdate(){
   console.log("beforeUpdate :更新之前")
 },
 updated(){
   console.log("Updated :更新之后")
 },
 beforeUnmount(){
   console.log("beforeUnmount: 销毁之前")
 },
 unmounted(){
   console.log("unmounted: 销毁之后")
 }

}
</script>

展示结果:

image-20220316155847310

点击后

image-20220316155918475

13.vue3合成API ( setup() )

1.vue3合成API初体验 --ref

<template>
 <div>
<h1 @click="changeEvent">计数:  {{count}}</h1>
<h1 @click="changeNum">计数:  {{num}}</h1>
</div>
</template>

<script>
import {ref} from 'vue'
export default {
  name: 'App',
  data(){
    console.log('data')
    return{
      count:0
    }
  },
  methods:{
    changeEvent:function(){
      this.count++;
    }
  },
    //setup细节问题
    //setup是在beforeCreate生命周期回调之前就执行了,而且就执行一次,此时组件对象还没有创建,这时就不能使用this,this为undefined,不能通过this来访问data/computed/methods/props
    //其实所有的composition API相关回调函数中也都不可以
    
    //setup中的返回值是一个对象,内部的属性和方法是给html模板使用的
    //setup中的对象内部的属性和data函数中的return对象的属性都可以在html模板中使用
    //setup中的对象中的属性和data函数中的对象中的属性会合并为组件对象的属性
    //setup中的对象中的方法和methods对象中的方法会合并为组件对象的方法
    //vue3中尽量不要混合使用data和setup及methods和setup
    //setup不能是一个async函数:因为返回值不再是return的对象,而是promise,模板看不到return对象中的属性数据
    
  setup(){
     console.log('setup')
    const num = ref(0)   //ref定义一个数据的响应式
    function changeNum(){
      num.value += 10
    }
    return {num,changeNum}
  },
    //数据初始化的生命周期回调
  beforeCreate(){
    console.log("beforeCreate: 初始化数据之前")
  },
 created(){
   console.log("created: 数据初始化之后")
 },
 beforeMount(){
   console.log("beforeMount: 挂载渲染之前")
 },
    //界面渲染完毕
 mounted(){
   console.log("mounted: 挂载渲染之后")
 }

}
</script>

展示结果

image-20220316163453566

2.vue3合成API详解 --reactive

<template>
 <div>
<h1 @click="changeEvent">计数:  {{count}}</h1>
<h1 @click="changeNum">计数:  {{num}}</h1>

<h1>用户名: {{user.username}}</h1>
<h1>特点: {{user.type}}</h1>

<h1>用户名: {{username}}</h1>
<h1>特点: {{type}}</h1>
<h1 @click="changeType">特点: {{type}}</h1>

<h1>特点 翻转: {{reverseType}}</h1>

</div>
</template>

<script>
import {ref,reactive,toRefs,computed,watchEffect,watch} from 'vue'
export default {
  name: 'App',
  data(){
    //console.log('data')
    return{
      count:0
    }
  },
  methods:{
    changeEvent:function(){
      this.count++;
    }
  },
  setup(){
   //  console.log('setup')
    const num = ref(0)  //ref定义一个数据的响应式
       //reactive 作用: 定义多个数据的响应式
    const user= reactive({
      username:"老陈",
      age:27,
      type:'sport',
      reverseType:computed(()=>{
        return user.type.split('').reverse().join('');
      })
    })
    function changeNum(){
      num.value += 10
    }
      //vue2中的写法
    function changeType(){
      user.type = "超级帅!"
    } 
      //vue3中的写法
    const  changeType = ()=>{
        user.type="非常帅!!!"
    }
    watchEffect(()=>{
        console.log(user.type)
        console.log("当user Type改变时,会触发此函数执行")
    })
    //单独监听
    watch(num,(newNum,preNum)=>{
        console.log("newNum:"+newNum,"preNum:"+preNum)
        console.log("当num改变时,会触发此函数执行")
    })
  //多个 监听
    watch([num,user],(newNum,preNum)=>{
        console.log("newNum:"+newNum,"preNum:"+preNum)
        console.log("当num改变时,会触发此函数执行")
    })

    // ...toRefs(user) :是为了调用username时省去user.的
    return {num,changeNum,user,...toRefs(user),changeType}
  }

}
</script>

展示结果:

image-20220316171204294

点击后

image-20220316171220907

3.setup()中使用生命周期函数

<!--App.vue-->
<template>
 <div>
   <!-- <h1>用户名:{{username}}</h1> -->
<User :username1="username"  :age="age"  msg2="小米"  />

</div>
</template>

<script>
import {reactive,toRefs} from 'vue'
import User from './components/User.vue'
export default {
  name: 'App',
  data(){
    return{
      
    }
  },
  components:{
    User
  },
  setup(){
     const user= reactive({
      username:"老陈",
      age:27,
      type:'sport',
     
    })

    return {user,...toRefs(user)}
  }
 
}
</script>

<!--User.vue-->
<template>
    <div>
        <h1>username:{{username1}}</h1>
        <h1>age:{{age}}</h1>
        <h1>description:{{description}}</h1>
    </div>
</template>

<script>
import {ref,onBeforeMount,onMounted,onBeforeUpdate,onUpdated,onBeforeUnmount,onUnmounted} from 'vue'
export default {
    setup(props,content){
        //props参数,是一个对象,里面有父级组件向子级组件传递的数据,并且是在子级组件中使用props接收到的所有的属性 ,  包含props配置声明且传入了的所有属性的对象
        //content参数是一个对象,里面有attrs对象(后去当前组件标签上的所有的属性的对象,但是该属性是在props中没有声明接收的所有的尚需要的对象),emit方法(分发事件的),slots对象(插槽)
        //attrs:包含没有在props配置中声明的属性的对象,相当于 this.$attrs
        //slots:包含所有掺入的插槽内容的对象,相当于this.$slots
        //emit:用来分发自定义事件的函数,相当于this.$emit
        //可以写成 setup(props,{attrs,slots,emit})
        console.log(props)       
        console.log(content)
        console.log(content.attrs)
        console.log(content.emit)
        console.log(content.attes.msg2)
        
        const description = ref(props.username1+"年龄是"+props.age)

        onBeforeMount(()=>{
            console.log('onBeforeMount')
        })
         onBeforeMount(()=>{
            console.log('onBeforeMount')
        })

        return {description}
    },
    props:['username1','age']   
}
</script>

展示结果:

image-20220316174513779

4.reactive和ref的细节问题

<template>
  <div class="about">
    <h1>reactive和ref的细节问题</h1>
    <h1>m1:{{m1}}</h1>
    <h1>m2:{{m2}}</h1>
    <h1>m3:{{m3}}</h1>
    <button @click="update">更新数据</button>
  </div>
</template>

<script>
import {ref,reactive} from 'vue'

export default {

  //是vue3的 composition API中2个最重要的响应式API (reactive和ref)
  //ref用来处理基本类型数据,reactive用来处理对象(递归深度响应式)
  //如果用ref对象/数组,内部会自动将对象/数组转换为reactive的代理对象
  //ref内部:通过给value属性添加getter/setter来实现对数据的劫持
  //reactive内部:通过使用proxy来实现对对象内部所有数据的劫持,并通过reflect操作对象内部数据
  //ref的数据操作:在js中要 .value,在模板中不需要(内部解析模板时会自动添加 .value)
  
  setup(props,content) {
    console.log(props);
    console.log(content);

     const m1 = ref('小明')
     const m2 = reactive({
       name:"liming",
       user:{
         name:'张三',
         age:20
       }
     })
     //ref的方式也可以传入对象
      const m3 = ref({
        name:"liming",
       user:{
         name:'张三',
         age:20
       }
     })

     function update(){
       //ref中如果放入是一个对象,那么是经过了reactive的处理, 形成一个Proxy类型的对象
       m1.value += "===" 
       console.log(m1);
       m2.user.name="lisi"
       m3.value.user.age += "==="
       console.log(m3);
     }

    return{m1,m2,m3,update}

  }

}
</script>

image-20220331195443910

14.Provive和inject

<!--App.vue-->

<template>
 <div>
	<Student />
</div>
</template>

<script>
import {reactive,toRefs,provide} from 'vue'
import Student from './components/Student.vue' 
export default {
  name: 'App',
  components:{
    Student
  },
  setup(){
      
    const student=reactive({
      name:"小红",
      classname:'三年级5班'
    })
    provide('student',student)

  }
  
}
</script>

<!--Student.vue-->
<template>
    <div>
        <h1>学生</h1>
        <h1>name:{{name}}</h1>
        <h1>classname:{{classname}}</h1>
    </div>
</template>

<script>
import {ref,inject} from 'vue'
export default {
    setup(){
        const student=inject('student')
        return {...student}
    } 
}
</script>

展示结果

image-20220316180209204

15.路由

1.vue3路由的基本使用

<!--App.vue-->
<template>
  <div>
    <h1>Hello App!</h1>
  <p>
    <!-- use the router-link component for navigation. -->
    <!-- specify the link by passing the `to` prop. -->
    <!-- `<router-link>` will render an `<a>` tag with the correct `href` attribute -->
    <router-link to="/">Go to Home</router-link>
    <router-link to="/about">Go to About</router-link>
  </p>
  <!-- route outlet -->
  <!-- component matched by the route will render here -->
  <router-view></router-view>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  components: {
    HelloWorld
  }
}
</script>


<!--router/index.js-->
// 导入进来
// import VueRouter from 'vue-router'
import {createRouter,createWebHashHistory} from 'vue-router'

// 1. Define route components.
// These can be imported from other files
const Home = { template: '<div>Home</div>' }
const About = { template: '<div>About</div>' }

// 2. Define some routes
// Each route should map to a component.
// We'll talk about nested routes later.
const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
]

// 3. Create the router instance and pass the `routes` option
// You can pass in additional options here, but let's
// keep it simple for now.
const router = createRouter({
  // 4. Provide the history implementation to use. We are using the hash history for simplicity here.
  history: createWebHashHistory(),
  routes, // short for `routes: routes`
})

//导出路由
export default router
<!--main.js-->
import { createApp } from 'vue'
import router from '../router'
import App from './App.vue'
import './index.css'

const app = createApp(App)
//使用路由
app.use(router)
app.mount('#app')

2.动态路由和404NotFound

<!--App.vue-->
<template>
  <div>
    <!-- <h1>Hello App!</h1> -->
  
    <!-- use the router-link component for navigation. -->
    <!-- specify the link by passing the `to` prop. -->
    <!-- `<router-link>` will render an `<a>` tag with the correct `href` attribute -->
  <!-- <p>
    <router-link to="/">Go to Home</router-link>
    <router-link to="/about">Go to About</router-link>
  </p> -->
  <!-- route outlet -->
  <!-- component matched by the route will render here -->
  <router-view></router-view>
  </div>
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

export default {
  name: 'App',
  components: {
    HelloWorld
  }
}
</script>

<!--News.vue-->
<template>
    <div>
        <h1>新闻页 {{$route.params.id}}</h1>
        
    </div>
</template>
<script>
export default {
    mounted(){
        console.log(this.$route)
    }
}
</script>

<!--Home.vue-->
<template>
    <h1>这是首页</h1>
</template>

<!--NotFound.vue-->
<template>
    <h1>404,找不到页面</h1>
</template>
<!--router/index.js-->

// 导入进来
// import VueRouter from 'vue-router'
import {createRouter,createWebHashHistory} from 'vue-router'

import Home from '../src/components/Home.vue'
import News from '../src/components/News.vue'
import NotFound from '../src/components/NotFound.vue' 

// 1. Define route components.
// These can be imported from other files
//const Home = { template: '<div>Home</div>' }
const About = { template: '<div>About</div>' }

// 2. Define some routes
// Each route should map to a component.
// We'll talk about nested routes later.
const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
  {
      path:'/news/:id',
      component:News
  },
  {
      path:'/:path(.*)',
      component:NotFound
  }
]

// 3. Create the router instance and pass the `routes` option
// You can pass in additional options here, but let's
// keep it simple for now.
const router = createRouter({
  // 4. Provide the history implementation to use. We are using the hash history for simplicity here.
  history: createWebHashHistory(),
  routes, // short for `routes: routes`
})

//导出路由
export default router

3.路由正则与重复参数

/route/index.js

// 导入进来
// import VueRouter from 'vue-router'
import {createRouter,createWebHashHistory} from 'vue-router'

import Home from '../src/components/Home.vue'
import News from '../src/components/News.vue'
import NotFound from '../src/components/NotFound.vue' 
import Article from '../src/components/Article.vue' 
import Films from '../src/components/Films.vue' 

// 1. Define route components.
// These can be imported from other files
//const Home = { template: '<div>Home</div>' }
const About = { template: '<div>About</div>' }

// 2. Define some routes
// Each route should map to a component.
// We'll talk about nested routes later.
const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
  {
      path:'/news/:id',
      component:News
  },
  {
      path:'/:path(.*)',
      component:NotFound
  },
  {
      path:'/article/:id(\\d+)',
      component:Article
  },
  {
    // id+ 是至少会有1个参数  例: /films/111/555
    // id* 是可有可没有,也可以有任意多个  例:/films/ 或/films/111/555
    // id? 是有,或者没有  ,不可以重复   例:/films/  或/films/111
      path:'/films/:id',
      component:Films
  }
]

// 3. Create the router instance and pass the `routes` option
// You can pass in additional options here, but let's
// keep it simple for now.
const router = createRouter({
  // 4. Provide the history implementation to use. We are using the hash history for simplicity here.
  history: createWebHashHistory(),
  routes, // short for `routes: routes`
})

//导出路由
export default router

​ Films.vue

<template>
    <div>
        <h1>Films页 {{$route.params.id}}</h1>
        
    </div>
</template>
<script>
export default {
    mounted(){
        console.log(this.$route)
    }
}
</script>

Article.vue

<template>
    <div>
        <h1>Article页: {{$route.params.id}}</h1>
        
    </div>
</template>
<script>
export default {
    mounted(){
        console.log(this.$route)
    }
}
</script>

展示结果

image-20220316203024304

image-20220316203436922

4.路由嵌套

/route/index.js

// 导入进来
// import VueRouter from 'vue-router'
import {createRouter,createWebHashHistory, useRoute} from 'vue-router'

import Home from '../src/components/Home.vue'
import News from '../src/components/News.vue'
import NotFound from '../src/components/NotFound.vue' 
import Article from '../src/components/Article.vue' 
import Films from '../src/components/Films.vue' 
import User from '../src/components/User.vue' 
import Hengban from '../src/components/Hengban.vue' 
import Shuban from '../src/components/Shuban.vue' 

// 1. Define route components.
// These can be imported from other files
//const Home = { template: '<div>Home</div>' }
const About = { template: '<div>About</div>' }

// 2. Define some routes
// Each route should map to a component.
// We'll talk about nested routes later.
const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
  {
      path:'/news/:id',
      component:News
  },
  {
      path:'/:path(.*)',
      component:NotFound
  },
  {
      path:'/article/:id(\\d+)',
      component:Article
  },
  {
    // id+ 是至少会有1个参数  例: /films/111/555
    // id* 是可有可没有,也可以有任意多个  例:/films/ 或/films/111/555
    // id? 是有,或者没有  ,不可以重复   例:/films/  或/films/111
      path:'/films/:id+',
      component:Films
  },
  {
    // /user/:id  这样写的话 路径为 /user/11/hengban
    // /user  这样写的话 路径为 /user/hengban
    path:'/user/:id',
    component:User,
    children:[
      {
        path:'hengban',
        component:Hengban
      },
      {
        path:'shuban',
        component:Shuban
      }
    ]
  }
]

// 3. Create the router instance and pass the `routes` option
// You can pass in additional options here, but let's
// keep it simple for now.
const router = createRouter({
  // 4. Provide the history implementation to use. We are using the hash history for simplicity here.
  history: createWebHashHistory(),
  routes, // short for `routes: routes`
})

//导出路由
export default router

User.vue 、 Hengban.vue 、 Shuban.vue

<!--User.vue-->
<template>
    <div>
        <h1>{{$route.params.id}}:user页面</h1>

        <router-view></router-view>

    </div>
</template>

<!--Hengban.vue-->
<template>
    <h1>这是横版页面</h1>
</template>

<!--Shuban.vue-->
<template>
    <h1>这是竖版页面</h1>
</template>

5.使用js跳转页面

page.vue

<template>
    <dir>
        <h1>这是page页面,学习编程导航</h1>
        <button @click="goPage">跳转页面</button>
    </dir>
</template>
<script>
export default {
    methods:{
        goPage(){
        console.log("跳转到首页") 
       // this.$router.push("/")  //跳转到首页
      //  this.$router.push({path:'/news/111'})  //跳转到/news/111页面
        //携带参数跳转
       // this.$router.push({name:"news",params:{id:7788}})
       this.$router.push({path:"/",query:{search:'特朗普'}})

        } 
    }
}
</script>

index.js

// 导入进来
// import VueRouter from 'vue-router'
import {createRouter,createWebHashHistory, useRoute} from 'vue-router'

import Home from '../src/components/Home.vue'
import News from '../src/components/News.vue'
import NotFound from '../src/components/NotFound.vue' 
import Article from '../src/components/Article.vue' 
import Films from '../src/components/Films.vue' 
import User from '../src/components/User.vue' 
import Hengban from '../src/components/Hengban.vue' 
import Shuban from '../src/components/Shuban.vue' 
import Page from '../src/components/Page.vue' 

// 1. Define route components.
// These can be imported from other files
//const Home = { template: '<div>Home</div>' }
const About = { template: '<div>About</div>' }

// 2. Define some routes
// Each route should map to a component.
// We'll talk about nested routes later.
const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About },
  {
      name:"news",
      path:'/news/:id',
      component:News
  },
  {
      path:'/:path(.*)',
      component:NotFound
  } ,
  {
    path:'/page',
    component:Page
  }
]

// 3. Create the router instance and pass the `routes` option
// You can pass in additional options here, but let's
// keep it simple for now.
const router = createRouter({
  // 4. Provide the history implementation to use. We are using the hash history for simplicity here.
  history: createWebHashHistory(),
  routes, // short for `routes: routes`
})

//导出路由
export default router

News.vue

<template>
    <div>
        <h1>新闻页 {{$route.params.id}}</h1>
        
    </div>
</template>
<script>
export default {
    mounted(){
        console.log(this.$route)
    }
}
</script>

展示结果:

image-20220316212931898

image-20220316212955893

6.命名路由与重定向和别名

1.命名视图

  <router-view name="ShopTop"></router-view>
  <router-view></router-view>
  <router-view name="ShopFooter"></router-view>
import ShopMain from '../src/components/ShopMain.vue' 
import ShopTop from '../src/components/ShopTop.vue' 
import ShopFooter from '../src/components/ShopFooter.vue' 

const routes = [ 
  {
    path:'/shop',
    components:{
      default:ShopMain,
      ShopTop:ShopTop,
      ShopFooter:ShopFooter
    }
  }
]

展示结果

image-20220316214610444

2.重定向

{
    path:'/mail',
    redirect:(to)=>{return {path:'/shop'}}
    // redirect:"/shop"
  }

3.取别名

{
    path:'/shop',
    alias:"/jihushop",
   //alias:["/q11","/222"],
    components:{
      default:ShopMain,
      ShopTop:ShopTop,
      ShopFooter:ShopFooter
    }
}    

image-20220316215229499

4.replace 使用

replace : 使覆盖原来的页面,让其不能往回退

page.vue

<template>
    <dir>
        <h1>这是page页面,学习编程导航</h1>
        <button @click="goPage">跳转页面</button>
        <button @click="replacePage">替换页面</button>
        <button @click="$router.go(1)">前进</button>  //前进
        <button @click="$router.go(-1)">后退</button>  //后退
    </dir>
</template>
<script>
export default {
    methods:{
        goPage(){
        console.log("跳转到首页") 
       // this.$router.push("/")  //跳转到首页
      //  this.$router.push({path:'/news/111'})  //跳转到/news/111页面
        //携带参数跳转
       this.$router.push({name:"news",params:{id:7788}})
      // this.$router.push({path:"/",query:{search:'特朗普'}})

        },
        replacePage(){
            this.$router.replace({name:"news",params:{id:7788}})
        }

    }
}
</script>

5.路由模式与路由守卫

路由守卫就是  和权限差不多  没有权限进不去该页面
{
    path:'/page',
    component:Page,
    beforeEnter:(to,from)=>{
      console.log('beforeEnter')
    }
  },
  router.beforeEach((to, from,next) => {
    // ...
    // explicitly return false to cancel the navigation
    console.log(to)
    next()
    //return false
  })

page.vue

<script>
export default {
    methods:{
        goPage(){
        console.log("跳转到首页") 
       // this.$router.push("/")  //跳转到首页
      //  this.$router.push({path:'/news/111'})  //跳转到/news/111页面
        //携带参数跳转
       this.$router.push({name:"news",params:{id:7788}})
      // this.$router.push({path:"/",query:{search:'特朗普'}})

        },
        replacePage(){
            this.$router.replace({name:"news",params:{id:7788}})
        }

    },
    beforeRouteEnter(){
        console.log('路由进入组件')
    },
     beforeRouteUpdate(){
        console.log('路由更新组件')
    },
     beforeRouteLeave(){
        console.log('路由离开组件')
    }
}
</script>

展示结果

image-20220316221656113

image-20220316221713520

16.vue3中如何设置状态管理

App.vue

<template>
  <img alt="Vue logo" src="./assets/logo.png" />
  <HelloWorld msg="Hello Vue 3.0 + Vite" />
</template>

<script>
import HelloWorld from './components/HelloWorld.vue'

import store from './store/index.js'

// import {reactive} from 'vue'

// const store={
//   state:reactive({
//     message:"helloworld"
//   }),
//   setMessage(value){
//     this.state.message = value;
//   }
// }

export default {
  name: 'App',
  components: {
    HelloWorld
  },
  provide:{
    store
  }
}
</script>

Helloworld.vue

<template>
<div>
  <h1>{{ store.state.message }}</h1>
  <button @click="store.setMessage('老陈真帅!')">count is: {{ count }}</button>
</div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data() {
    return {
      count: 0
    }
  },
  inject:['store']
}
</script>

store/index.js

import {reactive} from 'vue'

const store={
  state:reactive({
    message:"helloworld"
  }),
  setMessage(value){
    this.state.message = value;
  }
}

//导出默认值
export default store;

17.vue3中如何使用axios实现前后端交互

使用axios实现前后端交互时需要先安装axios:

​ npm install axios --save

App.vue

<template>
  <div>
    <h1>ajax请求</h1>
    <div v-for="(item,i) in store.state.duanziList" :key="i">
      <p>{{i}}{{item.text}}</p>
    </div>
  </div>
</template>

<script>
// import HelloWorld from './components/HelloWorld.vue'

import store from './store/index.js'
import axios from 'axios' 


export default {
  name: 'App',
  provide:{
    store
  },
  setup(){
    //方法一
    var api = "https://api.apiopen.top/getJoke?page=1&count=10&type=text"
    // fetch(api).then(res=>res.json()).then(result=>{
    //   store.setDzList(result.result)
    //   console.log(result)
    // })

//方法二:
    axios.get(api).then((result)=>{
      console.log(result)
      store.setDzList(result.data.result)
    })
    return{ store }
  }
}
</script>

components/HelloWorld.vue

<template>
<div>
  <h1>{{ store.state.message }}</h1>
  <button @click="store.setMessage('老陈真帅!')">count is: {{ count }}</button>
</div>
</template>

<script>
export default {
  name: 'HelloWorld',
  props: {
    msg: String
  },
  data() {
    return {
      count: 0
    }
  },
  inject:['store']
}
</script>

store/index.js

import {reactive} from 'vue'

const store={
  state:reactive({
    message:"helloworld",
    duanziList:[]
  }),
  setMessage(value){
    this.state.message = value;
  },
  setDzList(list){
    this.state.duanziList = list
  }
}

//导出默认值
export default store;

展示结果

image-20220317102759847

18.vite配置跨域请求

在项目的根目录下创建一个vite.config.js配置文件

vite.config.js

module.exports = {
    
   proxy:{
         '/api':{
                target:'https://pvp.qq.com/',
                changeOrigin:true,//是否允许跨域
                rewrite:path => path.replace(/^\/api/, '')
         } 
    }
    
}

App.vue

<template>
  <div>
    <h1>ajax请求</h1>
    <div v-for="(item,i) in store.state.duanziList" :key="i">
      <p>{{item.cname}}===>{{item.title}}</p>
    </div>
  </div>
</template>

<script>
// import HelloWorld from './components/HelloWorld.vue'

import store from './store/index.js'
import axios from 'axios' 


export default {
  name: 'App',
  provide:{
    store
  },
  setup(){

    var api = "/api/web201605/js/herolist.json"
    axios.get(api).then((result)=>{
      console.log(result)
      store.setDzList(result.data)
    })
    return{ store }
  }
}
</script>

store/index.js

import {reactive} from 'vue'

const store={
  state:reactive({
    message:"helloworld",
    duanziList:[]
  }),
  setMessage(value){
    this.state.message = value;
  },
  setDzList(list){
    this.state.duanziList = list
  }
}

//导出默认值
export default store;

展示结果

image-20220317102418408

image-20220317102438158

19.mockjs模拟获取数据

mockjs 官网:http://mockjs.com/

# 安装
npm install mockjs --save

// 使用 Mock
var Mock = require('mockjs')
var data = Mock.mock({
    // 属性 list 的值是一个数组,其中含有 1 到 10 个元素
    'list|1-10': [{
        // 属性 id 是一个自增数,起始值为 1,每次增 1
        'id|+1': 1
    }]
})

// 输出结果
console.log(JSON.stringify(data, null, 4))

例子

App.vue

<template>
  <div>
    <h1>ajax请求</h1>
    <div v-for="(item,i) in store.state.duanziList" :key="i">
      <p>{{item.cname}}===>{{item.title}}</p>
    </div>

    <h1>{{store.state.message}}</h1>
    
  </div>
</template>

<script>
// import HelloWorld from './components/HelloWorld.vue'

import store from './store/index.js'
import axios from 'axios' 


export default {
  name: 'App',
  provide:{
    store
  },
  setup(){
    let api = '/user/userinfo'
  //let api = '/user/userinfo?username=laoma$password=123456'

    axios.get(api).then((result)=>{
      console.log(result)
      store.setMessage(result.data.username+result.data.type)
    })

    axios.get('/account?username=laoma$password=123456').then((result)=>{
      console.log(result)
     
      })

    return{ store }
  }
}
</script>

/mock/index.js

//导入mock
import Mock from 'mockjs'


//设置一下模拟返回数据的时间
Mock.setup({
    timeout:'200-600'
})

Mock.mock(
    //请求的路径
    "/user/userinfo",
    'get',
    (req)=>{
        console.log(req)
        return{
            username:"老马",
            type:'帅!'
        }
    }
)

Mock.mock(
    //请求的路径
    /\/account.*/,  //正则匹配  .* :匹配 account后面所有的
    'get',
    (req)=>{
        console.log(req)
        return{
           info:"登录成功"
        }
    }

)

main.js

import { createApp } from 'vue'
import App from './App.vue'
import './index.css'
import './mock/index.js'  //要是与后端发送请求只需把这句话注释掉

createApp(App).mount('#app')

目录结果

image-20220317110810348

输出结果:

image-20220317110840984

20.vue脚手架cli的使用

安装 脚手架cli

npm install -g @vue/cli
//查看版本
 vue --version

安装时出现的问题

VSCode的终端输入vue --version报错:vue : 无法加载文件 D:\nodejs\node_global\vue.ps1,因为在此系统上禁止运行脚本。

image-20220317115006071

解决办法

(1)以管理员身份运行VSCode

(2)执行命令:get-ExecutionPolicy(取得shell的当前执行策略)

显示Restricted(表示状态是禁止的)

(3)执行命令:set-ExecutionPolicy RemoteSigned

(4)执行命令:get-ExecutionPolicy,显示RemoteSigned

image-20220317115040729

Vue CLI 创建项目

创建项目命令:

 vue create vueproject01
 
 #安装 element Ui
 npm i element-ui -S  #vue2.0版本
 npm install element-plus --save
  vue add element
  vue add element-plus  #vue3.0使用这个安装  element Ui 插件
  
  npm install echarts@4.9.0 --save  #安装echarts插件
  npm i echarts -S
  在main.js中引入
  import echarts from 'echarts'
  Vue.prototype.$echarts = echarts

第一步,创建项目结构,第一个是vue3,第二个是vue2,第三个是自定义,我们选择第三个自定义结构,回车。

image-20220317151804803

第二步,选择模块,上下选择,选中按空格,选好后按回车 。选择四个就可以了(linter 以后再选,效验用的)

image-20220317145908117

第三步:需要进行的一些配置

image-20220317152303904

第四步:等待创建好(此时必须网好才行)

image-20220317152023355

第五步:运行项目

image-20220317152117783

21.vuex状态管理的应用

HomeView.vue

<template>
  <div class="home">
    <h1>商品数量:{{$store.state.count}}</h1>
    <h1>商品价格:100</h1>
    <h1>商品总价: {{$store.getters.totalPrice}}</h1>
    <button @click="changeEvent">点击数量增加按钮</button>

  <h1>段子</h1>
  <p v-for="(item,i) in $store.state.dzList" :key="i">{{item.text}}</p>

  </div>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'

export default {
  name: 'HomeView',
  components: {
    HelloWorld
  },
  methods:{
    changeEvent:function(){
      //this.$store.commit('setCount');
      this.$store.commit('setCountNum',10);  //想要触发 setCountNum这个函数,必须用commit方式来执行
    }
  },
  mounted:function(){
    this.$store.dispatch('getDz')  //让其触发actions这个函数, 使getDz生效
  }
}
</script>

/store/index.js

import { createStore } from 'vuex'

export default createStore({
  //设置全局数据的地方
  state: {
    count:1,
    dzList:[]
  },
  getters: {
    totalPrice:function(state){
      return state.count*100
    }
  },
  //修改状态的方法 (同步的操作)
  mutations: {
    setCount:function(state){
      state.count++;
    },
    setCountNum:function(state,num){
      state.count+=num;
    },
    setDzList:function(state,arr){
      state.dzList =arr;
    }
  },
  //异步的操作 (比如 ajax)
  actions: {
    getDz:function(context){
      var api = "https://api.apiopen.top/getJoke?page=1&count=10&type=text"
      fetch(api).then(res=>res.json()).then(result=>{
        console.log(result);
        context.commit('setDzList',result.result);
      })
    }
  },
  modules: {
  }
})

展示效果:

image-20220317161058017

22.映射状态数据和方法(map)

此映射方法让其 不用写($store.state.count)这么长的名字了

HomeView.vue

<template>
  <div class="home">
    <h1>商品数量:{{$store.state.count}}</h1>
    <h1>商品数量:{{count}}</h1>
    <h1>商品数量:{{productCount}}</h1>
    <h1>商品价格:100</h1>
    <h1>商品总价: {{$store.getters.totalPrice}}</h1>
     <h1>商品总价: {{totalPrice}}</h1>
    <button @click="changeEvent">点击数量增加按钮</button>
     <button @click="setCountNum(5)">点击数量增加按钮</button>

  <h1>段子</h1>
  <p v-for="(item,i) in $store.state.dzList" :key="i">{{item.text}}</p>

  </div>
</template>

<script>
// @ is an alias to /src
import HelloWorld from '@/components/HelloWorld.vue'

import {mapState,mapGetters,mapMutations,mapActions} from 'vuex';

export default {
  name: 'HomeView',
  components: {
    HelloWorld
  },
  computed:{
    ...mapState(['count']),
    ...mapState({
      productCount:(state)=>state.count   //将state.count映射进来
    }),
    ...mapGetters(['totalPrice'])
  },
  methods:{
    changeEvent:function(){
      //this.$store.commit('setCount');
      this.$store.commit('setCountNum',10);  //想要触发 setCountNum这个函数,必须用commit方式来执行
    },  // 前面加... 是解构一下
    ...mapMutations(['setCountNum']),
    ...mapActions(['getDz'])

  },
  mounted:function(){
   // this.$store.dispatch('getDz')  //让其触发actions这个函数, 使getDz生效
   this.getDz()
  }
}
</script>

/store/index.js

import { createStore } from 'vuex'

export default createStore({
  //设置全局数据的地方
  state: {
    count:1,
    dzList:[]
  },
  getters: {
    totalPrice:function(state){
      return state.count*100
    }
  },
  //修改状态的方法 (同步的操作)
  mutations: {
    setCount:function(state){
      state.count++;
    },
    setCountNum:function(state,num){
      state.count+=num;
    },
    setDzList:function(state,arr){
      state.dzList =arr;
    }
  },
  //异步的操作 (比如 ajax)
  actions: {
    getDz:function(context){
      var api = "https://api.apiopen.top/getJoke?page=1&count=10&type=text"
      fetch(api).then(res=>res.json()).then(result=>{
        console.log(result);
        context.commit('setDzList',result.result);
      })
    }
  },
  modules: {
  }
})

展示效果

image-20220317163229858

23.模块化管理vuex(Module)

1.模块的局部状态

store/user.js

const user = {
    state:() =>({
        username:'老马',
        age:27
    }),
    mutations:{
        setUsername:function(state){
            state.username = '小陈'
        },
        setAge:function(state,value){
            state.age = value
        }
    },
    actions:{
        asyncSetAge:function(context){
            console.log(context)
            setTimeout(()=>{
                context.commit('setAge',50);
            },3000);
        }
    },
    getters:{
        description:function(state,getters,rootState){
            return state.username +'的年龄是'+ state.age + '岁'
        }
    }
}

export default user

/views/User.vue

<template>
    <div>
        <h1>用户名:{{$store.state.user.username}}</h1>
        <h1>年龄:{{$store.state.user.age}}</h1>
        <h1>描述:{{$store.getters.description}}</h1>
        <button @click="changeAge">异步修改年龄</button>
    </div>
</template>
<script>
export default {
    mounted(){
        console.log(this.$store)
    },
    methods:{
        changeAge:function(){
            this.$store.dispatch('asyncSetAge')
        }
    }
}
</script>

store/index.js

import { createStore } from 'vuex'
import user from './user'

export default createStore({
  //设置全局数据的地方
  state: {
    count:1,
    dzList:[]
  },
  getters: {
    totalPrice:function(state){
      return state.count*100
    }
  },
  //修改状态的方法 (同步的操作)
  mutations: {
    setCount:function(state){
      state.count++;
    },
    setCountNum:function(state,num){
      state.count+=num;
    },
    setDzList:function(state,arr){
      state.dzList =arr;
    }
  },
  //异步的操作 (比如 ajax)
  actions: {
    getDz:function(context){
      var api = "https://api.apiopen.top/getJoke?page=1&count=10&type=text"
      fetch(api).then(res=>res.json()).then(result=>{
        console.log(result);
        context.commit('setDzList',result.result);
      })
    }
  },
  modules: {
    user 
  }
})

router/index.js

import { createRouter, createWebHistory } from 'vue-router'
import HomeView from '../views/HomeView.vue'
import User from '../views/User.vue'

const routes = [
  {
    path: '/',
    name: 'home',
    component: HomeView
  },
  {
    path: '/about',
    name: 'about',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: () => import(/* webpackChunkName: "about" */ '../views/AboutView.vue')
  },
  {
    path: '/user',
    name: 'User',
    component: User
  }
]

const router = createRouter({
  history: createWebHistory(process.env.BASE_URL),
  routes
})

export default router

2.命名空间

默认情况下,模块内部的 action 和 mutation 仍然是注册在全局命名空间的——这样使得多个模块能够对同一个 action 或 mutation 作出响应。Getter 同样也默认注册在全局命名空间,但是目前这并非出于功能上的目的(仅仅是维持现状来避免非兼容性变更)。必须注意,不要在不同的、无命名空间的模块中定义两个相同的 getter 从而导致错误。

如果希望你的模块具有更高的封装度和复用性,你可以通过添加 namespaced: true 的方式使其成为带命名空间的模块。当模块被注册后,它的所有 getter、action 及 mutation 都会自动根据模块注册的路径调整命名。

​ User.vue

<template>
    <div>
        <h1>用户名:{{$store.state.user.username}}</h1>
        <h1>年龄:{{$store.state.user.age}}</h1>
        <h1>描述:{{$store.getters.description}}</h1>
        <button @click="changeAge">异步修改年龄</button>

        <!-- 命名空间的写法 -->
        <h1>用户名:{{$store.state.user1.username}}</h1>
        <h1>年龄:{{$store.state.user1.age}}</h1>
        <h1>描述:{{$store.getters['user1/description']}}</h1>
        <button @click="changeAge1">异步修改年龄</button>
        <!-- 辅助函数的写法 -->
        <h1>用户名:{{user1.username}}</h1>
        <h1>年龄:{{user1.age}}</h1>
        <h1>描述: {{description}} </h1>
        <button @click="asyncSetAge(100)">异步修改年龄值为100</button>

    </div>
</template>
<script>
import {mapState,mapGetters,mapMutations,mapActions} from 'vuex';

export default {
    computed:{
        ...mapState(['user1']),  //用user1把其解构出来
        ...mapGetters('user1',['description'])
    },
    mounted(){
        console.log(this.$store)
    },
    methods:{
        changeAge:function(){
            this.$store.dispatch('asyncSetAge')
        },
        changeAge1:function(){
            this.$store.dispatch('user1/asyncSetAge')
        },
        ...mapActions('user1',['asyncSetAge'])
    }
}
</script>

store/user1.js

const user = {
    namespaced:true,
    state:() =>({
        username:'隔壁老王',
        age:46
    }),
    mutations:{
        setUsername:function(state){
            state.username = '小王'
        },
        setAge:function(state,value){
            state.age = value
        }
    },
    actions:{
        asyncSetAge:function(context,value){
            console.log(context)
            setTimeout(()=>{
                context.commit('setAge',value);
            },1000);
        }
    },
    getters:{
        description:function(state,getters,rootState){
            return state.username +'的年龄是'+ state.age + '岁'
        }
    }
}

export default user

展示效果:

image-20220317173858830

24.element-ui axios Echarts插件安装

 #安装 element Ui
 npm i element-ui -S  #vue2.0版本
 npm install element-plus --save
  vue add element
  vue add element-plus  #vue3.0使用这个安装  element Ui 插件
  
  #安装echarts
  npm install echarts@4.9.0 --save  #安装echarts插件
  npm i echarts -S
  在main.js中引入
  import echarts from 'echarts'  #v4版本这样引用echarts
  Vue.prototype.$echarts = echarts
  import * as echarts from 'echarts' #v5版本这样引用echarts
  
  
  #安装axios
  	npm install axios  --save
  	
  	import axios from 'axios' 
  	
  	

image-20220328093329948

posted @ 2022-03-15 22:25  爲誰心殇  阅读(281)  评论(2编辑  收藏  举报
>