Vue3学习笔记

Vue3官网:https://v3.cn.vuejs.org/

Vue3 One Piece:https://vue3js.cn/#emits

菜鸟教程:https://www.runoob.com/vue3/vue3-tutorial.html

什么是Vue?

Vue是一套用于构建用户界面的渐进式框架

Vue.js设计的初衷就包括可以被渐进式地采用。这意味着它可以根据需求以多种方式集成到一个项目中。

cnpm(中国 NPM 镜像)

cnpm官网:https://npmmirror.com/

安装cnpm

npm install -g cnpm --registry=https://registry.npmmirror.com

使用cnpm安装模块

cnpm install [name]

Vue CLI

Vue CLI旨在成为Vue生态系统的标准工具基准。它可确保各种构建工具与合理的默认值一起顺利运行,因此您可以专注于编写应用程序,而不是花费数天时间与配置进行争论。同时,它仍然提供了调整每个工具配置的灵活性,而无需弹出。

安装新程序包

cnpm install -g @vue/cli
cnpm install -g vue-cli
cnpm : 无法加载文件 C:\Users\Xiaoyu.Zhang\AppData\Roaming\npm\cnpm.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID=135170 中的 about_Executio
n_Policies。
所在位置 行:1 字符: 1
+ cnpm install -g vue-cli
+ ~~~~
    + CategoryInfo          : SecurityError: (:) [],PSSecurityException
    + FullyQualifiedErrorId : UnauthorizedAccess

解决方案:

  1. 以管理员身份运行PowerShell

  2. 输入

    set-ExecutionPolicy RemoteSigned
    

    选择A

新建一个package.json文件并初始化

npm init -y

Vue项目中运行

vue upgrade --next

创建项目

vue create [app-name]

Vite

下一代前端开发与构建工具

Vite 是一个 web 开发构建工具,由于其原生 ES 模块导入方式,可以实现闪电般的冷服务器启动。

安装Vite

cnpm install vite

创建项目

npm init @vitejs/app

√ Project name: … vite-test
√ Select a framework: » vue
√ Select a variant: » vue-ts

Scaffolding project in D:\BSIT_Project\vue-vite-start\vite-project\vite-test…

Done. Now run:

cd vite-test
npm install
npm run dev

安装依赖

cd 项目名
npm i

运行项目

npm run dev

打开网页

http://localhost:3000/

目录结构

目录 / 文件说明
dist使用 npm run build 命令打包后会生成该目录。
node_modulesnpm 加载的项目依赖模块
public公共资源目录。
src这里是我们要开发的目录,基本上要做的事情都在这个目录里。里面包含了几个目录及文件:
assets: 放置一些图片,如logo等。
components: 目录里面放了一个组件文件,可以不用。
App.vue: 项目入口文件,我们也可以直接将组件写这里,而不使用 components 目录。
main.js: 项目的核心文件。
index.css: 样式文件。
index.html首页入口文件,你可以添加一些 meta 信息或统计代码啥的。
package.json项目配置文件。
README.md项目的说明文档,markdown 格式
tsconfig.json
vite.config.ts

配置

