JavaScript 之 Vue3 入门到精通+网络商城案例一篇文章精通系列【WebStorm版】

JavaScript 之 Vue3 入门到精通(一篇文章精通系列)【WebStorm版】

项目源代码:https://download.csdn.net/download/qq_44757034/86440913

一、Vite创建Vue3 项目

npm init vite@latest my-vue-app -- --template vue

在这里插入图片描述


创建成功

在这里插入图片描述

在这里插入图片描述


用WebStorm打开项目

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


自动下载好对应的依赖

在这里插入图片描述


启动运行项目

在这里插入图片描述

 npm run dev

在这里插入图片描述


http://127.0.0.1:5173/

在这里插入图片描述


提示要安装插件

二、Vue3基本语法

1、定义全局变量

在这里插入图片描述

<template>
  <h1>{{msg}}</h1>
  <div>
    <a href="https://vitejs.dev" target="_blank">
      <img src="/vite.svg" class="logo" alt="Vite logo" />
    </a>
    <a href="https://vuejs.org/" target="_blank">
      <img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
    </a>
  </div>
  <HelloWorld msg="Vite + Vue" />
</template>
<script setup>
// This starter template is using Vue 3 <script setup> SFCs
// Check out https://vuejs.org/api/sfc-script-setup.html#script-setup
import HelloWorld from './components/HelloWorld.vue'
let msg  = "itbluebox"

</script>
<style scoped>
.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
}
.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
  filter: drop-shadow(0 0 2em #42b883aa);
}
</style>

访问:http://127.0.0.1:5173/

在这里插入图片描述

2、定义函数

翻转字符串函数

在这里插入图片描述

<template>
  <h1>{{msg}}</h1>
  <h1>{{reMsg(msg)}}</h1>
  <div>
    <a href="https://vitejs.dev" target="_blank">
      <img src="/vite.svg" class="logo" alt="Vite logo" />
    </a>
    <a href="https://vuejs.org/" target="_blank">
      <img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
    </a>
  </div>
  <HelloWorld msg="Vite + Vue" />
</template>
<script setup>
// This starter template is using Vue 3 <script setup> SFCs
// Check out https://vuejs.org/api/sfc-script-setup.html#script-setup
import HelloWorld from './components/HelloWorld.vue'
let msg  = "itbluebox"

function reMsg(val){
  return val.split('').reverse().join('')
}

</script>
<style scoped>
.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
}
.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
  filter: drop-shadow(0 0 2em #42b883aa);
}
</style>

访问:http://127.0.0.1:5173/

在这里插入图片描述

3、定义响应式ref

在这里插入图片描述

<template>
  <h1>{{msg}}</h1>
  <h1>{{reMsg(msg)}}</h1>
  <button @click="setMsg">点击修改</button>
  <div>
    <a href="https://vitejs.dev" target="_blank">
      <img src="/vite.svg" class="logo" alt="Vite logo" />
    </a>
    <a href="https://vuejs.org/" target="_blank">
      <img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
    </a>
  </div>
  <HelloWorld msg="Vite + Vue" />
</template>
<script setup>
// This starter template is using Vue 3 <script setup> SFCs
// Check out https://vuejs.org/api/sfc-script-setup.html#script-setup
import HelloWorld from './components/HelloWorld.vue'
let msg  = "itbluebox"

function reMsg(val){
  return val.split('').reverse().join('')
}

function setMsg(){
  msg = "red!!!"
}

</script>
<style scoped>
.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
}
.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
  filter: drop-shadow(0 0 2em #42b883aa);
}
</style>

访问:http://127.0.0.1:5173/

在这里插入图片描述

点击,发现没有反应

数据以及发生变化,但是没有响应式

设置响应式
//通过 ref 创建响应式对象

在这里插入图片描述

<template>
  <h1>{{msg}}</h1>
  <h1>{{reMsg(msg)}}</h1>
  <button @click="setMsg">点击修改</button>
  <div>
    <a href="https://vitejs.dev" target="_blank">
      <img src="/vite.svg" class="logo" alt="Vite logo" />
    </a>
    <a href="https://vuejs.org/" target="_blank">
      <img src="./assets/vue.svg" class="logo vue" alt="Vue logo" />
    </a>
  </div>
  <HelloWorld msg="Vite + Vue" />
</template>
<script setup>
// This starter template is using Vue 3 <script setup> SFCs
// Check out https://vuejs.org/api/sfc-script-setup.html#script-setup
import HelloWorld from './components/HelloWorld.vue'
import {ref} from  'vue'
//通过 ref  创建响应式对象
let msg  = ref("itbluebox")

function reMsg(val){
  return val.split('').reverse().join('')
}

function setMsg(){
  msg.value = "red!!!"
}


</script>
<style scoped>
.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
}
.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
  filter: drop-shadow(0 0 2em #42b883aa);
}
</style>

http://127.0.0.1:5173/

在这里插入图片描述


在这里插入图片描述

分析HelloWorld.vue

在这里插入图片描述


在这里插入图片描述

4、响应式reactive

设置一个对象并显示

在这里插入图片描述

<template>
  <div>
    <h1>用户名:{{user.username}}</h1>
    <h1>年龄:{{user.age}}</h1>
  </div>
  <HelloWorld msg="Vite + Vue" />
</template>
<script setup>
  import HelloWorld from './components/HelloWorld.vue'
  import {ref} from  'vue'

  var user = ref({
    username: 'itbluebox',
    age:18
  })

</script>
<style scoped>
.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
}
.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
  filter: drop-shadow(0 0 2em #42b883aa);
}
</style>

显示成功

在这里插入图片描述


显示成功

但是在修改的时候(设置点击事件设置点击修改年龄)

在这里插入图片描述


刷新页面
点击修改年龄,值已经被修改,但是页面没有变化

在这里插入图片描述


值设置为value的方式

在这里插入图片描述

点击修改
页面值发生变化

在这里插入图片描述

设置响应式的转换

在这里插入图片描述

<template>
  <div>
    <h1>用户名:{{user.username}}</h1>
    <h1>年龄:{{user.age}}</h1>
    <button @click="setUserAge">点击修改年龄</button>
    <h1>老师:{{ teacher.username }}</h1>
    <button @click="setTeacherName">修改名字</button>
  </div>
  <HelloWorld msg="Vite + Vue" />
</template>
<script setup>
  import HelloWorld from './components/HelloWorld.vue'
  import {ref,reactive} from  'vue'

  var user = ref({
    username: 'itbluebox',
    age:18
  })

  const teacher = reactive({
    username: 'itbluebox teacher',
    sex:"男",
    age:18
  })

  function setUserAge(){
    //user.age = 14
    user.value.age = 14
    console.log(user)
  }

  function setTeacherName(){
    teacher.username = "redbox"
  }

</script>
<style scoped>
.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
}
.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
  filter: drop-shadow(0 0 2em #42b883aa);
}
</style>

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

<template>
  <div>
    <h1>用户名:{{user.username}}</h1>
    <h1>年龄:{{user.age}}</h1>
    <button @click="setUserAge">点击修改年龄</button>
    <h1>老师:{{ teacher.username }}</h1>
    <button @click="setTeacherName">修改名字</button>
    <h1>用户名:{{user2.username}}</h1>
    <h1>年龄:{{user2.age}}</h1>
    <button @click="setUser2Age">点击修改年龄</button>
  </div>
  <HelloWorld msg="Vite + Vue" />
</template>
<script setup>
  import HelloWorld from './components/HelloWorld.vue'
  import {ref,reactive} from  'vue'

  var user = ref({
    username: 'itbluebox',
    age:18
  })
  const teacher = reactive({
    username: 'itbluebox teacher',
    sex:"男",
    age:18
  })
  function setUserAge(){
    //user.age = 14
    user.value.age = 14
    console.log(user)
  }
  function setTeacherName(){
    teacher.username = "redbox"
  }
  let user2 = reactive(user.value)
  function setUser2Age(){
    user2.age = 100;
  }
</script>
<style scoped>
.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
}
.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
  filter: drop-shadow(0 0 2em #42b883aa);
}
</style>

在这里插入图片描述


修改成功

在这里插入图片描述

5、Vue3事件对象与传递参数

事件对象

在这里插入图片描述

<template>
  <div>
    <h1>用户名:{{user.username}}</h1>
    <h1>年龄:{{user.age}}</h1>
    <button @click="setUserAge">点击修改年龄</button>
    <h1>老师:{{ teacher.username }}</h1>
    <button @click="setTeacherName">修改名字</button>
    <h1>用户名:{{user2.username}}</h1>
    <h1>年龄:{{user2.age}}</h1>
    <button @click="setUser2Age">点击修改年龄</button>
  </div>
  <HelloWorld msg="Vite + Vue" />
</template>
<script setup>
  import HelloWorld from './components/HelloWorld.vue'
  import {ref,reactive} from  'vue'

  var user = ref({
    username: 'itbluebox',
    age:18
  })
  const teacher = reactive({
    username: 'itbluebox teacher',
    sex:"男",
    age:18
  })
  function setUserAge(event){
    //user.age = 14
    user.value.age = 14
    console.log(user)
    console.log(event)
  }
  function setTeacherName(){
    teacher.username = "redbox"
  }
  let user2 = reactive(user.value)
  function setUser2Age(){
    user2.age = 100;
  }
</script>
<style scoped>
.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
}
.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
  filter: drop-shadow(0 0 2em #42b883aa);
}
</style>

在这里插入图片描述


传递参数

在这里插入图片描述

<button @click="setUserAge(10000)">点击修改年龄</button>
function setUserAge(value){
    //user.age = 14
    user.value.age = value
    console.log(user)
  }

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

 <button @click="setUserAge(10000,$event)">点击修改年龄</button>

传递参数的同时传递事件对象

在这里插入图片描述

function setUserAge(value,event){
    //user.age = 14
    user.value.age = value
    console.log(user)
    console.log(event)
  }

在这里插入图片描述

6、Vue3计算属性

6.1引入computed将计算的结果进行缓存,防止多次调用损失性能

在这里插入图片描述

<template>
  <div>
    <h1>{{msg}}</h1>
    <h1>{{ reMsg  }}</h1>
    <h1>{{ reMsg  }}</h1>
    <h1>{{ reMsg }}</h1>
    <button @click="setMsg('itred',$event)"></button>
  </div>
  <HelloWorld msg="Vite + Vue" />
</template>
<script setup>
  import HelloWorld from './components/HelloWorld.vue'
  import {ref,computed,reactive} from  'vue'

  let msg = reactive("itbluebox")

  function setMsg(value,event){
    msg.value = value
    console.log(value)
    console.log(event)
  }
  const reMsg = computed( function (){
        console.log(123)
        return msg.split("").reverse().join("")
      }
  )
