Vue 流程 Vuecil脚手架安装 依次安装Node.js、Vue、Vuecli
安装脚手架
检查版本
创建项目
图形化界面
项目结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ├── node_modules ├── public │ ├── favicon.ico: 页签图标 │ └── index.html: 主页面 ├── src │ ├── assets: 存放静态资源 │ │ └── logo.png │ │── component: 存放组件 │ │ └── HelloWorld.vue │ │── App.vue: 汇总所有组件 │ │── main.js: 入口文件 ├── .gitignore: git版本管制忽略的配置 ├── babel.config.js: babel的配置文件 ├── package.json: 应用包配置文件 ├── README.md: 应用描述文件 ├── package-lock.json:包版本控制文件
路由 Vue为只有一个index.html作为单页面,会用路由实现多页面的跳转,路由则将路径和页面进行映射
路由:router包下面写index.js文件并附上path和name(注意!!!path: ‘/‘也就代表了网页的第一个页面是什么 )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 import Vue from 'vue' import VueRouter from 'vue-router' import HomeView from '../views/HomeView.vue' Vue .use (VueRouter )const routes = [ { path : '/' , name : 'home' , component : HomeView }, { path : '/about' , name : 'about' , component : () => import ( '../views/AboutView.vue' ) } ] const router = new VueRouter ({ routes }) export default router
路由在组件中的使用:
1 2 3 4 5 <li><router-link :to="{ name: 'home' }">首页</router-link></li> <li> <router-link :to="{ name: 'bookclass' }"> 全部作品 </router-link> </li> <li><router-link :to="{ name: 'bookRank' }">排行榜</router-link></li>
当你点击 <router-link>
时, router.push
方法会在内部调用,所以说,点击<router-link :to="...">
等同于调用 router.push(...)
1 2 3 4 5 6 7 8 // 字符串 router.push('home') // 对象 this.$router.push({path: '/login?url=' + this.$route.path}); // 命名的路由 router.push({ name: 'user', params: { userId: 123 }})
路由在父组件App.vue的
1 2 3 4 5 6 7 8 9 10 <template> <div id="app"> <router-view /> </div> </template> <script> export default { name: 'App' } </script>
在views包下写主要页面,再在如Home.vue里引入components(当然组件自己也可以引用自己)
1 2 3 4 5 6 <template> <div class="header"> <Top /> <Navbar /> </div> </template>
引用组件时要记得注册组件,并引入文件位置
1 2 3 4 5 6 7 8 9 10 11 <script> import Navbar from "@/components/common/Navbar"; import Top from "@/components/common/Top"; export default { name: "Header", components: { Navbar, Top, }, }; </script>
Css的引入 在assets包(静态资源管理包)下建立css包并命名global.css
1 2 3 4 html , body , div { margin : 0 ; padding : 0 ; }
随后在main.js中引入
1 import '@/assets/css/global.css' ;
axios Axios 是一个基于 promise 网络请求库,这不是一种新技术,本质上还是对原生XMLHttpRequest的封装,用来实现Ajax(异步网络请求。Ajax能够让页面无刷新的请求数据,由来是浏览器页面在向服务器请求数据时,因为返回的是整个页面的数据,页面都会强制刷新一下,这对于用户来讲并不是很友好。并且我们只是需要修改页面的部分数据,但是从服务器端发送的却是整个页面的数据,十分消耗网络资源。而我们只是需要修改页面的部分数据,也希望不刷新页面,因此异步网络请求就应运而生。)
安装
最基础需要写比较长的配置来使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 <script> <!-- 方法一 --> axios({ method:"get", url:"https://www.baidu.com", data:user_id=7 }).then(res => { console.log(res.data); }) <!-- 方法二 --> axios.get("https://www.baidu.com").then(res => { this.obj= res.data[0]; console.log(res.data); }) </script>
也可以全局注册后使用(这里不展开)
但是一般在请求数量增多时会需要来进行封装axios来简化开发
在utils下创建request.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 import axios from 'axios' import router from '@/router' import { ElMessage } from 'element-plus' import { getToken, removeToken, removeNickName, setToken } from '@/utils/auth' axios.defaults .baseURL = process.env .VUE_APP_BASE_API_URL axios.defaults .timeout = 10000 axios.defaults .withCredentials = true axios.defaults .headers ['X-Requested-With' ] = 'XMLHttpRequest' axios.defaults .headers .post ['Content-Type' ] = 'application/json' axios.interceptors .request .use (config => { config.headers ['Authorization' ] = getToken () return config }, error => { console .log (error) Promise .reject (error) }) axios.interceptors .response .use (res => { if (typeof res.data !== 'object' ) { ElMessage .error ('服务端异常!' ) return Promise .reject (res) } if (res.data .code != "00000" ) { if (res.data .message ) { ElMessage .error (res.data .message ) } if (res.data .code == 'A0230' ) { removeToken (); removeNickName (); router.push ({ path : '/login' }) } return Promise .reject (res.data ) } return res.data }, error => { ElMessage .error ('网络异常!' ) console .log (error) Promise .reject (error) }) export default axios
在main.js中注册
1 2 3 4 5 6 7 8 import axios from './util/axios' ;import { createApp } from 'vue' import App from './App.vue' const app = createApp (App );app.use (store) .use (router) .mount ('#app' ) app.config .globalProperties .$axios = axios;
封装api在api包下
1 2 3 4 5 6 7 8 9 import request from '../utils/request' export function listHomeBooks ( ) { return request.get ('/front/home/books' ); } export function getBookById (bookId ) { return request.get (`/front/book/${bookId} ` ); }
然后在vue的生命周期函数里调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 <script> <!--导入--> import { reactive, toRefs, onMounted } from "vue"; import { useRouter, useRoute } from "vue-router"; import { listHomeBooks } from "@/api/home"; <!--注册组件--> export default { name: "home", components: { Header, LatestNews, FriendLink, BookVisitRank, BookNewestRank, BookUpdateRank, Footer, }, setup() { <!--route是一个跳转的路由对象,每一个路由都会有一个route对象,是一个局部的对象,可以获取对应的name,path,params,query等:--> const route = useRoute(); <!--router是VueRouter的一个对象,通过Vue.use(VueRouter)和VueRouter构造函数得到一个router的实例对象,这个对象中是一个全局的对象,包含了所有的路由包含了许多关键的对象和属性。例如history对象$router.push({path:’/path’}); 本质是向history栈中添加一个路由,在我们看来是 切换路由,但本质是在添加一个history记录--> const router = useRouter(); <!--reactive()函数接收一个普通对象,返回一个响应式的数据对象。访问: state.参数名--> const state = reactive({ // 轮播图 sliderContent: [], // 顶部栏 topBooks1: [], //本周强推 weekcommend: [], // 热门推荐 hotRecommend: [], // 精品推荐 goodRecommend: [], imgBaseUrl: process.env.VUE_APP_BASE_IMG_URL, }); <!--生命周期函数--> onMounted(async () => { const loadingInstance = ElLoading.service({ target: "#topBooks2", text: "加载中。。。", }); <!--等待listHomeBooks()方法传来数据给data--> const { data } = await listHomeBooks(); <!--可能book和v-for的item相似,属于别名,这段的意思就是从--> await data.forEach((book) => { if (book.type == 0) { // 轮播图 state.sliderContent[state.sliderContent.length] = book; } if (book.type == 1) { // 顶部栏 state.topBooks1[state.topBooks1.length] = book; } if (book.type == 2) { //本周强推 state.weekcommend[state.weekcommend.length] = book; } if (book.type == 3) { //热门推荐 state.hotRecommend[state.hotRecommend.length] = book; } if (book.type == 4) { //精品推荐 state.goodRecommend[state.goodRecommend.length] = book; } }); <!--push就是在浏览器的历史记录中追加一个新的记录,你可以通过window.history看到这个记录。而replace则是将当前的路由记录替换掉,替换后你如果回退,会发现上一个路由地址已经消失了。此处是点击链接后触发的方法,将跳转到小说的详情页--> const bookDetail = (bookId) => { router.push({ path: `/book/${bookId}` }); }; <!--toRefs将一个响应式对象,转换为普通对象,并且将其中的属性转换为 Ref 对象,与reactive搭配使用,reactive将数据变成响应式数据,当数据发生变化时state也会自动更新--> return { ...toRefs(state), bookDetail, }; } }; </script>
Vue3与Vue2的不同 Vite脚手架的安装 1 2 3 4 5 6 7 8 npm init vite-app vue3_test-vitecd vue3_test-vite npm install npm run dev
分析文件目录 main.js Vue2项目的main.js
1 2 3 4 5 6 7 8 import Vue from 'vue' import App from './App.vue' Vue.config.productionTip = false new Vue({ render: h => h(App), }).$mount('#app')
我们再来看看Vue3项目中的main.js
1 2 3 4 import { createApp } from 'vue' import App from './App.vue' createApp(App).mount('#app')
分析一下
1 2 3 4 5 6 7 8 9 // 引入的不再是Vue构造函数了,引入的是一个名为createApp的工厂函数 import { createApp } from 'vue' import App from './App.vue' // 创建应用实例对象——app(类似于之前Vue2中的vm,但app比vm更“轻”) const app = createApp(App) console.log(app) // 挂载 app.mount('#app')
App.vue 我们再来看看组件
在template
标签里可以没有根标签了
1 2 3 4 5 <template> <!-- Vue3组件中的模板结构可以没有根标签 --> <img alt="Vue logo" src="./assets/logo.png"> <HelloWorld msg="Welcome to Your Vue.js App"/> </template>
setup函数 代替了Vue2的data()以及method
vue基础 ref 一、ref函数的引入
import { ref } from ‘vue’
二、什么是 ref
1、ref 和 reactive 一样都是实现响应式数据的方法
2、由于 reactive 必须传递一个对象,所以导致我们再企业开发中,如果我们只想让某个变量实现响应式的时候非常麻烦,所以 Vue3 就提供了 ref 方法,实现对简单值的监听
三、ref 的本质
const input = ref(‘’)
ref 底层的本质还是 reactive 系统会自动根据我们给 ref 传入的值将他转换成 ref(xx) —— reactive({value: xx})
四、ref 注意点
1、在 VUE 的模板中使用 ref 的值不需要通过 value 获取 (Vue 会通过自动给 ref 的值加上 .value)
2、在 js 中使用 ref 的值必须使用 .value 获取’
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <template> <uni-popup ref="popup" type="dialog"> <!--mode="base"为对话框加两个按钮的形式--> <uni-popup-dialog mode="base" title="确定要放弃吗?" content="本次计时将不会得到任何分数" :duration="2000" :before-close="true" @close="close" @confirm="confirm"></uni-popup-dialog> </uni-popup> </template> <script setup> let popup = ref(null); //记着赋初值,本质是reactive({value:null}) const timeEnd = () => { popup.value.open() //记得.value然后调用函数 } const confirm = () => { popup.value.close() } const close = () => { popup.value.close() } </script>
v-for 在v-for中使用字符串
string:data中的源数据字符串,
str:data数据string字符串的每一个,
index:string字符串索引
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <div id="app"> <!-- 这里表示被vue控制的区域 --> <ul> <li v-for="(str, index) in string"> {{ index }}---{{ str }} </li> </ul> </div> <script> const vm = new Vue({ el: '#app', // 控制id为app的元素 data: { // 存放所需要的数据 string: 'abcdefgh' } }) </script>
实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 <template> <div class="sliderContent"> <dl class="scBigImg" id="carouseBig"> <dd v-for="(item, index) in sliderContent" :key="index" :class="{ on: index == 0 }"> <!-- 点击触发bookDetail函数,传入sliderContent.bookid,并在最后使用push来跳转到小说的详情页 --> <a href="javascript:void(0)" @click="bookDetail(item.bookId)"> <img :src="`${imgBaseUrl}` + `${item.picUrl}`" :alt="item.bookName" onerror="this.src='default.gif';this.onerror=null" /> </a> </dd> </dl> </div> </template>
其中
sliderContent:data中的源数据数组(会从数据库中获得),
item:data数据list数组的别名,
index:list数组索引,即为数据数字的多少
函数传入数据: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 //targetNoTimeDelete(index)来传入数据index,方便下面接收 <view class="targetMenuDetailD" v-for="(item, index) in state.targetNoTime" :key="index" @click="targetNoTimeDelete(index)"> <text>{{item.targetName}}</text> <view class="targetMenuDetailDI"> <img src="@\static\coin.svg" style="width: 34rpx;height:34rpx;"> <text>X{{item.targetPoint}}</text> </view> <text>任意时间</text> </view> <script setup> //记忆一下书写方式 const targetNoTimeDelete = (index) => { uni.request({ url: 'http://localhost:8181/target/delete', method: "POST", data: { targetName: state.targetWithTime[index].targetName, ifPoints: 1, }, success: (res) => { console.log(res) // 从targetWithTime数组中移除已删除的目标数据 state.targetWithTime.splice(index, 1); user.data.point = res.data.data.targetPoint } }) } </script>
route.params.categoryId的用法 route.params.url参数
url参数来自于:categoryId(要求与该变量完全一致,卡了半小时QAQ)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const routes = [ { path : '/:categoryId' , name : 'bookcategory' , component : () => import ('@/views/BookCategory' ) }, ] const router = createRouter ({ history : createWebHashHistory (), routes }) export default router
正式使用:
在onMounted生命周期函数里,就用变量来接,之后要记得放进带参数的变量里,还是要求id参数一致
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 <script> import { reactive, toRefs, onMounted } from "vue"; import { useRouter, useRoute } from "vue-router"; import { listHomeCategoryId } from "@/api/home"; export default { name: "home", setup() { const route = useRoute(); const router = useRouter(); const state = reactive({ // 分类推荐 catagorycommendId: [], }); onMounted(async () => { const categoryId = route.params.categoryId-2; dataCategoryId(categoryId); }); const dataCategoryId = async (categoryId) => { const { data } = await listHomeCategoryId(categoryId); await data.forEach((book) => { { //历史推荐 state.catagorycommendId[state.catagorycommendId.length] = book; } }); } return { ...toRefs(state), dataCategoryId, }; } } </script>
组件 组件是.vue的单文件组件,实现代码复用,以及理顺css以及js之间的关系,可以用script setup这样就可以在引入之后自动注册组件
选项式api 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 <script> //js对象 export default { name: "targetMenu", //实例对象的属性 data() { //返回出去的才是响应式数据 return { showFocusAfter: true, showTargetAfter: false, showTargetBefore: true, showFocusBefore: false, }; }, //实例对象的方法 methods() { const menuItems = this.$route.meta.menuItems || [] if (menuItems.includes('target')) { this.showFocusAfter = false; this.showTargetBefore = false; this.showTargetAfter = true; this.showFocusBefore = true; } }, }; </script>
组合式api 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 <script> //使用setup,可以直接写变量,但是只是普通变量,需要通过const state = reactive({hotRecommend: [], });来变成响应式变量,也可以用ref(),可以接收任何值,不止于此对象,把数据转化为{value:0} import { reactive, toRefs, onMounted } from "vue"; import { useRouter, useRoute } from "vue-router"; import Header from '@/components/Header'; import Footer from '@/components/Footer'; import { listHomeBooks, listHomeCategory,listHomeCategory2,listHomeCategory3,listHomeCategory4 } from "@/api/home"; import { getBookById, } from "@/api/book"; import { SetUp } from '@element-plus/icons-vue'; export default { name: "home", components: { Header, Footer, }, setup() { const route = useRoute(); const router = useRouter(); const state = reactive({ // 热门推荐 hotRecommend: [], // 精品推荐 goodRecommend: [], // 分类推荐 catagorycommend: [], catagorycommend2: [], catagorycommend3: [], catagorycommend4: [], imgBaseUrl: process.env.VUE_APP_BASE_IMG_URL, }); onMounted(async () => { const { data } = await listHomeBooks(); await data.forEach((book) => { if (book.type == 3) { //热门推荐 state.hotRecommend[state.hotRecommend.length] = book; } if (book.type == 4) { //精品推荐 state.goodRecommend[state.goodRecommend.length] = book; } }); dataCategory(); dataCategory2(); dataCategory3(); dataCategory4(); }); const bookDetail = (bookId) => { router.push({ path: `/book/${bookId}` }); }; const dataCategory = async () => { const { data } = await listHomeCategory(); await data.forEach((book) => { if (book.categoryName == "历史军事") { //历史推荐 state.catagorycommend[state.catagorycommend.length] = book; } }); } const dataCategory2 = async () => { const { data } = await listHomeCategory2(); await data.forEach((book) => { if (book.categoryName == "科幻灵异") { //历史推荐 state.catagorycommend2[state.catagorycommend2.length] = book; } }); } const dataCategory3 = async () => { const { data } = await listHomeCategory3(); await data.forEach((book) => { if (book.categoryName == "都市言情") { //历史推荐 state.catagorycommend3[state.catagorycommend3.length] = book; } }); } const dataCategory4 = async () => { const { data } = await listHomeCategory4(); await data.forEach((book) => { if (book.categoryName == "玄幻奇幻") { //历史推荐 state.catagorycommend4[state.catagorycommend4.length] = book; } }); } return { ...toRefs(state), bookDetail, dataCategory, }; } } </script>
v-bind 当需要在属性内使用动态数据的时候则需要使用v-bind,标签内则可以直接使用双大括号,可简写为:
1 2 3 4 5 6 7 <template> <img v-bind:src="imgPath"/> </template> //简写 <template> <img :src="imgPath"/> </template>
style scoped 这样设置会成为局部样式
1 2 3 4 5 6 7 8 9 10 <style scoped lang="scss"> .menu { width: 200px; margin-left: 20px; } .menuButton { margin-top: 50px; } </style>
style module css 变成模块,通过:class=”$style.box1”使用
v-on v-on:click简写为@click
v-model 双向绑定
此处还采用了pinia集中管理状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <view class="LoginInput"> <text>你的邮箱</text> <input v-model="user.data.userEmail" name="txtEmail" type="text" id="txtPassword" placeholder="请输入邮箱" class="LoginInputIn"> </view> <view class="LoginP"> <text>登陆</text> <text>将使用{{user.data.userEmail}}登陆</text> </view> <script setup> import { useUserStore } from "../../store/user"; const user = useUserStore() </script>
store Router 引入 1 import {useRoute,useRouter} from 'vue-router' ;
使用 1 2 3 4 5 6 7 const route = useRoute ();const router = useRouter ();const HomeR = ( ) => { router.push ({ path : `/Login` }); }
Route 引入 1 import {useRoute,useRouter} from 'vue-router' ;
使用 1 2 3 const route = useRoute ();const router = useRouter ();const id = route.params .id ;
params props 在组合式api和setup语法糖中需要按下面的方式进行定义
1 2 3 4 5 6 7 8 <script setup> const props = defineProps({ navbarTo: { type: String, required: true } }) </script>
组件传参 1、组件内定义props
1 2 3 4 5 6 7 8 <script setup> const props = defineProps({ navbarTo: { type: String, required: true } }) </script>
2、在需要使用组件的部分进行数据双向绑定
1 <Navbar :navbarTo="'/menu/2'"></Navbar>
路由传参 1、定义参数:router-link :to=“params”
1 2 3 4 5 <a href="#"> router-link :to="props.navbarTo"> <img src="@\assets\Filter.png" alt="#"> </router-link> </a>
2、接收参数
1 2 const route = useRoute ();const id = route.params .id ;
v-if 1、在需要控制出现与否的标签上加上v-if(注意不需要双向绑定 :,但是要加上state.)
1 2 3 4 <FocusAfter v-if="state.showFocusAfter"></FocusAfter> <TargetBefore v-if="state.showTargetBefore"></TargetBefore> <FocusBefore v-if="state.showFocusBefore"></FocusBefore> <TargetAfter v-if="state.showTargetAfter"></TargetAfter>
2、通过响应式的数据,更改标签出现与否
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const route = useRoute ();const state = reactive ({ showFocusAfter : true , showTargetBefore : true , showFocusBefore : false , showTargetAfter : false , }); const id = route.params .id ;if (id == 2 ) { state.showFocusAfter = false ; state.showTargetBefore = false ; state.showFocusBefore = true ; state.showTargetAfter = true ; }
依赖注入 用于父组件和子组件的数据传递(但是只能用于父组件和子组件)
父组件
1 2 3 4 import {provide} from "vue" ;provide : { message : '这是祖先组件提供的消息' },
子组件
1 2 3 4 import {inject} from 'vue' ;provide : { message : '这是祖先组件提供的消息' },
pinia 在面对多组件内传参的情况下,可以使用集中的状态管理pinia对应vue2的vuex
1、创建store文件夹下的js文件进行后续定义
2、定义状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import { defineStore } from "pinia" export const useUserStore = defineStore ('user' , { state : () => ({ data : { userEmail : "" , userName : "" , userPassword : "" , userCode : "" } }), actions : {} })
3、在所需要该状态的组件内进行引用和使用
1 2 3 4 5 6 7 8 import { useUserStore } from "../../store/user" ; const state = reactive ({}) const user = useUserStore () console .log (user.data .userEmail )
computed 1 2 3 4 5 6 7 8 9 10 11 12 const formattedTime = computed (() => { state.hours = Math .floor (state.remainingTime / 3600 ); state.minutes = Math .floor ((state.remainingTime % 3600 ) / 60 ); state.seconds = Math .floor (state.remainingTime % 60 ); return `${formatTime(state.hours)} :${formatTime(state.minutes)} :${formatTime(state.seconds)} ` ; });
js基础 时间类函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 let time = new Date ()let myDate = time.getDate ()let dayNum = time.getDay ()let myMonth = time.getMonth ()const selectedDate = new Date (time.getFullYear (), state.dayList [0 ].month , 1 );time = new Date (selectedDate); for (let i = 0 ; i < 30 ; i++) { time.setDate (time.getDate () + 1 ) state.dayList .push ({ 'day' : time.getDate (), 'month' : time.getMonth (), 'week' : weeks[time.getDay ()], 'className' : 'Num' }) } time.setDate (time.getDate () + 1 ) time.setDate (state.dayList [index].day ) time.setMonth (state.dayList [index].month ) let currentTime = new Date (target.data .currentTime )let timeDiff = item.getTime () - currentTime.getTime ()let dayDiff = Math .floor (timeDiff / (1000 * 3600 * 24 ))
数组 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 const state = reactive ({ dayList : [] }); target.data .deadlineDate .forEach ((item ) => { let currentTime = new Date (target.data .currentTime ) let timeDiff = item.getTime () - currentTime.getTime () let dayDiff = Math .ceil (timeDiff / (1000 * 3600 * 24 )) }); state.dayList .push ({ 'day' : time.getDate (), 'month' : time.getMonth (), 'week' : weeks[time.getDay ()], 'className' : 'Num' }) const targetNoTimeDelete = (index ) => { state.targetWithTime .splice (index, 1 ); }
字符串拼接 1 2 3 4 5 6 7 8 9 const hours = item.getHours ();const minutes = item.getMinutes ();const timeString = `${hours} :${minutes.toString().padStart(2 , '0' )} ` const month = item.getMonth () + 1 ; const date = item.getDate (); dayDiff = `${month} .${date} ` ;
math函数 1 2 3 4 5 6 let dayDiff = Math .floor (timeDiff / (1000 * 3600 * 24 ))let dayDiff = Math .ceil (timeDiff / (1000 * 3600 * 24 ))let dayDiff = Math .trunc (timeDiff / (1000 * 3600 * 24 ))
substr 1 2 3 4 5 6 const str = "Hello, world!" ;console .log (str.substr (7 )); console .log (str.substr (-6 )); console .log (str.substr (7 , 5 ));
练习 数组刷新重复输入问题 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 onMounted ( uni.request ({ url : 'http://localhost:8181/target/get' , method : "POST" , data : user.data .userEmail , success : (res ) => { target.data .deadlineDate = [] for (let i = 0 ; i < res.data .data .length ; i++) { if (res.data .data [i].status == 0 ) { state.targetNoTime .push ({ 'targetName' : res.data .data [i].targetName , 'targetDescribe' : res.data .data [i].targetDescribe , 'targetPoint' : res.data .data [i].targetPoint , 'deadline' : res.data .data [i].deadline , }) } else if (res.data .data [i].status == 1 ) { let deadline = new Date (res.data .data [i].deadline ) if (!target.data .deadlineDate .includes (deadline)) { target.data .deadlineDate .push (deadline); } state.targetWithTime .push ({ 'targetName' : res.data .data [i].targetName , 'targetDescribe' : res.data .data [i].targetDescribe , 'targetPoint' : res.data .data [i].targetPoint , 'deadline' : res.data .data [i].deadline , }) } else if (res.data .data [i].status == 2 ) { state.targetCompleted .push ({ 'targetName' : res.data .data [i].targetName , 'targetDescribe' : res.data .data [i].targetDescribe , 'targetPoint' : res.data .data [i].targetPoint , 'deadline' : res.data .data [i].deadline , }) } else if (res.data .data [i].status == 3 ) { state.targetExpire .push ({ 'targetName' : res.data .data [i].targetName , 'targetDescribe' : res.data .data [i].targetDescribe , 'targetPoint' : res.data .data [i].targetPoint , 'deadline' : res.data .data [i].deadline , }) } } } }) )
后端交互完前端页面不更新问题 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 const targetNoTimeDelete = (index ) => { uni.request ({ url : 'http://localhost:8181/target/delete' , method : "POST" , data : { targetName : state.targetWithTime [index].targetName , ifPoints : 1 , }, success : (res ) => { console .log (res) state.targetWithTime .splice (index, 1 ); user.data .point = res.data .data .targetPoint } }) }
关于点击转换样式的练习 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 //关键在于通过数组的方式,使得每个v-for生成的元素都有它独立的className:state.dayList[index].className //这样就可以通过改变特定的className,来达成效果 <template> <view class="tagetDay"> <scroll-view class="scroll-view" scroll-x="true" enable-flex="true"> <view class="Mon" v-for="(item, index) in state.dayList" :key="index" @click="classChange(index)"> <text>{{item.week}}</text> <view :class="item.className"> <text class="Num">{{item.day}}</text> </view> </view> </scroll-view> </view> </template> <script setup> const state = reactive({ dayList: [] }); state.dayList.push({ 'className': 'NumCenter' }) for (let i = 0; i < 30; i++) { time.setDate(time.getDate() + 1) state.dayList.push({ 'className': 'Num' }) } const classChange = (index) => { state.dayList.forEach((item) => { item.className = "Num"; // 先将所有日期的 className 属性设置为 Num }); state.dayList[index].className = "NumCenter"; // 将点击的日期的 className 属性设置为 NumCenter }; </script>
前端获取不到初值的原因 使用中经常出现,赋不上初值的问题,需要在刷新时才能获取到数据,在通过打印后发现,网络请求返回前,初值已经赋上,解决方法就是在需要该数据的前一个页面就要加上请求语句,获取到所有的数据(clock的bug QAQ)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 <script setup> const home = () => { uni.request({ url: 'http://localhost:8181/user/home', method: "POST", data: user.data.userEmail, success: (res) => { if (res.data.code != null) { uni.redirectTo({ url: '../../pages/Login/Login' }); } else { uni.redirectTo({ url: '../../pages/Sign/Sign' }); } } }) //后续需要的tag数据 uni.request({ url: 'http://localhost:8181/tag/get', method: "POST", data: user.data.userEmail, success: (res) => { console.log(res) tag.data.tagName = res.data.data[0].tagName tag.data.tagDescribe = res.data.data[0].tagDescribe tag.data.tagPoint = res.data.data[0].tagPoint tag.data.tagHour = res.data.data[0].tagHour tag.data.tagMinute = res.data.data[0].tagMinute } }) //此处的time.data.remainingTime其实还是零,原因就是上面所说的,所以在下一个页面有相同的语句,获取到time.data.remainingTime的初值,此处因为在需要数据的页面前有两个页面才能完成需求,不知道有没有其他办法来优化 time.data.remainingTime = (tag.data.tagHour * 3600) + (tag.data.tagMinute * 60) + tag.data.tagSecond } </script>