import {defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'
// @ts-ignore
import path from 'path';
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import {ElementPlusResolver} from 'unplugin-vue-components/resolvers'

// https://vitejs.dev/config/
export default defineConfig({
    plugins: [
        vue(),
        AutoImport({
            resolvers: [ElementPlusResolver()],
        }),
        Components({
            resolvers: [ElementPlusResolver()],
        }),
    ],
    // 在生产中服务时的基本公共路径。类似publicPath,'./'避免打包访问后空白页面,要加上,不然线上也访问不了
    base: "./",
    resolve: {
        // 目录别名
        alias: {
            "@": path.resolve(__dirname, "src"),
            "@assets": path.resolve(__dirname, "src/assets"),
            "@components": path.resolve(__dirname, "src/components"),
            "@img": path.resolve(__dirname, "src/assets/img"),
            "@views": path.resolve(__dirname, "src/views"),
            "@store": path.resolve(__dirname, "src/store"),
        },
    },
    // 打包配置
    build: {
        outDir: "dist",       // 指定输出路径
        assetsDir: "assets",  // 指定静态资源存放路径
        sourcemap: false,     // 是否构建source map 文件
        minify: 'terser',     // 混淆器,terser构建后文件体积更小
        terserOptions: {
            // 生产环境移除console
            compress: {
                drop_console: true,
                drop_debugger: true,
            },
        },
    },
    // 本地运行配置,及反向代理配置
    server: {
        cors: true,   // 默认启用并允许任何源
        https: false, // 是否开启 https
        open: true,   // 是否自动在浏览器打开
        port: 2048,   // 端口号
        host: "0.0.0.0",
        proxy: {
            "/api": {
                target: "", // 后台接口(代理接口)
                changeOrigin: true,
                secure: false, // 如果是https接口,需要配置这个参数
                // ws: true, //websocket支持
                rewrite: (path) => path.replace(/^\/api/, ""),
            },
        },
    },
    // 引入第三方的配置
    optimizeDeps: {
        include: ["axios",],
    },
})

构建应用

安装vue-tsc

cnpm install vue-tsc

构建

npm run build

Element Plus

官方文档:https://element-plus.gitee.io/zh-CN/

安装

cnpm install element-plus --save

自动导入

安装插件

cnpm install -D unplugin-vue-components unplugin-auto-import

vite.config.ts中添加

import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

export default {
  plugins: [
    // ...
    AutoImport({
      resolvers: [ElementPlusResolver()],
    }),
    Components({
      resolvers: [ElementPlusResolver()],
    }),
  ],
}

HelloWorld

App.vue

<template>
  <div>
    {{ msg }}
  </div>
  <div>
    {{ data.data }}
  </div>
</template>

<script>
export default {
  data() {
    return {
      msg: "hello world",
      data:{
        data:[1,2,3,4,5]
      }
    }
  }
}
</script>

Vue语法

插值

文本
<template>
  <div>
    {{ msg }}
  </div>
</template>

<script>
export default {
  data() {
    return {
      msg: "hello world",
    }
  }
}
</script>
原生html
<template>
  <p>Using v-html directive: <span v-html="rawHtml"></span></p>
</template>

<script>
export default {
  data() {
    return {
      rawHtml: '<span style="color: red">This should be red.</span>',
    }
  }
}
</script>
Attribute
<template>
  <h1 v-bind:id="msg">Hello World</h1>
</template>

<script>
export default {
  data() {
    return {
      msg: "hello world",
    }
  }
}
</script>
JavaScript 表达式

每个绑定都只能包含单个表达式

<template>
  <p>{{ number + 1 }}</p>
</template>

<script>
export default {
  data() {
    return {
      number:10,
    }
  }
}
</script>

处理用户输入

事件监听器

v-on 指令添加一个事件监听器

<template>
  <div id="event-handling">
    <p>{{ message }}</p>
    <button v-on:click="reverseMessage">反转 Message</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello Vue.js!'
    }
  },
  methods: {
    reverseMessage() {
      this.message = this.message
          .split('')
          .reverse()
          .join('')
    }
  }
}
</script>
双向绑定

v-model 指令实现表单输入和应用状态之间的双向绑定

<template>
  <div id="two-way-binding">
    <p>{{ message }}</p>
    <input v-model="message" />
  </div>
</template>

<script>
export default {
  data() {
    return {
      message: 'Hello Vue!'
    }
  }
}
</script>

条件与循环

条件控制

v-if 指令进行条件控制

<template>
  <div id="conditional-rendering">
    <span v-if="see">现在你看到我了</span>
  </div>
</template>

<script>
export default {
  data() {
    return {
      see: true,
      // see:false,
    }
  }
}
</script>

v-for 指令可以绑定数组的数据来渲染一个项目列表

<template>
  <div id="list-rendering">
    <ol>
      <li v-for="todo in todos">
        {{ todo.text }}
      </li>
    </ol>
  </div>
</template>