</script>
<style scoped>
.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
}
.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
  filter: drop-shadow(0 0 2em #42b883aa);
}
</style>

在这里插入图片描述


我们可以发现虽然调用了三遍,但是函数只执行了一次

6.2 设置值和修改值

在这里插入图片描述

<template>
  <div>
    <h1>{{msg}}</h1>
    <h1>{{ reMsg  }}</h1>
    <h1>{{ reMsg  }}</h1>
    <h1>{{ reMsg }}</h1>
    <button @click="setMsg('itred',$event)">修改内容</button>
    <button @click="setReMsg">修改计算属性reMsg</button>
  </div>
  <HelloWorld msg="Vite + Vue" />
</template>
<script setup>
  import HelloWorld from './components/HelloWorld.vue'
  import {ref,computed} from  'vue'

  let msg = ref("itbluebox")

  function setMsg(value,event){
    msg.value = value
    console.log(value)
    console.log(event)
  }
  const reMsg = computed(  {
    get:()=>{
      console.log(123)
      return msg.value.split("").reverse().join("")
    },
    set:(value)=>{
      msg.value = value.split("").reverse().join("")
    }
  })
  function setReMsg(){
    reMsg.value = "zhngsan";
  }
</script>
<style scoped>
.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
}
.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
  filter: drop-shadow(0 0 2em #42b883aa);
}
</style>

在这里插入图片描述


上述reMsg默认加载的时候调用了get方法

在这里插入图片描述


点击修改计算属性reMsg的时候调用set方法后又调用get方法

7、Vue3监听数据变化

7.1、单个数据监听

在这里插入图片描述


  watch(msg,(newValue,oldValue)=>{
    console.log("newValue",newValue)
    console.log("oldValue",oldValue)
  })

在这里插入图片描述


在这里插入图片描述

监听对象

在这里插入图片描述

<h1>{{user.name}}</h1>
<button @click="user.name = '赵六'">修改名字</button>

在这里插入图片描述

 watch(
      ()=> user.name,
      (newValue,oldValue)=>{
    console.log("newValue",newValue)
    console.log("oldValue",oldValue)
  })

在这里插入图片描述


在这里插入图片描述

7.2、多个数据监听

同时监听多个数据

在这里插入图片描述

 watch(
      [msg,()=> user.name],
      (newValue,oldValue)=>{
    console.log("newValue",newValue)
    console.log("oldValue",oldValue)
  })

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

8、Vue3常见指令与样式

8.1、class

在这里插入图片描述

<template>
  <div>
    <h1>{{msg}}</h1>
     <h1 v-bind:class="classname"></h1>
    <h1 :class="classname"></h1>
  </div>
  <HelloWorld msg="Vite + Vue" />
</template>
<script setup>
  import HelloWorld from './components/HelloWorld.vue'
  import {ref, computed, watch, reactive} from 'vue'
  let msg = ref("itbluebox")
  let classname = ref('box bgRed')