<script>
export default {
  data() {
    return {
      todos: [
        {text: 'Learn JavaScript'},
        {text: 'Learn Vue'},
        {text: 'Learn JavaScript'},
        {text: 'Learn Vue'},
        {text: 'Learn JavaScript'},
        {text: 'Learn Vue'},
        {text: 'Learn JavaScript'},
        {text: 'Learn Vue'},
        {text: 'Learn JavaScript'},
        {text: 'Learn Vue'},
        {text: 'Build something awesome'},
      ]
    }
  }
}
</script>

计算属性

为了避免在模板中放入太多的逻辑,使模板过重且难以维护,对于任何包含响应式数据的复杂逻辑,你都应该使用计算属性

<template>
  <div id="computed-basics">
    <p>Has published books:</p>
    <span>{{ publishedBooksMessage }}</span>
  </div>
</template>

<script>
export default {
  data() {
    return {
      author: {
        name: 'John Doe',
        books: [
          'Vue 2 - Advanced Guide',
          'Vue 3 - Basic Guide',
          'Vue 4 - The Mystery'
        ]
      }
    }
  },
  computed: {
    // 计算属性的 getter
    publishedBooksMessage() {
      // `this` 指向 vm 实例
      return this.author.books.length > 0 ? 'Yes' : 'No'
    }
  }
}
</script>

侦听器

当需要在数据变化时执行异步或开销较大的操作时,watch 选项提供了一个更通用的方法来响应数据的变化。

但是要避免侦听器的滥用!

<template>
  <div id="watch-example">
    <p>
      Ask a yes/no question:
      <input v-model="question" />
    </p>
    <p>{{ answer }}</p>
  </div>
</template>

<!--<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>-->
<script>
export default {
  data() {
    return {
      question: '',
      answer: 'Questions usually contain a question mark. ;-)'
    }
  },
  watch: {
    // 每当 question 发生变化时,该函数将会执行
    question(newQuestion, oldQuestion) {
      if (newQuestion.indexOf('?') > -1) {
        this.getAnswer()
      }
    }
  },
  methods: {
    getAnswer() {
      this.answer = 'Thinking...'
      axios
          .get('https://yesno.wtf/api')
          .then(response => {
            this.answer = response.data.answer
          })
          .catch(error => {
            this.answer = 'Error! Could not reach the API. ' + error
          })
    }
  }
}
</script>

选项式API

// src/components/UserRepositories.vue

export default {
  components: { RepositoriesFilters, RepositoriesSortBy, RepositoriesList },
  props: {
    user: { 
      type: String,
      required: true
    }
  },
  data () {
    return {
      repositories: [], // 1
      filters: { ... }, // 3
      searchQuery: '' // 2
    }
  },
  computed: {
    filteredRepositories () { ... }, // 3
    repositoriesMatchingSearchQuery () { ... }, // 2
  },
  watch: {
    user: 'getUserRepositories' // 1
  },
  methods: {
    getUserRepositories () {
      // 使用 `this.user` 获取用户仓库
    }, // 1
    updateFilters () { ... }, // 3
  },
  mounted () {
    this.getUserRepositories() // 1
  }
}

组合式API

<script lang="ts" setup>
import {ref, watch} from 'vue'
import {
  Location,
  Document,
  Menu as IconMenu,
  Setting,
} from '@element-plus/icons-vue'

// 定义一个变量
let isCollapse = ref(true)

// 定义方法
const handleOpen = (key: string, keyPath: string[]) => {
  console.log(key, keyPath)
}
const handleClose = (key: string, keyPath: string[]) => {
  console.log(key, keyPath)
}

const changeCollapse = () => {
  console.log("点击")
  isCollapse.value = !isCollapse.value
  return {
    isCollapse
  }
}

// 监听变量变化
watch(isCollapse, (newVal, oldVal) => {
  console.log(newVal, oldVal)
})
</script>

组件

定义子组件

src\componentsHelloWorld.vue

<template>
  <h1>{{ msg }}</h1>
</template>

<script lang="ts">
export default {
  name: "Hello World"!,
  props: {
    msg: String,
  }
}
</script>

<style>

</style>

src\componentsHelloWorld1.vue

<template>
  <h1>{{ msg }}</h1>
</template>

<script lang="ts">
export default {
  name: "HelloWorld1",
  props: {
    msg: String,
  }
}
</script>