</script>
<style scoped>
.logo {
  height: 6em;
  padding: 1.5em;
  will-change: filter;
}
.logo:hover {
  filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.vue:hover {
  filter: drop-shadow(0 0 2em #42b883aa);
}
.box{
  width: 200px;
  height: 200px;
  background-color: pink;
}
.bgRed{
  background-color: red;
}
</style>

在这里插入图片描述

8.2、id

在这里插入图片描述

<template>
  <div>
    <h1>{{msg}}</h1>
     <h1 v-bind:class="classname"></h1>
    <h1 :class="classname"></h1>
    <h1 :id="box"></h1>
  </div>
  <HelloWorld msg="Vite + Vue" />
</template>
<script setup>
  import HelloWorld from './components/HelloWorld.vue'
  import {ref, computed, watch, reactive} from 'vue'
  let msg = ref("itbluebox")
  let classname = ref('box bgRed')
  let box = ref('box')
</script>
<style scoped>
.box{
  width: 200px;
  height: 200px;
  background-color: pink;
}
.bgRed{
  background-color: red;
}
#box{
  width: 200px;
  height: 200px;
  background-color: pink;
}
</style>

在这里插入图片描述

8.3、title

在这里插入图片描述

 <h1 :title="desc" :class="classname"></h1>
 let desc = ref("这是一个box")

8.4、富文本显示

在这里插入图片描述

 <div class="content">{{html}}</div>
 let html = ref("<h1>这是HTML的内容</h1>")

我们发现显示的是文本

在这里插入图片描述


设置富文本显示

在这里插入图片描述

<div class="content" v-html="html"></div>

在这里插入图片描述

8.5、点击事件

监听点击事件
全显示

在这里插入图片描述

 <div v-on:click="count++">{{count}}</div>
 let count = ref(0)

在这里插入图片描述


简写

在这里插入图片描述

8.6、点击切换样式

在这里插入图片描述

<h1 :class="{box:true,bgRed:toggle}" @click="toggle = !toggle" ></h1>
let toggle = ref(true)

在这里插入图片描述


在这里插入图片描述

8.7、:style

在这里插入图片描述

  <h1 :style="h1Style"></h1>
 let h1Style = reactive({
    background:"skyblue",
    width:"200px",
    height:"200px"
  })

在这里插入图片描述


有横杠的属性使用驼峰命名法

在这里插入图片描述

borderStyle:"solid",

在这里插入图片描述

9、Vue父子组件数据传递Props

9.1 定义子组件在父组件当中引用

清空一下App.vue的数据

在这里插入图片描述

<template>
  <div>

  </div>
</template>
<script setup>

</script>
<style scoped>

</style>

新建自定义组件

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

<template>
  <h1>
    <span>
      {{num}}
    </span>
    ------------
    <span>
      {{title}}
    </span>

  </h1>
</template>

<script setup>


  let num = 1;
  let title = "今天是个好日子"

</script>

<style scoped>

</style>

在App.vue当中

在这里插入图片描述

<template>
  <div>
    <ListItem></ListItem>
  </div>
</template>
<script setup>
import ListItem from "./components/ListItem.vue"
</script>
<style scoped>

</style>

在这里插入图片描述

9.2 设置父组件给子组件传递数据

在这里插入图片描述

<template>
  <div>
    <ListItem :num="article.num" :title="article.title"></ListItem>
    <!--  prop = property  -->
  </div>
</template>
<script setup>
import ListItem from "./components/ListItem.vue"
import {reactive} from "vue";

let article = reactive({
  num:10,
  title:"定义propss"
})

</script>
<style scoped>

</style>

在这里插入图片描述

<template>
  <h1>
    <span>
      {{props.num}}
    </span>
    ---------
    <span>
      {{props.title}}
    </span>

  </h1>
</template>

<script setup>

import { defineProps } from 'vue'
const  props = defineProps({
  num:Number,
  title:String
})

</script>

<style scoped>

</style>

刷新页面

在这里插入图片描述

9.3 传递数组

在这里插入图片描述

<template>
  <div>
    <ListItem :num="article.num" :title="article.title"></ListItem>
    <!--  prop = property  -->
    <h1>列表循环</h1>
    <ListItem :num="item.num" :title="item.title" v-for="item in articleList"></ListItem>

  </div>
</template>
<script setup>
import ListItem from "./components/ListItem.vue"
import {reactive} from "vue";

let article = reactive({
  num:10,
  title:"定义propss"
})
let articleList = reactive([
  {
    num:10,
    title:"定义propss1"
  },
  {
    num:11,
    title:"定义propss2"
  }
])

</script>
<style scoped>

</style>

刷新页面

在这里插入图片描述

9.4 传递对象

在这里插入图片描述

<ListItem :num="article.num" :title="article.title" :article="article"></ListItem>
    <!--  prop = property  -->
    <h1>列表循环</h1>
    <ListItem
        :num="item.num"
        :title="item.title"
        :article="item"
        v-for="item in articleList">
    </ListItem>

在这里插入图片描述

	<template>
  <h1>
    <span>
      {{props.num}}
    </span>
    ---------
    <span>
      {{props.title}}
    </span>
    <br>
    article
    <span>
      {{props.article.num}}
    </span>
    ---------
    <span>
      {{props.article.title}}
    </span>
  </h1>
</template>

<script setup>

import { defineProps } from 'vue'
const  props = defineProps({
  num:Number,
  title:String,
  article:Object
})

</script>

<style scoped>

</style>

刷新页面

在这里插入图片描述

10、Vue3自定义事件

10.1 定义子组件在父组件当中引用(父组件的数据传递给子组件)

子组件当中定义事件

在这里插入图片描述

<template>
  <h1 @click="sendRead">
    <span>
      {{props.num}}
    </span>
    ---------
    <span>
      {{props.title}}
    </span>
    <br>
    article
    <span>
      {{props.article.num}}
    </span>
    ---------
    <span>
      {{props.article.title}}
    </span>
  </h1>
</template>

<script setup>

import { defineProps,defineEmits } from 'vue'
const  props = defineProps({
  num:Number,
  title:String,
  article:Object
})

const emit = defineEmits(['finishRead','reading'])

function sendRead(){
    emit('finishRead')
}

</script>

<style scoped>

</style>

在这里插入图片描述

<template>
  <div>
    <ListItem :num="article.num" :title="article.title" :article="article"></ListItem>
    <!--  prop = property  -->
    <h1>列表循环</h1>
    <ListItem
        :num="item.num"
        :title="item.title"
        :article="item"
        v-for="item in articleList"
        @finishRead="changeTitle(item)"
    >
    </ListItem>
  </div>
</template>
<script setup>
import ListItem from "./components/ListItem.vue"
import {reactive} from "vue";
let article = reactive({
  num:10,
  title:"定义propss"
})
let articleList = reactive([
  {
    num:10,
    title:"定义propss1"
  },
  {
    num:11,
    title:"定义propss2"
  }
])

function changeTitle(item){
  item.title += '【已读】'
}

</script>
<style scoped>

</style>

点击

在这里插入图片描述


在这里插入图片描述

10.2 定义子组件在父组件当中引用(子组件的数据传递给父组件)

在这里插入图片描述

emit('finishRead','【已经阅读】')

在这里插入图片描述

<template>
  <div>
    <ListItem :num="article.num" :title="article.title" :article="article"></ListItem>
    <!--  prop = property  -->
    <h1>列表循环</h1>
    <ListItem
        :num="item.num"
        :title="item.title"
        :article="item"
        v-for="item in articleList"
        @finishRead="changeTitle(item,$event)"
    >
    </ListItem>
  </div>
</template>
<script setup>
import ListItem from "./components/ListItem.vue"
import {reactive} from "vue";
let article = reactive({
  num:10,
  title:"定义propss"
})
let articleList = reactive([
  {
    num:10,
    title:"定义propss1"
  },
  {
    num:11,
    title:"定义propss2"
  }
])

function changeTitle(item,$event){
  item.title += $event
}

</script>
<style scoped>

</style>

点击

在这里插入图片描述


在这里插入图片描述


点击几次就增加几次

在这里插入图片描述


设置点击事件,设置点击内容内容不增加

在这里插入图片描述

function changeTitle(item,$event){
  if(item.title.indexOf($event) == -1){
    item.title += $event
  }
}

在这里插入图片描述


点击多次内容不累加

在这里插入图片描述


采用下角标的方式实现

在这里插入图片描述

<template>
  <div>
    <ListItem :num="article.num" :title="article.title" :article="article"></ListItem>
    <!--  prop = property  -->
    <h1>列表循环</h1>
    <ListItem
        :num="item.num"
        :title="item.title"
        :article="item"
        v-for="(item,index) in articleList"
        @finishRead="changeTitle(index,$event)"
    >
    </ListItem>
  </div>
</template>
<script setup>
import ListItem from "./components/ListItem.vue"
import {reactive} from "vue";
let article = reactive({
  num:10,
  title:"定义propss"
})
let articleList = reactive([
  {
    num:10,
    title:"定义propss1"
  },
  {
    num:11,
    title:"定义propss2"
  }
])
function changeTitle(index,$event){
  if(articleList[index].title.indexOf($event) == -1){
    articleList[index].title += $event
  }
}

</script>
<style scoped>

</style>

实现效果是一样的

在这里插入图片描述

11、Vue3路由

11.1 、设置路由

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

创建一些其他的页面

在这里插入图片描述

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

<template>
    <h1>Home</h1>
</template>

<script>
export default {
  name: "Home"
}
</script>

<style scoped>

</style>

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

<template>
  <h1>About</h1>
</template>

<script>
export default {
  name: "About"
}
</script>

<style scoped>

</style>

在这里插入图片描述


在这里插入图片描述

<template>
  <h1>Buycart</h1>
</template>

<script>
export default {
  name: "Buycart"
}
</script>

<style scoped>

</style>

设置路由
安装vue-router

在这里插入图片描述

npm install vue-router@4

完善index.js

在这里插入图片描述

import {
    createRouter,
    createWebHistory,
    createWebHashHistory
} from "vue-router"
import Home from "../views/Home.vue";
import About from "../views/About.vue";
import Buycart from "../views/Buycart.vue";
//2、定义一些路由
//每个路由都需要映射到一个组件
//我们后面再讨论嵌套路由
const routes = [
    {path:"/",component:Home,name:"home"},
    {path:"/about",component:About,name:"About"},
    {path:"/buycart",component:Buycart,name:"Buycart"},
];

//3、创建路由实例并传递‘routes’配置
//你可以在这里输入更多的配置,但是我们在这里
const router = createRouter({
    //4、内部提供了 history 模式的实现。为了简单起见,我们在这里使用hash模式
    history:createWebHashHistory(),
    routes, //routes:routes 的缩写
})

export default router

在这里插入图片描述

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router/index.js'

let app = createApp(App)
app.use(router)
app.mount('#app')

修改App.vue引入路由,完善页面

在这里插入图片描述

<template>
  <div>
    <router-view></router-view>
  </div>
</template>
<script setup>
</script>
<style scoped>
</style>

清除样式所带来的干扰

在这里插入图片描述


在这里插入图片描述

11.2 、设置跳转

在这里插入图片描述

<template>
  <div>
    <router-link to="/">跳转至首页</router-link> |
    <router-link to="/about">跳转至about</router-link> |
    <button @click="router.push('/')">跳转至首页</button>
    <button @click="goAbout">跳转至abou</button>
  </div>
  <router-view></router-view>
</template>
<script setup>
import { useRoute, useRouter } from "vue-router";
// 获取路由信息
let route = useRoute();
// 执行路由的跳转
let router = useRouter();
function goAbout() {
  console.log(route);
  router.push("/about");
}
</script>
<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>

在这里插入图片描述


在这里插入图片描述

11.3 、携带参数

在这里插入图片描述

	{
        path:"/product/:id",
        component:()=>{
          return   import('../views/Product.vue')
        },
        name:"product"
    },

在这里插入图片描述


在这里插入图片描述


访问:http://127.0.0.1:5173/#/product/123

在这里插入图片描述

12、Vue3状态管理

12.1 、安装Vuex相关内容

停止运行项目

在这里插入图片描述

npm install vuex@next --save

12.2、创建状态管理的内容(使用Vuex)

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

import { createStore } from 'vuex'

// 创建一个新的 store 实例
const store = createStore({
    state () {
        return {
            count: 0
        }
    },
    mutations: {
        increment (state) {
            state.count++
        }
    }
})

export default store;

在main.js当中使用

在这里插入图片描述

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router/index.js'
import store from "./store/index.js";
let app = createApp(App)
app.use(router)
app.use(store)
app.mount('#app')

完善store下的index.js

在这里插入图片描述

import { createStore } from 'vuex'
// 创建一个新的 store 实例
const store = createStore({
    state () {
        return {
            count: 0
        }
    },
    mutations: {
        increment (state,payload) {
            state.count+=payload
        }
    },
    getters:{
        totalPrice(state){
            return state.count * 98.8;
        }
    },
    actions:{
        asyncAdd(store,payload){
            setTimeout(()=>{
                store.commit('increment',10)
            },1000)
        }
    }
})

export default store;

12.3、使用状态管理(同步添加数据)

在这里插入图片描述

<template>
  <h1>Buycart</h1>
  <h1>商品数量:{{ store.state.count }}</h1>
  <button @click="addProd">添加商品数量+2</button>
</template>

<script setup>
import {useStore} from 'vuex'

let store = useStore()

function addProd(){
  store.commit('increment',2)
}



</script>

<style scoped>

</style>

访问

http://127.0.0.1:5173/#/buycart

在这里插入图片描述

点击以后每次加2

在这里插入图片描述

12.4、使用状态管理(异步添加数据)

在这里插入图片描述

<template>
  <h1>Buycart</h1>
  <h1>商品数量:{{ store.state.count }}</h1>
  <button @click="addProd">添加商品数量+2</button>
  <button @click="asyncAddProd">异步添加商品数量+10</button>
</template>

<script setup>
import {useStore} from 'vuex'

let store = useStore()

function addProd(){
  store.commit('increment',2)
}

function asyncAddProd(){
  store.dispatch('asyncAdd');
}



</script>

<style scoped>

</style>

在这里插入图片描述


点击以后有延迟的在新增数据

在这里插入图片描述


使用参数传递新增数据

在这里插入图片描述

 store.commit('increment',payload)

在这里插入图片描述

  store.dispatch('asyncAdd',5);

在这里插入图片描述

<template>
  <h1>Buycart</h1>
  <h1>商品数量:{{ store.state.count }}</h1>
  <button @click="addProd">添加商品数量+2</button>
  <button @click="asyncAddProd(5)">异步添加商品数量+5</button>
</template>

<script setup>
import {useStore} from 'vuex'

let store = useStore()

function addProd(){
  store.commit('increment',2)
}

function asyncAddProd(val){
  store.dispatch('asyncAdd',val);
}



</script>

<style scoped>

</style>

在这里插入图片描述


在这里插入图片描述


获取商品总价

在这里插入图片描述

 <h1>商品总价{{ store.getters.totalPrice }}</h1>

在这里插入图片描述


在这里插入图片描述

三、Vue3项目案例

1、vite按需加载antdesing与less

官网:https://www.antdv.com/docs/vue/migration-v3-cn

在这里插入图片描述


安装命令

在这里插入图片描述


在这里插入图片描述

npm i --save ant-design-vue

安装成功

在这里插入图片描述


局部引入组件

在这里插入图片描述


在这里插入图片描述


安装

npm i unplugin-vue-components -D

在这里插入图片描述


在这里插入图片描述

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import Components from "unplugin-vue-components/vite";
import { AntDesignVueResolver } from "unplugin-vue-components/resolvers";

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
    Components({
      resolvers: [AntDesignVueResolver()],
    }),
  ],
});

2、引入组件

在这里插入图片描述

<template>
  <h1>About</h1>
  <a-button type="primary">Primary Button</a-button>

</template>

<script setup>

</script>

<style scoped>

</style>

在这里插入图片描述

3、设置发起请求

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


安装axios

在这里插入图片描述

npm install axios

在这里插入图片描述

import axios from "axios";

const request = axios.create({
    // 配置接口请求的基准路径
    baseURL: "http://localhost:8080/metashop/api",
});
// 响应拦截器
request.interceptors.response.use(
    (response) => {
        if (response.status == 200) {
            return response.data;
        } else {
            return response;
        }
    },
    function (error) {
        return Promise.reject(error);
    }
);
export const getHomepage = (params) => {
    return request({
        method: "GET",
        url: "/homepage",
        // params选项用来配置QUERY的参数 ?query=xxxx
        params,
    });
};
export const getProducts = () => {
    return request({
        method: "GET",
        url: "/products",
    });
};

重新启动项目后访问:http://127.0.0.1:5173/#/

在这里插入图片描述


成功
获取数据

在这里插入图片描述

4、suspense异步组件

在子组件当中定义发起请求,在父组件当中显示数据
自定义异步组件

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

<template>

  <h1>首页</h1>
  <ul>
    <li v-for="(item,i) in hero">
      <h3>{{item.category}}</h3>
    </li>
  </ul>
</template>

<script setup>
import * as api from  '../api/index';
import {reactive} from "vue";

let result = await api.getHomepage();

const hero = reactive(result.hero);

</script>

<style scoped>

</style>

完善Home

在这里插入图片描述

<template>
  <suspense>
    <template #fallback>
      <div class="loading">
        <h1>Loading</h1>
      </div>
    </template>
    <template #default>
      <h1><HomeAsync></HomeAsync></h1>
    </template>
  </suspense>
</template>
<script setup>
import { onMounted, defineAsyncComponent } from "vue";
const HomeAsync = defineAsyncComponent(() =>
    import("../components/HomeCom.vue")
);

onMounted(async () => {
  //   let result = await api.getHomepage();
  //   console.log(result);
});
</script>

<style lang="less" scoped></style>

运行查看
会先显示Loading后显示首页

在这里插入图片描述


设置加载页面的优化,我们下载一些加载动画
https://loading.io/spinner/

在这里插入图片描述


选择一个

在这里插入图片描述

复制这段代码

<svg
      xmlns="http://www.w3.org/2000/svg"
      xmlns:xlink="http://www.w3.org/1999/xlink"
      style="
      margin: auto;
      background: #fff;
      display: block;
      position: fixed;
      left: 50%;
      top: 50%;
      margin-left: -100px;
      margin-top: -100px;
    "
      width="200px"
      height="200px"
      viewBox="0 0 100 100"
      preserveAspectRatio="xMidYMid"
  >
    <defs>
      <clipPath id="ldio-ssf8off6o8l-cp" x="0" y="0" width="100" height="100">
        <rect x="0" y="5" width="100" height="46"></rect>
      </clipPath>
    </defs>
    <path
        d="M70 75.2H34.1l-4.1-18.4l-0.7-3l-1-4.7c0 0 0 0 0-0.1c0-0.1 0-0.1-0.1-0.2c0 0 0-0.1-0.1-0.1c0 0 0-0.1-0.1-0.1 c0 0-0.1-0.1-0.1-0.1c0 0-0.1-0.1-0.1-0.1c0 0-0.1-0.1-0.1-0.1c0 0 0 0-0.1-0.1L22.3 44c0-0.1 0-0.2 0-0.3c0-1.9-1.6-3.5-3.5-3.5 s-3.5 1.6-3.5 3.5c0 1.9 1.6 3.5 3.5 3.5c0.7 0 1.4-0.2 2-0.6l4.8 3.7L31.5 77c0 0 0 0 0 0l-5.6 7.7c-0.3 0.5-0.4 1.1-0.1 1.6 c0.3 0.5 0.8 0.8 1.3 0.8h4c-0.8 0.8-1.3 1.9-1.3 3.2c0 2.6 2.1 4.7 4.7 4.7c2.6 0 4.7-2.1 4.7-4.7c0-1.2-0.5-2.3-1.3-3.2h29 c-0.8 0.8-1.3 1.9-1.3 3.2c0 2.6 2.1 4.7 4.7 4.7c2.6 0 4.7-2.1 4.7-4.7c0-1.2-0.5-2.3-1.3-3.2H77c0.8 0 1.5-0.7 1.5-1.5 s-0.7-1.5-1.5-1.5H30l4.3-6h36.8c0.7 0 1.3-0.5 1.4-1.1l7.5-27.3c0.2-0.8-0.2-1.6-1-1.8c-0.8-0.2-1.6 0.2-1.8 1l-1.3 4.7l-0.8 3"
        fill="#dddddd"
    ></path>
    <polygon
        points="31.3 53.1 35.7 73.2 68.5 73.2 74 53.1"
        fill="#dddddd"
    ></polygon>
    <g clip-path="url(#ldio-ssf8off6o8l-cp)">
      <g>
        <g transform="translate(50 41)">
          <path
              d="M6.5-6.7C6.1-6.9 5.7-7.2 5.3-7.4C5-7.5 4.6-7.7 4.3-7.8C3.1-2.2-4-3.7-2.9-9.3c-0.4 0-0.7 0-1.1 0 c-0.5 0-1 0.1-1.4 0.2c-1.8 0.3-3.6 0.9-5.3 1.8l1.1 4.2l3.1-0.8L-8.7 6.9L3.2 9.3L5.4-1.5l2.5 2l2.7-3.4C9.5-4.4 8.1-5.7 6.5-6.7z"
              fill="#e15b64"
          >
            <animateTransform
                attributeName="transform"
                type="rotate"
                keyTimes="0;1"
                values="0;360"
                dur="0.7462686567164178s"
                repeatCount="indefinite"
            ></animateTransform>
          </path>
        </g>
        <animateTransform
            attributeName="transform"
            type="translate"
            keyTimes="0;1"
            values="0 0;0 75"
            dur="1.4925373134328357s"
            repeatCount="indefinite"
        ></animateTransform>
      </g>
      <g>
        <g transform="translate(35 17)">
          <path
              d="M3.4-5.3L2.5-5l0.8-2.3L1.1-6.3l-1.2-2.2l-1.6 4.6l-4.6-1.6l0.9 2.3l-2.2 1.2l2.3 0.8L-6-0.9 c-0.6 0.3-0.8 0.9-0.5 1.5l1 2.1C-5.2 3.4-4.6 3.6-4 3.3l0.1-0.1l2.1 4.5C-1.4 8.4-0.7 8.7 0 8.3l1.7-0.8l1.7-0.8L5 5.9l1.7-0.8 C7.4 4.8 7.7 4 7.4 3.3L5.2-1.1l0.1-0.1c0.6-0.3 0.8-0.9 0.5-1.5l-1-2.1C4.6-5.4 3.9-5.6 3.4-5.3z"
              fill="#f47e60"
          >
            <animateTransform
                attributeName="transform"
                type="rotate"
                keyTimes="0;1"
                values="0;360"
                dur="0.7462686567164178s"
                repeatCount="indefinite"
            ></animateTransform>
          </path>
        </g>
        <animateTransform
            attributeName="transform"
            type="translate"
            keyTimes="0;1"
            values="0 0;0 75"
            dur="1.4925373134328357s"
            repeatCount="indefinite"
        ></animateTransform>
      </g>
      <g>
        <g transform="translate(66 26)">
          <path
              d="M-4.5-3.7L1.9-6l0.5-0.2L2-7.2l-6.9 2.5C-5.7-4.4-6.1-3.5-6-2.7c0 0.1 0 0.2 0.1 0.3l3 8.2 C-2.5 6.9-1.3 7.4-0.2 7l5.6-2C5.9 4.8 6.2 4.2 6 3.7L3.2-3.9l-0.4-1L2.4-4.7L1.9-4.5l-3.2 1.2l-2.7 1c-0.3 0.1-0.6 0-0.8-0.2 c-0.1-0.1-0.1-0.1-0.1-0.2C-5.1-3.1-4.9-3.6-4.5-3.7z"
              fill="#f8b26a"
          >
            <animateTransform
                attributeName="transform"
                type="rotate"
                keyTimes="0;1"
                values="0;360"
                dur="0.7462686567164178s"
                repeatCount="indefinite"
            ></animateTransform>
          </path>
        </g>
        <animateTransform
            attributeName="transform"
            type="translate"
            keyTimes="0;1"
            values="0 0;0 75"
            dur="1.4925373134328357s"
            repeatCount="indefinite"
        ></animateTransform>
      </g>
      <g>
        <g transform="translate(55 6)">
          <polygon
              points="0 -4.9 1.6 -1.7 5.1 -1.1 2.6 1.3 3.2 4.9 0 3.2 -3.2 4.9 -2.6 1.3 -5.1 -1.1 -1.6 -1.7"
              fill="#abbd81"
          >
            <animateTransform
                attributeName="transform"
                type="rotate"
                keyTimes="0;1"
                values="0;360"
                dur="0.7462686567164178s"
                repeatCount="indefinite"
            ></animateTransform>
          </polygon>
        </g>
        <animateTransform
            attributeName="transform"
            type="translate"
            keyTimes="0;1"
            values="0 0;0 75"
            dur="1.4925373134328357s"
            repeatCount="indefinite"
        ></animateTransform>
      </g>
    </g>
    <g clip-path="url(#ldio-ssf8off6o8l-cp)">
      <g transform="translate(0 -75)">
        <g>
          <g transform="translate(50 41)">
            <path
                d="M6.5-6.7C6.1-6.9 5.7-7.2 5.3-7.4C5-7.5 4.6-7.7 4.3-7.8C3.1-2.2-4-3.7-2.9-9.3c-0.4 0-0.7 0-1.1 0 c-0.5 0-1 0.1-1.4 0.2c-1.8 0.3-3.6 0.9-5.3 1.8l1.1 4.2l3.1-0.8L-8.7 6.9L3.2 9.3L5.4-1.5l2.5 2l2.7-3.4C9.5-4.4 8.1-5.7 6.5-6.7z"
                fill="#e15b64"
            >
              <animateTransform
                  attributeName="transform"
                  type="rotate"
                  keyTimes="0;1"
                  values="0;360"
                  dur="0.7462686567164178s"
                  repeatCount="indefinite"
              ></animateTransform>
            </path>
          </g>
          <animateTransform
              attributeName="transform"
              type="translate"
              keyTimes="0;1"
              values="0 0;0 75"
              dur="1.4925373134328357s"
              repeatCount="indefinite"
          ></animateTransform>
        </g>
        <g>
          <g transform="translate(35 17)">
            <path
                d="M3.4-5.3L2.5-5l0.8-2.3L1.1-6.3l-1.2-2.2l-1.6 4.6l-4.6-1.6l0.9 2.3l-2.2 1.2l2.3 0.8L-6-0.9 c-0.6 0.3-0.8 0.9-0.5 1.5l1 2.1C-5.2 3.4-4.6 3.6-4 3.3l0.1-0.1l2.1 4.5C-1.4 8.4-0.7 8.7 0 8.3l1.7-0.8l1.7-0.8L5 5.9l1.7-0.8 C7.4 4.8 7.7 4 7.4 3.3L5.2-1.1l0.1-0.1c0.6-0.3 0.8-0.9 0.5-1.5l-1-2.1C4.6-5.4 3.9-5.6 3.4-5.3z"
                fill="#f47e60"
            >
              <animateTransform
                  attributeName="transform"
                  type="rotate"
                  keyTimes="0;1"
                  values="0;360"
                  dur="0.7462686567164178s"
                  repeatCount="indefinite"
              ></animateTransform>
            </path>
          </g>
          <animateTransform
              attributeName="transform"
              type="translate"
              keyTimes="0;1"
              values="0 0;0 75"
              dur="1.4925373134328357s"
              repeatCount="indefinite"
          ></animateTransform>
        </g>
        <g>
          <g transform="translate(66 26)">
            <path
                d="M-4.5-3.7L1.9-6l0.5-0.2L2-7.2l-6.9 2.5C-5.7-4.4-6.1-3.5-6-2.7c0 0.1 0 0.2 0.1 0.3l3 8.2 C-2.5 6.9-1.3 7.4-0.2 7l5.6-2C5.9 4.8 6.2 4.2 6 3.7L3.2-3.9l-0.4-1L2.4-4.7L1.9-4.5l-3.2 1.2l-2.7 1c-0.3 0.1-0.6 0-0.8-0.2 c-0.1-0.1-0.1-0.1-0.1-0.2C-5.1-3.1-4.9-3.6-4.5-3.7z"
                fill="#f8b26a"
            >
              <animateTransform
                  attributeName="transform"
                  type="rotate"
                  keyTimes="0;1"
                  values="0;360"
                  dur="0.7462686567164178s"
                  repeatCount="indefinite"
              ></animateTransform>
            </path>
          </g>
          <animateTransform
              attributeName="transform"
              type="translate"
              keyTimes="0;1"
              values="0 0;0 75"
              dur="1.4925373134328357s"
              repeatCount="indefinite"
          ></animateTransform>
        </g>
        <g>
          <g transform="translate(55 6)">
            <polygon
                points="0 -4.9 1.6 -1.7 5.1 -1.1 2.6 1.3 3.2 4.9 0 3.2 -3.2 4.9 -2.6 1.3 -5.1 -1.1 -1.6 -1.7"
                fill="#abbd81"
            >
              <animateTransform
                  attributeName="transform"
                  type="rotate"
                  keyTimes="0;1"
                  values="0;360"
                  dur="0.7462686567164178s"
                  repeatCount="indefinite"
              ></animateTransform>
            </polygon>
          </g>
          <animateTransform
              attributeName="transform"
              type="translate"
              keyTimes="0;1"
              values="0 0;0 75"
              dur="1.4925373134328357s"
              repeatCount="indefinite"
          ></animateTransform>
        </g>
      </g>
    </g>
  </svg>