<style>

</style>

src/App.vue

<template>
  <h2>组件测试</h2>
  <HelloWorld msg="HelloWorld组件"></HelloWorld>
  <HelloWorld1 msg="HelloWorld1组件"></HelloWorld1>
</template>

<script lang="ts">
import HelloWorld from "./components/HelloWorld.vue";
import HelloWorld1 from "./components/HelloWorld1.vue";

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

<style>

</style>
组件传值
父组件向子组件传值

通过props

Prop类型
  1. 数组形式

    props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
    
  2. 对象形式

    props: {
      title: String,
      likes: Number,
      isPublished: Boolean,
      commentIds: Array,
      author: Object,
      callback: Function,
      contactsPromise: Promise // 或任何其他构造函数
    }
    
静态传值
<blog-post title="My journey with Vue"></blog-post>
动态赋值
<!-- 动态赋予一个变量的值 -->
<blog-post :title="post.title"></blog-post>

<!-- 动态赋予一个复杂表达式的值 -->
<blog-post :title="post.title + ' by ' + post.author.name"></blog-post>
父子组件传值

父组件

<template>
  <h1>父组件</h1>
  <Child1 :msg="msg"></Child1>
  <Child2></Child2>
</template>

<script>


import Child1 from "./Child1.vue";
import Child2 from "./Child2.vue";

export default {
  name: "Parent",
  components: {
    Child1,
    Child2,
  },
  data() {
    return {
      msg: '你好',
    }
  },
}
</script>

<style scoped>

</style>

子组件

<template>
  <h2>子组件1</h2>
  <textarea>{{msg}}</textarea>
</template>

<script>
export default {
  name: "Child1",
  props: {
    msg: String,
  },
  setup(props) {
    console.log(props);
    return props
  }
}
</script>

<style scoped>

</style>
子组件向父组件传值

通过emit

子组件

<template>
  <h2>子组件2</h2>
</template>

<script>
export default {
  name: "Child2",
  // setup(props, context) {
  //   context.emit('setShow', false);
  //   return {}
  // },

  setup(props, {emit}) {
    emit('childEvent', "这是子组件传递过来的内容");
    return {}
  },
}
</script>

<style scoped>

</style>

父组件

<template>
  <h1>传值测试</h1>
  <Child1 :msg="msg"></Child1>
  <Child2 @childEvent="parentEvent"></Child2>
  <h2>{{name}}</h2>
</template>

<script>


import Child1 from "./Child1.vue";
import Child2 from "./Child2.vue";
import {ref} from "vue";

export default {
  name: "Parent",
  components: {
    Child1,
    Child2,
  },
  data() {
    return {
      msg: '你好',
      name: "",
    }
  },
  methods: {
    parentEvent(value) {
      this.name = value
    }
  }
}
</script>

<style scoped>

</style>

Vue Router

安装

cnpm install vue-router@4

新建Page1.vue

<template>
  <h1>Page1</h1>
  <p>{{ msg }}</p>
</template>

<script>
export default {
  name: "Page1",
  data() {
    return {
      msg: "Page组件"
    }
  }
}
</script>

<style scoped>

</style>

新建Page2.vue

<template>
  <h1>Page2</h1>
  <p>{{ msg }}</p>
</template>

<script>
export default {
  name: "Page2",
  data() {
    return {
      msg: "Page组件"
    }
  }
}
</script>

<style scoped>

</style>

src文件夹下新建router/index.ts

import {createRouter, createWebHashHistory} from "vue-router";
import page1 from '../components/Page1.vue';
import page2 from '../components/Page2.vue';
import Parent from "../components/Parent.vue";


// 定义routes路由的集合,数组类型
const routes = [
    // 单个路由均为对象类型,path代表的是路径,component代表组件
    {
        path: '/',
        redirect: '/index'
    },
    {
        path: '/index',
        name: 'index',
        component: Parent
    },
    {
        path: '/user/:name',
        name: 'user',
        component: Parent
    },
    {
        path: '/page1',
        name: 'page1',
        component: page1
    },
    {
        path: '/page2',
        name: 'page2',
        component: page2
    },
]