在这里插入图片描述


在这里插入图片描述


将刚刚的代码复制到这里
添加加载内容和百分比

在这里插入图片描述

<template>
  <svg
      xmlns="http://www.w3.org/2000/svg"
      xmlns:xlink="http://www.w3.org/1999/xlink"
      style="
      margin: auto;
      background: #fff;
      display: block;
      position: fixed;
      left: 50%;
      top: 50%;
      margin-left: -100px;
      margin-top: -100px;
    "
      width="200px"
      height="200px"
      viewBox="0 0 100 100"
      preserveAspectRatio="xMidYMid"
  >
    <defs>
      <clipPath id="ldio-ssf8off6o8l-cp" x="0" y="0" width="100" height="100">
        <rect x="0" y="5" width="100" height="46"></rect>
      </clipPath>
    </defs>
    <path
        d="M70 75.2H34.1l-4.1-18.4l-0.7-3l-1-4.7c0 0 0 0 0-0.1c0-0.1 0-0.1-0.1-0.2c0 0 0-0.1-0.1-0.1c0 0 0-0.1-0.1-0.1 c0 0-0.1-0.1-0.1-0.1c0 0-0.1-0.1-0.1-0.1c0 0-0.1-0.1-0.1-0.1c0 0 0 0-0.1-0.1L22.3 44c0-0.1 0-0.2 0-0.3c0-1.9-1.6-3.5-3.5-3.5 s-3.5 1.6-3.5 3.5c0 1.9 1.6 3.5 3.5 3.5c0.7 0 1.4-0.2 2-0.6l4.8 3.7L31.5 77c0 0 0 0 0 0l-5.6 7.7c-0.3 0.5-0.4 1.1-0.1 1.6 c0.3 0.5 0.8 0.8 1.3 0.8h4c-0.8 0.8-1.3 1.9-1.3 3.2c0 2.6 2.1 4.7 4.7 4.7c2.6 0 4.7-2.1 4.7-4.7c0-1.2-0.5-2.3-1.3-3.2h29 c-0.8 0.8-1.3 1.9-1.3 3.2c0 2.6 2.1 4.7 4.7 4.7c2.6 0 4.7-2.1 4.7-4.7c0-1.2-0.5-2.3-1.3-3.2H77c0.8 0 1.5-0.7 1.5-1.5 s-0.7-1.5-1.5-1.5H30l4.3-6h36.8c0.7 0 1.3-0.5 1.4-1.1l7.5-27.3c0.2-0.8-0.2-1.6-1-1.8c-0.8-0.2-1.6 0.2-1.8 1l-1.3 4.7l-0.8 3"
        fill="#dddddd"
    ></path>
    <polygon
        points="31.3 53.1 35.7 73.2 68.5 73.2 74 53.1"
        fill="#dddddd"
    ></polygon>
    <g clip-path="url(#ldio-ssf8off6o8l-cp)">
      <g>
        <g transform="translate(50 41)">
          <path
              d="M6.5-6.7C6.1-6.9 5.7-7.2 5.3-7.4C5-7.5 4.6-7.7 4.3-7.8C3.1-2.2-4-3.7-2.9-9.3c-0.4 0-0.7 0-1.1 0 c-0.5 0-1 0.1-1.4 0.2c-1.8 0.3-3.6 0.9-5.3 1.8l1.1 4.2l3.1-0.8L-8.7 6.9L3.2 9.3L5.4-1.5l2.5 2l2.7-3.4C9.5-4.4 8.1-5.7 6.5-6.7z"
              fill="#e15b64"
          >
            <animateTransform
                attributeName="transform"
                type="rotate"
                keyTimes="0;1"
                values="0;360"
                dur="0.7462686567164178s"
                repeatCount="indefinite"
            ></animateTransform>
          </path>
        </g>
        <animateTransform
            attributeName="transform"
            type="translate"
            keyTimes="0;1"
            values="0 0;0 75"
            dur="1.4925373134328357s"
            repeatCount="indefinite"
        ></animateTransform>
      </g>
      <g>
        <g transform="translate(35 17)">
          <path
              d="M3.4-5.3L2.5-5l0.8-2.3L1.1-6.3l-1.2-2.2l-1.6 4.6l-4.6-1.6l0.9 2.3l-2.2 1.2l2.3 0.8L-6-0.9 c-0.6 0.3-0.8 0.9-0.5 1.5l1 2.1C-5.2 3.4-4.6 3.6-4 3.3l0.1-0.1l2.1 4.5C-1.4 8.4-0.7 8.7 0 8.3l1.7-0.8l1.7-0.8L5 5.9l1.7-0.8 C7.4 4.8 7.7 4 7.4 3.3L5.2-1.1l0.1-0.1c0.6-0.3 0.8-0.9 0.5-1.5l-1-2.1C4.6-5.4 3.9-5.6 3.4-5.3z"
              fill="#f47e60"
          >
            <animateTransform
                attributeName="transform"
                type="rotate"
                keyTimes="0;1"
                values="0;360"
                dur="0.7462686567164178s"
                repeatCount="indefinite"
            ></animateTransform>
          </path>
        </g>
        <animateTransform
            attributeName="transform"
            type="translate"
            keyTimes="0;1"
            values="0 0;0 75"
            dur="1.4925373134328357s"
            repeatCount="indefinite"
        ></animateTransform>
      </g>
      <g>
        <g transform="translate(66 26)">
          <path
              d="M-4.5-3.7L1.9-6l0.5-0.2L2-7.2l-6.9 2.5C-5.7-4.4-6.1-3.5-6-2.7c0 0.1 0 0.2 0.1 0.3l3 8.2 C-2.5 6.9-1.3 7.4-0.2 7l5.6-2C5.9 4.8 6.2 4.2 6 3.7L3.2-3.9l-0.4-1L2.4-4.7L1.9-4.5l-3.2 1.2l-2.7 1c-0.3 0.1-0.6 0-0.8-0.2 c-0.1-0.1-0.1-0.1-0.1-0.2C-5.1-3.1-4.9-3.6-4.5-3.7z"
              fill="#f8b26a"
          >
            <animateTransform
                attributeName="transform"
                type="rotate"
                keyTimes="0;1"
                values="0;360"
                dur="0.7462686567164178s"
                repeatCount="indefinite"
            ></animateTransform>
          </path>
        </g>
        <animateTransform
            attributeName="transform"
            type="translate"
            keyTimes="0;1"
            values="0 0;0 75"
            dur="1.4925373134328357s"
            repeatCount="indefinite"
        ></animateTransform>
      </g>
      <g>
        <g transform="translate(55 6)">
          <polygon
              points="0 -4.9 1.6 -1.7 5.1 -1.1 2.6 1.3 3.2 4.9 0 3.2 -3.2 4.9 -2.6 1.3 -5.1 -1.1 -1.6 -1.7"
              fill="#abbd81"
          >
            <animateTransform
                attributeName="transform"
                type="rotate"
                keyTimes="0;1"
                values="0;360"
                dur="0.7462686567164178s"
                repeatCount="indefinite"
            ></animateTransform>
          </polygon>
        </g>
        <animateTransform
            attributeName="transform"
            type="translate"
            keyTimes="0;1"
            values="0 0;0 75"
            dur="1.4925373134328357s"
            repeatCount="indefinite"
        ></animateTransform>
      </g>
    </g>
    <g clip-path="url(#ldio-ssf8off6o8l-cp)">
      <g transform="translate(0 -75)">
        <g>
          <g transform="translate(50 41)">
            <path
                d="M6.5-6.7C6.1-6.9 5.7-7.2 5.3-7.4C5-7.5 4.6-7.7 4.3-7.8C3.1-2.2-4-3.7-2.9-9.3c-0.4 0-0.7 0-1.1 0 c-0.5 0-1 0.1-1.4 0.2c-1.8 0.3-3.6 0.9-5.3 1.8l1.1 4.2l3.1-0.8L-8.7 6.9L3.2 9.3L5.4-1.5l2.5 2l2.7-3.4C9.5-4.4 8.1-5.7 6.5-6.7z"
                fill="#e15b64"
            >
              <animateTransform
                  attributeName="transform"
                  type="rotate"
                  keyTimes="0;1"
                  values="0;360"
                  dur="0.7462686567164178s"
                  repeatCount="indefinite"
              ></animateTransform>
            </path>
          </g>
          <animateTransform
              attributeName="transform"
              type="translate"
              keyTimes="0;1"
              values="0 0;0 75"
              dur="1.4925373134328357s"
              repeatCount="indefinite"
          ></animateTransform>
        </g>
        <g>
          <g transform="translate(35 17)">
            <path
                d="M3.4-5.3L2.5-5l0.8-2.3L1.1-6.3l-1.2-2.2l-1.6 4.6l-4.6-1.6l0.9 2.3l-2.2 1.2l2.3 0.8L-6-0.9 c-0.6 0.3-0.8 0.9-0.5 1.5l1 2.1C-5.2 3.4-4.6 3.6-4 3.3l0.1-0.1l2.1 4.5C-1.4 8.4-0.7 8.7 0 8.3l1.7-0.8l1.7-0.8L5 5.9l1.7-0.8 C7.4 4.8 7.7 4 7.4 3.3L5.2-1.1l0.1-0.1c0.6-0.3 0.8-0.9 0.5-1.5l-1-2.1C4.6-5.4 3.9-5.6 3.4-5.3z"
                fill="#f47e60"
            >
              <animateTransform
                  attributeName="transform"
                  type="rotate"
                  keyTimes="0;1"
                  values="0;360"
                  dur="0.7462686567164178s"
                  repeatCount="indefinite"
              ></animateTransform>
            </path>
          </g>
          <animateTransform
              attributeName="transform"
              type="translate"
              keyTimes="0;1"
              values="0 0;0 75"
              dur="1.4925373134328357s"
              repeatCount="indefinite"
          ></animateTransform>
        </g>
        <g>
          <g transform="translate(66 26)">
            <path
                d="M-4.5-3.7L1.9-6l0.5-0.2L2-7.2l-6.9 2.5C-5.7-4.4-6.1-3.5-6-2.7c0 0.1 0 0.2 0.1 0.3l3 8.2 C-2.5 6.9-1.3 7.4-0.2 7l5.6-2C5.9 4.8 6.2 4.2 6 3.7L3.2-3.9l-0.4-1L2.4-4.7L1.9-4.5l-3.2 1.2l-2.7 1c-0.3 0.1-0.6 0-0.8-0.2 c-0.1-0.1-0.1-0.1-0.1-0.2C-5.1-3.1-4.9-3.6-4.5-3.7z"
                fill="#f8b26a"
            >
              <animateTransform
                  attributeName="transform"
                  type="rotate"
                  keyTimes="0;1"
                  values="0;360"
                  dur="0.7462686567164178s"
                  repeatCount="indefinite"
              ></animateTransform>
            </path>
          </g>
          <animateTransform
              attributeName="transform"
              type="translate"
              keyTimes="0;1"
              values="0 0;0 75"
              dur="1.4925373134328357s"
              repeatCount="indefinite"
          ></animateTransform>
        </g>
        <g>
          <g transform="translate(55 6)">
            <polygon
                points="0 -4.9 1.6 -1.7 5.1 -1.1 2.6 1.3 3.2 4.9 0 3.2 -3.2 4.9 -2.6 1.3 -5.1 -1.1 -1.6 -1.7"
                fill="#abbd81"
            >
              <animateTransform
                  attributeName="transform"
                  type="rotate"
                  keyTimes="0;1"
                  values="0;360"
                  dur="0.7462686567164178s"
                  repeatCount="indefinite"
              ></animateTransform>
            </polygon>
          </g>
          <animateTransform
              attributeName="transform"
              type="translate"
              keyTimes="0;1"
              values="0 0;0 75"
              dur="1.4925373134328357s"
              repeatCount="indefinite"
          ></animateTransform>
        </g>
      </g>
    </g>
  </svg>
  <h3>加载中:{{ progress }}%</h3>
</template>
<script setup>
let props = defineProps({
  progress: Number,
});
</script>
<style scoped>
h3 {
  position: fixed;
  top: 100px;
  left: 50%;
  font-size: 30px;
  font-weight: 900;
}
</style>

访问页面

在这里插入图片描述

5、导航菜单栏实现现有图标使用

在这里插入图片描述


在这里插入图片描述

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

<template>
  <Header></Header>
  <router-view></router-view>
</template>
<script setup>
import Header from './components/Header.vue'
import { useRoute, useRouter } from "vue-router";
// 获取路由信息
let route = useRoute();
// 执行路由的跳转
let router = useRouter();

</script>

<style>

</style>

完善Header.vue
设置布局

在这里插入图片描述

<template>
  <div class="header"  >
    <div class="logo" @click="router.push('/')">
      <img src="../assets/img/logo_rect.jpg" alt="logo" />
    </div>
    <a-input-search
        v-model:value="data.value"
        placeholder="搜索商品或商品号"
        class="input-search"
        @search="onSearch"
    />
    <a-menu v-model:selectedKeys="data.current" mode="horizontal">
      <a-menu-item key="help">
        <template #icon>
          <question-circle-outlined />
        </template>
        帮助
      </a-menu-item>
      <a-menu-item key="salesroom">
        <template #icon>
          <ShopOutlined />
        </template>
        门店
      </a-menu-item>
      <a-sub-menu key="account">
        <template #icon>
          <UserOutlined />
        </template>
        <template #title>账户</template>
      </a-sub-menu>
      <a-sub-menu key="buycart">
        <template #icon>
          <CarOutlined />
        </template>
        <template #title>购物车</template>
        <a-menu-item-group title="购物商品">
          <a-menu-item v-for="(item, i) in store.state.buycarts" :key="item.id">
            <div class="prod-item">
              <div class="left">
                <img :src="item.imgsrc" :alt="item.title" />
              </div>
              <div class="middle">
                <div class="title">{{ item.title }}</div>
                <div class="content">
                  <span class="num">数量:{{ item.num }}</span>
                  <div class="control">
                    <span
                        class="btn"
                        @click.stop="store.commit('addBuycartsNum', i)"
                    >+</span
                    >
                    <span
                        class="btn"
                        @click.stop="store.commit('minusBuycartsNum', i)"
                    >-</span
                    >
                  </div>
                </div>
              </div>
              <div class="right">
                <div class="price">¥ {{ item.price * item.num }}</div>
              </div>
            </div>
          </a-menu-item>
          <a-menu-item key="totalPrice">
            <div class="total">
              <span>总价:</span>
              <span class="num"> ¥ {{ store.getters.totalPrice }}</span>
            </div>
          </a-menu-item>
        </a-menu-item-group>
      </a-sub-menu>
    </a-menu>
  </div>
</template>

<script setup>
import { useRoute, useRouter } from "vue-router";
import { useStore } from "vuex";
import { reactive } from "vue";
import {
  ShopOutlined,
  UserOutlined,
  CarOutlined,
  QuestionCircleOutlined,
} from "@ant-design/icons-vue";
const store = useStore();
const router = useRouter();
const data = reactive({
  value: "",
  current: ["help"],
});
const onSearch = () => {};
</script>

<style  scoped>

.header{
  display: flex;
  justify-content: space-between;
  align-content: center;
  position: fixed;
  z-index: 10000;
  width: 100%;
}

.logo{
  margin-right: 40px;
}

</style>

完善样式

安装less、less-loader

在这里插入图片描述

# .scss and .sass
npm install -D sass

# .less
npm install less-loader less --save-dev

# .styl and .stylus
npm install -D stylus

在这里插入图片描述

<style lang="less" scoped>
.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  position: fixed;
  z-index: 1000000;
  width: 100%;
  background-color: #fff;
  box-shadow: 0 0 10px #ccc;
  transition: all 0.5s;
}
.header.hidden {
  transform: translate(0, -100%);
}

.logo {
  margin-right: 40px;
  img {
    height: 30px;
  }
}
.input-search {
  display: flex;
  flex: 1;
  height: 40px;
  align-items: center;
}
</style>

在这里插入图片描述

6、轮播图倾斜与颜色转变

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

<template>

  <div class="homeswiper">
    <div class="swiperBg">
      <a-carousel arrows autoplay>
        <template #prevArrow>
          <div class="custom-slick-arrow" style="left: 10px; z-index: 1">
            <left-circle-outlined />
          </div>
        </template>
        <template #nextArrow>
          <div class="custom-slick-arrow" style="right: 10px">
            <right-circle-outlined />
          </div>
        </template>
        <div><h3>1</h3></div>
        <div><h3>2</h3></div>
        <div><h3>3</h3></div>
        <div><h3>4</h3></div>
      </a-carousel>
    </div>
  </div>

</template>

<script setup>
import { LeftCircleOutlined, RightCircleOutlined } from '@ant-design/icons-vue';
</script>
<!--
scoped 设置样式作用域仅仅在当前有效
:deep 控制当前组件内部组件样式
-->
<style lang="less" scoped>
/* For demo */
.ant-carousel :deep(.slick-slide) {
  text-align: center;
  height: 160px;
  line-height: 160px;
  background: #364d79;
  overflow: hidden;
}

.ant-carousel :deep(.slick-arrow.custom-slick-arrow) {
  width: 25px;
  height: 25px;
  font-size: 25px;
  color: #fff;
  background-color: rgba(31, 45, 61, 0.11);
  opacity: 0.3;
  z-index: 1;
}
.ant-carousel :deep(.custom-slick-arrow:before) {
  display: none;
}
.ant-carousel :deep(.custom-slick-arrow:hover) {
  opacity: 0.5;
}

.ant-carousel :deep(.slick-slide h3) {
  color: #fff;
}
</style>

在HomeCom首页当中引入改组件

在这里插入图片描述

<template>
  <div class="homepage">
    <HomeSwiper></HomeSwiper>
  </div>
</template>

<script setup>
import HomeSwiper from "./Home/HomeSwiper.vue"
import * as api from  '../api/index';
import {reactive} from "vue";

let result = await api.getHomepage();

const hero = reactive(result.hero);

</script>

<style scoped>

</style>

访问:http://127.0.0.1:5173/#/

在这里插入图片描述


设置倾斜

在这里插入图片描述

<template>
  <div class="homepage">
    <HomeSwiper></HomeSwiper>
  </div>
</template>

<script setup>
import HomeSwiper from "./Home/HomeSwiper.vue"
import * as api from  '../api/index';
import {reactive} from "vue";

let result = await api.getHomepage();

const hero = reactive(result.hero);

</script>

<style lang="less" scoped>
.homepage{
  padding-top: 46px;
  height: 575px;
  position: relative;
}
</style>

在这里插入图片描述

<template>

  <div class="homeswiper">
    <div class="swiperBg">
      <a-carousel arrows autoplay>
        <template #prevArrow>
          <div class="custom-slick-arrow" style="left: 10px; z-index: 1">
            <left-circle-outlined />
          </div>
        </template>
        <template #nextArrow>
          <div class="custom-slick-arrow" style="right: 10px">
            <right-circle-outlined />
          </div>
        </template>
        <div><h3>1</h3></div>
        <div><h3>2</h3></div>
        <div><h3>3</h3></div>
        <div><h3>4</h3></div>
      </a-carousel>
    </div>
  </div>

</template>

<script setup>
import { LeftCircleOutlined, RightCircleOutlined } from '@ant-design/icons-vue';

</script>
<!--
scoped 设置样式作用域仅仅在当前有效
:deep 控制当前组件内部组件样式
-->