// 实例化VueRouter并将routes添加进去
const router = createRouter({
    history: createWebHashHistory(),
    routes
})

// 抛出这个这个实例对象方便外部读取以及访问
export default router

修改App.vue

<template>
  <h1>组件测试</h1>
  <router-link to="/page1">Page1</router-link>
  <router-link to="/page2">Page2</router-link>

  <br/>
  <router-link :to="{ name: 'user', params: { name: 'LiMing' }}">
    Param传参
  </router-link>

  <br/>
  <router-link :to="{ name: 'index', query: { name: 'LiMing' }}">
    Query传参
  </router-link>
  <router-view></router-view>
<!--  <Parent>-->
<!--  </Parent>-->
</template>

<script lang="ts">

import Parent from "./components/Parent.vue";

export default {
  name: "App",
  components: {Parent}
}
</script>

<style>

</style>

修改main.ts

import {createApp} from "vue";
import App from "./App.vue";
import router from "./router/index";

const app = createApp(App)
// 一定要注入到vue的实例对象上
app.use(router)
app.mount('#app')
export default app

Vuex

Vuex 是 Vue .js 应用程序的状态管理模式 + 库。它充当应用程序中所有组件的集中存储,其规则确保状态只能以可预测的方式发生变异。

安装

cnpm install vuex@next --save

src文件夹下新建stroe/index.ts

import Vuex from 'vuex';


const store = new Vuex.Store({
    state: {
        // 定义一个name,以供全局使用
        name: '张三',
        // 定义一个number,以供全局使用
        number: 0,
        // 定义一个list,以供全局使用
        list: [
            {id: 1, name: '111'},
            {id: 2, name: '222'},
            {id: 3, name: '333'},
        ]
    },
});

export default store;

修改main.ts

import {createApp} from "vue";
import App from "./App.vue";
import router from "./router/index";
import store from "./store/index";

const app = createApp(App)
// 一定要注入到vue的实例对象上
app.use(router)
app.use(store)
app.mount('#app')
export default app

修改Page1.vue

<template>
  <h1>Page1</h1>
  <p>{{ msg }}</p>
  <button v-on:click="logStore">打印store变量</button>
</template>

<script>
export default {
  name: "Page1",
  data() {
    return {
      msg: "Page组件"
    }
  },
  methods:{
    logStore(){
      alert(this.$store.state.name)
      alert(this.$store.state.number)
      alert(this.$store.state.list)
    }
  }

}
</script>

<style scoped>

</style>

官方建议把this.$store.state.XXX最好放在计算属性中,使代码优雅

<template>
  <h1>Page1</h1>
  <p>{{ msg }}</p>
  <button v-on:click="logStore">打印store变量</button>
</template>

<script>
export default {
  name: "Page1",
  data() {
    return {
      msg: "Page组件"
    }
  },
  methods: {
    logStore() {
      alert(this.getName)
    }
  },
  computed: {
    getName() {
      return this.$store.state.name
    }
  }

}
</script>

<style scoped>

</style>

使用mapState解构

<template>
  <h1>Page1</h1>
  <p>{{ msg }}</p>
  <button v-on:click="logStore">打印store变量</button>
</template>

<script>
import { mapState } from 'vuex';
export default {
  name: "Page1",
  data() {
    return {
      msg: "Page组件"
    }
  },
  methods: {
    logStore() {
      alert(this.name)
    }
  },
  computed: {
    ...mapState(['name']),
  }

}
</script>

<style scoped>

</style>

修改器

import Vuex from 'vuex';


const store = new Vuex.Store({
    state: {
        // 定义一个name,以供全局使用
        name: '张三',
        // 定义一个number,以供全局使用
        number: 0,
        // 定义一个list,以供全局使用
        list: [
            {id: 1, name: '111'},
            {id: 2, name: '222'},
            {id: 3, name: '333'},
        ]
    },
    // 在store对象中增加getters属性
    getters: {
        getName(state) { // 获取修饰后的name,第一个参数state为必要参数,必须写在形参上
            return `hello${state.name}`;
        }
    },
});