<style lang="less" scoped>
.swiperBg {
  position: absolute;
  display: block;
  width: 100%;
  height: 575px;
  background-color: #00d9ff;
  transform-origin: 0 0;
  transform: skew(0, -8deg);
  transition: all 0.5s;
}
.swiper-item {
  height: 575px;
  .swiper-box {
    display: flex;
    min-width: 1200px;
    justify-content: center;
    .swiper-left {
      width: 340px;
      padding-right: 100px;
      display: flex;
      flex-direction: column;
      align-items: flex-end;
      margin-top: 100px;
      text-align: right;
    }
    h3 {
      font-size: 30px;
      font-weight: 900;
      margin: 0;
      line-height: 40px;
    }
    h1 {
      font-size: 60px;
      font-weight: 900;
      margin: 0;
      line-height: 70px;
    }

    .banner-right {
      margin-top: 45px;
      transform-origin: 0 100%;
      transform: skew(0, -8deg);
      overflow: hidden;
      border-radius: 20px;
      border-bottom-right-radius: 80px;
      img {
        transform-origin: 0 100%;
        transform: skew(0, 8deg);
        border-radius: 20px;
      }
    }
  }
}
/* For demo */
.ant-carousel :deep(.slick-slide) {
  text-align: center;
  height: 575px;
  line-height: 160px;
  overflow: hidden;
}
.ant-carousel :deep(.slick-arrow.custom-slick-arrow) {
  width: 25px;
  height: 25px;
  font-size: 25px;
  color: #fff;
  background-color: rgba(31, 45, 61, 0.11);
  opacity: 0.3;
  z-index: 1;
}
.ant-carousel :deep(.custom-slick-arrow:before) {
  display: none;
}
.ant-carousel :deep(.custom-slick-arrow:hover) {
  opacity: 0.5;
}
.ant-carousel :deep(.slick-slide h3) {
  color: #fff;
}
</style>

在这里插入图片描述


在HomeCom.vue得到请求对应的数据,将数据设置到子组件当中:banner="data.banner"

在这里插入图片描述

<template>
  <div class="homepage">
    <HomeSwiper :banner="data.banner"></HomeSwiper>
  </div>
</template>

<script setup>
import HomeSwiper from "./Home/HomeSwiper.vue"
import * as api from  '../api/index';
import {reactive} from "vue";
let result = await api.getHomepage();


const data = reactive({ banner: result.banner });

</script>
<style lang="less" scoped>
.homepage{
  padding-top: 46px;
  height: 575px;
  position: relative;
}
</style>

在HomeSwiper子组件当中获取父组件数据,实现走马灯切换图片

在这里插入图片描述

<script setup>
import { LeftCircleOutlined, RightCircleOutlined } from '@ant-design/icons-vue';

import {reactive,defineProps} from "vue";

const props = defineProps({banner:Array})

const data = reactive({
  bgColor: props.banner[0].bg_color,
})

console.log(props)

function changeFn(from,to) {
  data.bgColor = props.banner[to].bg_color
}
</script>

在这里插入图片描述


在这里插入图片描述

7、实现轮播图负负得正的倾斜效果

在这里插入图片描述


在这里插入图片描述

<template>
  <div class="homeswiper">
    <div class="swiperBg" :style="{ backgroundColor: data.bgColor }"></div>
    <a-carousel arrows autoplay :beforeChange="changeFn">
      <template #prevArrow>
        <div class="custom-slick-arrow" style="left: 10px; z-index: 1">
          <left-circle-outlined />
        </div>
      </template>
      <template #nextArrow>
        <div class="custom-slick-arrow" style="right: 10px">
          <right-circle-outlined />
        </div>
      </template>
      <div class="swiper-item" v-for="(item, i) in props.banner">
        <div class="swiper-box">
          <div class="swiper-left">
            <h3 :style="{ color: item.text_color }">
              {{ item.desktop_sub_title || item.sub_title }}
            </h3>
            <h1 :style="{ color: item.text_color }">
              {{ item.desktop_title || item.title }}
            </h1>
          </div>
          <div class="banner-right">
            <img
                :src="`https://pixl.decathlon.com.cn/${item.picture_desktop}/banner.jpg`"
                :alt="item.title"
            />
          </div>
        </div>
      </div>
    </a-carousel>
  </div>
</template>
<script setup>
import { LeftCircleOutlined, RightCircleOutlined } from "@ant-design/icons-vue";
import { reactive } from "vue";
const props = defineProps({ banner: Array });
const data = reactive({
  bgColor: props.banner[0].bg_color,
});
function changeFn(from, to) {
  //   console.log(to);
  data.bgColor = props.banner[to].bg_color;
}
</script>
<style lang="less" scoped>
.swiperBg {
  position: absolute;
  display: block;
  width: 100%;
  height: 575px;
  background-color: orangered;
  transform-origin: 0 0;
  transform: skew(0, -8deg);
  transition: all 0.5s;
}
.swiper-item {
  height: 575px;
  .swiper-box {
    display: flex;
    min-width: 1200px;
    justify-content: center;
    .swiper-left {
      width: 340px;
      padding-right: 100px;
      display: flex;
      flex-direction: column;
      align-items: flex-end;
      margin-top: 100px;
      text-align: right;
    }
    h3 {
      font-size: 30px;
      font-weight: 900;
      margin: 0;
      line-height: 40px;
    }
    h1 {
      font-size: 60px;
      font-weight: 900;
      margin: 0;
      line-height: 70px;
    }
    .banner-right {
      margin-top: 45px;
      transform-origin: 0 100%;
      transform: skew(0, -8deg);
      overflow: hidden;
      border-radius: 20px;
      border-bottom-right-radius: 80px;
      img {
        transform-origin: 0 100%;
        transform: skew(0, 8deg);
        border-radius: 20px;
      }
    }
  }
}
/* For demo */
.ant-carousel :deep(.slick-slide) {
  text-align: center;
  height: 575px;
  line-height: 160px;
  overflow: hidden;
}
.ant-carousel :deep(.slick-arrow.custom-slick-arrow) {
  width: 25px;
  height: 25px;
  font-size: 25px;
  color: #fff;
  background-color: rgba(31, 45, 61, 0.11);
  opacity: 0.3;
  z-index: 1;
}
.ant-carousel :deep(.custom-slick-arrow:before) {
  display: none;
}
.ant-carousel :deep(.custom-slick-arrow:hover) {
  opacity: 0.5;
}

.ant-carousel :deep(.slick-slide h3) {
  color: #fff;
}
</style>

在这里插入图片描述

8、实现分类组件的应用

在这里插入图片描述

<template>
  <div class="homepage">
    <HomeSwiper :banner="data.banner"></HomeSwiper>
    <div class="live">
      <h1>生活类别100+</h1>
      <div class="live-list">
        <div
            class="live-item"
            v-for="index in 10"
            v-if="data.sports.length !== 0"
        >
          <div class="live-btn">
            <img
                :src="data.sports[index].menuThumbnail"
                :alt="data.sports[index].displayName"
            />
            <h3>{{ data.sports[index].displayName }}</h3>
          </div>
        </div>
      </div>
      <a-button type="primary" size="large" @click="router.push('/product')"
      >立即享受生活</a-button
      >
    </div>
  </div>
</template>

<script setup>
import HomeSwiper from "./Home/HomeSwiper.vue";
import * as api from "../api/index";
import { reactive } from "vue";
import { useRouter } from "vue-router";
let result = await api.getHomepage();
const router = useRouter();

const data = reactive({ banner: result.banner, sports: result.sports });
console.log(result);
</script>

<style lang="less" scoped>
.homepage {
  padding-top: 46px;
  height: 575px;
  position: relative;
}

.live {
  width: 1200px;
  margin: 40px auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding-bottom: 40px;
  h1 {
    font-size: 30px;
  }

  .live-list {
    display: flex;
    flex-wrap: wrap;
    .live-item {
      width: 240px;
    }
    .live-btn {
      display: flex;
      height: 73px;
      width: 200px;
      background-color: #fff;
      border-radius: 8px 8px 25px 8px;
      margin-bottom: 30px;
      box-shadow: 5px 5px 5px #ccc;
      align-items: center;
      justify-content: center;
      position: relative;
      img {
        position: absolute;
        width: 80px;
        height: 80px;
        left: -15px;
        top: -15px;
      }
      h3 {
        font-weight: 900;
        font-size: 20px;
      }
    }
  }
}
</style>

刷新页面

在这里插入图片描述

9、鼠标滚动控制全屏切换

设置请求的接口

在这里插入图片描述

export const getProducts = () => {
    return request({
        method: "GET",
        url: "/products",
    });
};

在store当中设置对应状态管理

在这里插入图片描述

isFullscreen:false
getFullScreen(state,payload){
     state.isFullscreen = payload;
}

完善Product.vue 实现状态栏隐藏

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


鼠标滚动

在这里插入图片描述

10、实现产品列表的展示

在这里插入图片描述


在这里插入图片描述


完善样式

在这里插入图片描述


全部代码

<template>
  <h1>Product</h1>
  <h1>产品id是{{ route.params.id }}</h1>
  <div class="loading" v-show="data.isLoading">
      <Loading></Loading>
  </div>
  <div class="product" v-show="!data.isLoading">
    <div class="prod-list" :class="{hidden:store.state.isFullscreen}">
      <h1> <SketchOutlined>产品推荐</SketchOutlined> </h1>

      <div class="products">
        <div class="prod-item" v-for="(prod,pI) in data.products">
          <div class="prod-title">
              {{ prod.title }}
          </div>
          <div class="img">
              <img :src="prod.imgsrc" :alt="prod.title">
          </div>
          <a-button type="primary" block >
            <template #icon>
              <ShoppingCartOutlined></ShoppingCartOutlined>
            </template>
            加入购物车
          </a-button>
        </div>
      </div>

      <div class="products">

      </div>
    </div>
    <div class="scene-list" :class="{hidden:store.state.isFullscreen}">
      <h3><RadarChartOutlined>切换使用场景</RadarChartOutlined> </h3>
    </div>
  </div>
</template>

<script setup>
import Loading from "../components/Loading.vue";
import {
  SketchOutlined,
  RadarChartOutlined,
  ShoppingCartOutlined,
} from "@ant-design/icons-vue";
import { useRoute } from 'vue-router'
import {onMounted, reactive} from 'vue'
import * as api from '../api/index.js'
import {useStore} from 'vuex'
const route = useRoute();
const store = useStore();
console.log(route)
const data = reactive({
  products :[],
  isLoading:true,
  scenes:[]
})
//生命周期函数x
onMounted(async () => {
  //await  等待数据返回结果  ,使用await 的同时 必须使用async
  let result = await api.getProducts()
  console.log(result);
  data.isLoading = false;
  data.products = result.list;
  data.scenes = result.hdr;

})
window.addEventListener('mousewheel' ,(e)=>{
 // console.log(e)
    if(e.deltaY > 0){
      store.commit("getFullScreen",true)
    }
    if(e.deltaY < 0){
      store.commit("getFullScreen",false)
    }
})
</script>