export default store;

Page1.vue

<template>
  <h1>Page1</h1>
  <p>{{ msg }}</p>
  <button v-on:click="logStore">打印store变量</button>
</template>

<script>
import { mapState } from 'vuex';
import {mapGetters} from "vuex";
export default {
  name: "Page1",
  data() {
    return {
      msg: "Page组件"
    }
  },
  methods: {
    logStore() {
      alert(this.name)
      alert(this.getName)
    }
  },
  computed: {
    ...mapState(['name']),
    ...mapGetters(['getName']),
  }

}
</script>

<style scoped>

</style>

修改Store的值

import Vuex from 'vuex';


const store = new Vuex.Store({
    state: {
        // 定义一个name,以供全局使用
        name: '张三',
        // 定义一个number,以供全局使用
        number: 0,
        // 定义一个list,以供全局使用
        list: [
            {id: 1, name: '111'},
            {id: 2, name: '222'},
            {id: 3, name: '333'},
        ]
    },
    // 在store对象中增加getters属性
    getters: {
        getName(state) { // 获取修饰后的name,第一个参数state为必要参数,必须写在形参上
            return `hello${state.name}`;
        }
    },

    mutations: {
        setNumber(state) {
            state.number = 5;
        },
        setNumberIsWhat(state, number) { // 增加一个带参数的mutations方法
            state.number = number;
        },
    },

});

export default store;

Mutations里面的函数必须是同步操作,不能包含异步操作!

Page1.vue

<template>
  <h1>Page1</h1>
  <p>{{ msg }}</p>
  <button v-on:click="logStore">打印store变量</button>
</template>

<script>
import {mapMutations, mapState} from 'vuex';

export default {
  name: "Page1",
  data() {
    return {
      msg: "Page组件"
    }
  },
  methods: {
    logStore() {
      this.setNumberIsWhat({number:666});
      alert(this.number)
      this.setNumber();
      alert(this.number)
    }
  },
  computed: {
    ...mapState(['number']),
    ...mapMutations(['setNumber']),
    ...mapMutations(['setNumberIsWhat']),
  }

}
</script>

<style scoped>

</style>

参考文档:https://juejin.cn/post/6928468842377117709

Axios

官方文档:https://axios-http.com/zh/docs/intro

Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。

安装

cnpm install axios

这里以调用https://api.4gml.com/NeteaseMusic接口获取网易云热评为例

src目录下新建utils/request.ts

import axios from 'axios'

//  让请求在浏览器中允许跨域携带cookie
axios.defaults.withCredentials = true;

// 使用自定义配置新建一个实例
const instance = axios.create({
    // url = base url + request url
    baseURL: 'https://api.4gml.com',
    // 设置超时时间 5s
    timeout: 5000,
    headers: {'X-Custom-Header': 'foobar'}
});

// 请求拦截器
instance.interceptors.request.use(
    config => {
        // 在发送请求之前做些什么
        return config;
    }, error => {
        // 对请求错误做些什么
        return Promise.reject(error);
    }
)

// 响应拦截器
instance.interceptors.response.use(
    response => {
        // 2xx 范围内的状态码都会触发该函数。
        // 对响应数据做点什么
        return response;
    },
    error => {
        // 超出 2xx 范围的状态码都会触发该函数。
        // 对响应错误做点什么
        return Promise.reject(error);
    }
)

export default instance

src目录下新建api目录,在api目录下新建music.ts

import request from "../utils/request.ts";


export const getMusicReview = () => {
    return request({
        url: '/NeteaseMusic',
        method: 'get',
    })
}

修改Page2.vue

<template>
  <h1>Page2</h1>
  <p>{{ msg }}</p>
  <textarea class="tex" v-model="review"></textarea>
  <button v-on:click="getReview">获取评论</button>
</template>

<script>
import {getMusicReview} from "../api/music.ts";

export default {
  name: "Page2",
  data() {
    return {
      msg: "Page组件",
      review: "",
    }
  },
  methods: {
    getReview() {
      getMusicReview()
          .then(res => {
            // alert(res.data.content)
            this.review = res.data.content
          })
          .catch(res => {
            alert("网络开小差了,没有获取到图片验证码哦");
          })
    }
  }
}
</script>

<style scoped>
  .tex{
    height: 100px;
    width: 300px;
  }
</style>

防抖和节流

Vue3 没有内置支持防抖和节流,但可以使用 Lodash 等库来实现。

cnpm i --save lodash

修改Child2.vue

<template>
  <h2>子组件2</h2>
  <button @click="debouncedClick">防抖</button>
</template>

<script>
import _ from "lodash";

export default {
  name: "Child2",


  created() {
    // 使用 Lodash 实现防抖
    this.debouncedClick = _.debounce(this.click, 500)
  },
  unmounted() {
    // 移除组件时,取消定时器
    this.debouncedClick.cancel()
  },
  methods: {
    click() {
      console.log("点击")
    }
  },


  setup(props, {emit}) {
    emit('childEvent', "这是子组件传递过来的内容");
    return {}
  },

}
</script>

<style scoped>

</style>

注:@click中对应得是防抖封装后的函数名,而不是Method中的函数名!!!

参考文档:https://blog.csdn.net/zheng_jia_jun/article/details/114577857

Cookie

cnpm i js-cookie

创建

//创建简单的cookie
Cookies.set('name', 'value');
//创建有效期为7天的cookie
Cookies.set('name', 'value', { expires: 7 });
//为当前页创建有效期7天的cookie
Cookies.set('name', 'value', { expires: 7, path: '' });

取值

Cookies.get('name'); // => 'value'
Cookies.get('nothing'); // => undefined
//获取所有cookie
Cookies.get(); // => { name: 'value' }

删除值

Cookies.remove('name');

//如果值设置了路径,那么不能用简单的delete方法删除值,需要在delete时指定路径
Cookies.set('name', 'value', { path: '' });
Cookies.remove('name'); // 删除失败
Cookies.remove('name', { path: '' }); // 删除成功
//注意,删除不存在的cookie不会报错也不会有返回

参考文档:https://www.npmjs.com/package/js-cookie

localStorage

Vue中使用localStorage作为本地存储,解决了 cookie 存储空间不足的问题(cookie中每条cookie的存储空间为4k,localStorage中一般浏览器支持的是5M大小)。

创建

localStorage.setItem('userName', '张三');
localStorage.password = '123456';

读取数据

localStorage.getItem('userName');
localStorage.password

删除数据

localStorage.removeItem('userName')

参考文档:https://blog.csdn.net/zhanduo0118/article/details/110060623

懒加载

cnpm install vue3-lazy -S

用法

主要.js:

import { createApp } from 'vue'
import App from './app'
import lazyPlugin from 'vue3-lazy'
 
const app = createApp(App)
lazyPlugin.install(app, {
  loading: 'loading.png',
  error: 'error.png'
})
app.mount('#app')

模板:

<ul>
  <li v-for="img in list">
    <img v-lazy="img.src" >
  </li>
</ul>

懒惰选项

钥匙描述违约选项
error加载失败时图像的 src'data-src'String
loading加载时图像的 src'data-src'String

参考文档:https://www.npmjs.com/package/vue3-lazy

一些错误

import path from ‘path’ 异常

path 模块是 Node.js 的东西,需要安装 Node.js 的声明文件

npm i @types/node -D

views 和 components有什么区别?

  • components 是小组件(可被views 组件复用)
  • containers 是容器级组件(根据项目大小决定是否使用)
  • views 是页面级组件(一般不被复用)

如何为每个界面设置Title

法一

const routes = [
    {
        path: '/index',
        name: 'index',
        component: Index,
        meta: {
            title:"这是动态title",
            keepAlive: true, // 需要被缓存
            content: 'disable',
        }
    },
]

router.beforeEach((to,from,next) => {
    // 路由发生变化修改页面title
    if (to.meta.title) {
        document.title = to.meta.title;
    }
    next()
})

法二

<template>
  <h1>主页</h1>
</template>

<script>
export default {
  name: "index",
  mounted() {
    document.title = '需要设置的值';
  }
}
</script>

<style scoped>

</style>
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值