<style lang="less" scoped>
.desc {
  position: fixed;
  z-index: 100000;
  background-color: rgba(255, 255, 255, 0.5);
  width: 600px;
  top: 100px;
  left: 50%;
  margin-left: -300px;
  transition: all 0.5s;

  transform: translate(-100vw, 0);
  padding: 15px;
}
.desc.active {
  transform: translate(0, 0);
}
.prod-list {
  width: 300px;
  height: 100vh;
  padding: 60px 0 0;
  position: fixed;
  z-index: 100000;
  transition: all 0.5s;
  background-color: rgb(208, 255, 0);
  left: 0;
  top: 0;
  h1 {
    font-size: 20px;
    font-weight: 900;
    padding: 10px 25px 0;
  }
  .products {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    .prod-item {
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      width: 250px;
      background-color: #fff;
      border-radius: 20px;
      overflow: hidden;
      margin: 10px 0;
      box-shadow: 2px 2px 5px #666;
      transition: all 0.3s;
      &.active {
        box-shadow: 2px 2px 5px #666, 0px 0px 10px red;
      }
      &:hover {
        transform: translate(0px, -5px);
        box-shadow: 2px 2px 5px #666, 0px 0px 10px orangered;
        // background-color: orange;
      }
      img {
        width: 190px;
      }
      .prod-title {
        padding: 0 20px;
      }
    }
  }
}
.prod-list.hidden {
  transform: translate(-100%, 0);
}
.scene-list {
  width: 300px;
  height: 100vh;
  padding: 60px 0 0;
  position: fixed;
  z-index: 100000;
  transition: all 0.5s;
  background-color: rgba(182, 73, 73, 0.8);
  right: 0;
  top: 0;
  h3 {
    font-size: 20px;
    font-weight: 900;
    padding: 0 30px;
  }
  .scenes {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
  }

  .scene-item {
    padding: 6px 0;

    img {
      width: 250px;
      border-radius: 10px;
      box-shadow: 2px 2px 10px #666;
      transition: all 0.3s;
      &.active {
        box-shadow: 2px 2px 5px #666, 0px 0px 10px red;
      }
      &:hover {
        transform: translate(0px, -5px);
        box-shadow: 2px 2px 5px #666, 0px 0px 10px orangered;
      }
    }
  }
}
.scene-list.hidden {
  transform: translate(100%, 0);
}
</style>

在这里插入图片描述


继续完善列表功能

在这里插入图片描述

<div class="scenes">
          <div class="scene-item" v-for="(scene,index) in data.scenes">
            <img :src="`./files/hdr/${scene}.jpg`" :alt="scene">
          </div>
      </div>

在这里插入图片描述


设置点以及其他功能开发

在这里插入图片描述

  pIndex:0,
  sceneIndex: 0

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


实现点击选择
防止手残全部代码

<template>
  <h1>Product</h1>
  <h1>产品id是{{ route.params.id }}</h1>
  <div class="loading" v-show="data.isLoading">
      <Loading></Loading>
  </div>
  <div class="product" v-show="!data.isLoading">
    <div class="prod-list" :class="{hidden:store.state.isFullscreen}">
      <h1> <SketchOutlined>产品推荐</SketchOutlined> </h1>

      <div class="products">
        <div class="prod-item"
             :class="{ active : pI == data.pIndex }"
             v-for="(prod,pI) in data.products"
             @click="changeModel(prod,pI)">
          <div class="prod-title">
              {{ prod.title }}
          </div>
          <div class="img">
              <img :src="prod.imgsrc" :alt="prod.title">
          </div>
          <a-button type="primary" block >
            <template #icon>
              <ShoppingCartOutlined></ShoppingCartOutlined>
            </template>
            加入购物车
          </a-button>
        </div>
      </div>
      <div class="products">
      </div>
    </div>
    <div class="scene-list" :class="{hidden:store.state.isFullscreen}">
      <h3><RadarChartOutlined>切换使用场景</RadarChartOutlined> </h3>
      <div class="scenes">
          <div class="scene-item"
               v-for="(scene,index) in data.scenes"
               @click="changeHdr(scene,index)">
            <img  :class="{ active : index == data.sceneIndex }" :src="`./files/hdr/${scene}.jpg`" :alt="scene">
          </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import Loading from "../components/Loading.vue";
import {
  SketchOutlined,
  RadarChartOutlined,
  ShoppingCartOutlined,
} from "@ant-design/icons-vue";
import { useRoute } from 'vue-router'
import {onMounted, reactive} from 'vue'
import * as api from '../api/index.js'
import {useStore} from 'vuex'
const route = useRoute();
const store = useStore();
console.log(route)
const data = reactive({
  products :[],
  isLoading:true,
  scenes:[],
  pIndex:0,
  sceneIndex: 0
})
//生命周期函数x
onMounted(async () => {
  //await  等待数据返回结果  ,使用await 的同时 必须使用async
  let result = await api.getProducts()
  console.log(result);
  data.isLoading = false;
  data.products = result.list;
  data.scenes = result.hdr;

})
function changeModel(prod,pI){
  data.pIndex = pI;
}
function changeHdr(scene,index){
  data.sceneIndex = index;
}
window.addEventListener('mousewheel' ,(e)=>{
 // console.log(e)
    if(e.deltaY > 0){
      store.commit("getFullScreen",true)
    }
    if(e.deltaY < 0){
      store.commit("getFullScreen",false)
    }
})
</script>


<style lang="less" scoped>
.desc {
  position: fixed;
  z-index: 100000;
  background-color: rgba(255, 255, 255, 0.5);
  width: 600px;
  top: 100px;
  left: 50%;
  margin-left: -300px;
  transition: all 0.5s;

  transform: translate(-100vw, 0);
  padding: 15px;
}
.desc.active {
  transform: translate(0, 0);
}
.prod-list {
  width: 300px;
  height: 100vh;
  padding: 60px 0 0;
  position: fixed;
  z-index: 100000;
  transition: all 0.5s;
  background-color: rgba(255, 255, 255, 0.8);
  left: 0;
  top: 0;
  h1 {
    font-size: 20px;
    font-weight: 900;
    padding: 10px 25px 0;
  }
  .products {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    .prod-item {
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      width: 250px;
      background-color: #fff;
      border-radius: 20px;
      overflow: hidden;
      margin: 10px 0;
      box-shadow: 2px 2px 5px #666;
      transition: all 0.3s;
      &.active {
        box-shadow: 2px 2px 5px #666, 0px 0px 10px red;
      }
      &:hover {
        transform: translate(0px, -5px);
        box-shadow: 2px 2px 5px #666, 0px 0px 10px orangered;
        // background-color: orange;
      }
      img {
        width: 190px;
      }
      .prod-title {
        padding: 0 20px;
      }
    }
  }
}
.prod-list.hidden {
  transform: translate(-100%, 0);
}
.scene-list {
  width: 300px;
  height: 100vh;
  padding: 60px 0 0;
  position: fixed;
  z-index: 100000;
  transition: all 0.5s;
  background-color: rgba(255, 255, 255, 0.8);
  right: 0;
  top: 0;
  h3 {
    font-size: 20px;
    font-weight: 900;
    padding: 0 30px;
  }
  .scenes {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
  }
  .scene-item {
    padding: 6px 0;
    img {
      width: 250px;
      border-radius: 10px;
      box-shadow: 2px 2px 10px #666;
      transition: all 0.3s;
      &.active {
        box-shadow: 2px 2px 5px #666, 0px 0px 10px red;
      }
      &:hover {
        transform: translate(0px, -5px);
        box-shadow: 2px 2px 5px #666, 0px 0px 10px orangered;
      }
    }
  }
}
.scene-list.hidden {
  transform: translate(100%, 0);
}
</style>

在这里插入图片描述

11、使用Vuex状态管理完成购物车模块

在这里插入图片描述


在这里插入图片描述

 buycarts:[]
 addBuycarts(state,payload){
            state.buycarts.push(payload)
        },
        addBuycartsNum(state,payload){
            state.buycarts[payload].num++
        },
        minusBuycartsNum(state,payload){
            state.buycarts[payload].num--;
            if(state.buycarts[payload].num == 0){
                state.buycarts.splice(payload,1);//删除对应的内容
            }
        }
    getters:{
        totalPrice(state){
            let total = state.buycarts.reduce((pre,item) =>{  //reduce数组进行求和
                return pre + item.price * item.num;
            },0);
            return total;
        },
    },

设置加入购物车

在这里插入图片描述

<a-button type="primary" block @click.stop="addBuycart(prod)">
            <template #icon>
              <ShoppingCartOutlined></ShoppingCartOutlined>
            </template>
            加入购物车
          </a-button>

在这里插入图片描述

function addBuycart(prod){
  let product = {...prod,num:1};
  store.commit('addBuycarts',product)
}

完善购物车样式

在这里插入图片描述


<style>
.ant-menu-submenu {
  z-index: 1000000000 !important;
}

body .ant-menu-sub .ant-menu-item {
  height: auto;
}
.ant-menu-sub .ant-menu-item .prod-item {
  display: flex;
  width: 400px;
  justify-content: space-between;
}
.ant-menu .prod-item img {
  width: 100px;
  height: 100px;
}
.ant-menu-item .prod-item .middle {
  width: 220px;
  height: 100px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.ant-menu-item .prod-item .middle .title {
  font-size: 16px;
  font-weight: 900;
}
.ant-menu-item .prod-item .middle .content {
  display: flex;
  justify-content: space-between;
}
.ant-menu-item .prod-item .middle .btn {
  display: inline-block;
  width: 30px;
  height: 30px;
  text-align: center;
  line-height: 30px;
  border: 1px solid #ccc;
  margin: 0 5px;
}
.ant-menu-item .prod-item .right .price {
  font-weight: 900;
  color: orange;
  font-size: 16px;
  display: flex;
  justify-content: center;
  align-items: center;
}
.ant-menu-item .total {
  font-weight: 900;
  display: flex;
  justify-content: flex-end;
  font-size: 16px;
}
.ant-menu-item .total .num {
  color: orange;
  padding-right: 20px;
}
</style>

访问:http://127.0.0.1:5173/#/product/212121212
添加商品

在这里插入图片描述


在这里插入图片描述


完善功能实现重复商品添加购物车(累加数量)

在这里插入图片描述

function addBuycart(prod){
  let product = {...prod,num:1};
  let index = 0;
  let isExist = store.state.buycarts.some((item,i)=>{
    if(product.id == item.id){
      index = i
      return true
    }else {
      return false
    }
  })
  if(isExist){
    store.commit('addBuycartsNum',index)
  }else {
    store.commit('addBuycarts',product)
  }
}

在这里插入图片描述


在这里插入图片描述

相关文章

学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习...
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面...
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生...
Can’t connect to local MySQL server through socket \'/v...
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 ...
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服...