Vue详解知识概括

  • Vue CLI
  • Vue-router
  • Promise
  • Vuex
  • axios
  • Vue开发总结

Vue CLI

什么是Vue CLI:

  • 如果你只是简单写几个Vue的Demo程序, 那么你不需要Vue CLI.
  • 如果你在开发大型项目, 那么你需要, 并且必然需要使用Vue CLI
    ①使用Vue.js开发大型应用时,我们需要考虑代码目录结构、项目结构和部署、热加载、代码单元测试等事情。
    ②如果每个项目都要手动完成这些工作,那无疑效率比较低效,所以通常我们会使用一些脚手架工具来帮助完成这些事情。
  • CLI是什么意思?
    ①CLI是Command-Line Interface, 翻译为命令行界面, 但是俗称脚手架.
    ②Vue CLI是一个官方发布 vue.js 项目脚手架
    ③使用 vue-cli 可以快速搭建Vue开发环境以及对应的webpack配置.

Vue CLI使用前提:

  • 安装NodeJS
    ①默认情况下自动安装Node和NPM
    ②NPM的全称是Node Package Manager
    ③是一个NodeJS包管理和分发工具,已经成为了非官方的发布Node模块(包)的标准。
  • Vue.js官方脚手架工具就使用了webpack模板
    ①对所有的资源会压缩等优化操作
    ②它在开发过程中提供了一套完整的功能,能够使得我们开发过程中变得高效。

Vue CLI的使用:

  • 安装Vue脚手架:npm install -g @vue/cli
    ①查看vue版本:vue –version
    ②注意:上面安装的是Vue CLI3的版本,如果需要想按照Vue CLI2的方式初始化项目时不可以的。
    ③拉取2.X模板(旧版本):npm install -g @vue/cli-init
  • Vue CLI2初始化项目:vue init webpack my-project
  • Vue CLI3初始化项目:vue create my-project

Vue CLI2详解:

  • 初始化命令使用:
  • 目录简介:
    ①build.js:构建入口
    ②index.js:变量,配置信息
    ③webpack.base.conf.js:公共webpack配置信息
    ④webpack.dev.conf.js:部署配置信息
    ⑤webpack.prod.conf.js:构建配置信息

(运行时+编译器)Runtime-Compiler和(只含有运行时版本)Runtime-only的区别:

  • 如果你需要在客户端编译模板(例如, 向template 选项传入一个字符串,或者需要将模 板中的非DOM的HTML挂载到一个元素),你需要带有编译器的版本,因而需要完整构建版本。
  • 在使用vue-loader或vueify 时,* . vue文件中的模板会在构建时(build time)预编译(pre-compile)为JavaScript.最终生成的bundle中你不再需要编译器(compiler),因此可以直接使用只含有运行时的构建版本(runtime- only)。
//这种情况需要编译器(compiler)new Vue({template: '<div>({ hi }}</div>')//这种情况不需要new Vue({render (h) {return h('div', this.h1)}})
  • 由于只含有运行时构建版本(runtime-only)比完整构建版本(ull-build)轻量大约30%,你应该尽可能使用只含有运行时的构建版本。如果你还是希望使用完整构建版本,则需要在打包器中配置别名。
  • 简单总结:
    ①如果在之后的开发中,你依然使用template,就需要选择Runtime-Compiler。
    ②如果你之后的开发中,使用的是.vue文件夹开发,那么可以选择Runtime-only。

render和template区别:

//Runtime-Compilernew Vue({el :'#app',components: { App },template: '<App/>'})//Runtime-onlynew Vue({el : '#app',render: h => h(App)})
  • 为什么存在这样的差异呢?
    ①我们需要先理解Vue应用程序是如何运行起来的。
    ②Vue中的模板如何最终渲染成真实DOM。
    ③我们来看下面的一幅图。

npm run build与npm run dev详解:

  • npm run build:
  • npm run dev:

webpack.base.conf.js起别名:

resolve: {extensions: ['.js', '.vue', '.json'],alias: {'@':resolve('src'),'pages': resolve('src/pages'),'common': resolve('src/common'),'components':resolve('src/components'),'network': resolve('src/network')}},

Vue CLI3详解:

  • vue-cli 3 与 2 版本有很大区别:
    ①vue-cli 3 是基于 webpack 4 打造,vue-cli 2 还是 webapck 3
    ②vue-cli 3 的设计原则是“0配置”,移除的配置文件根目录下的,build和config等目录
    ③vue-cli 3 提供了 vue ui 命令,提供了可视化配置,更加人性化
    ④移除了static文件夹,新增了public文件夹,并且index.html移动到public中
  • 初始化使用:
  • 目录结构详解:
  • 配置去哪里了:
    ①UI方面的配置:启动配置服务器:vue ui

    ②一大堆配置文件去哪里了?

Vue-router

什么是路由?

  • 路由(routing)就是通过互联的网络把信息从源地址传输到目的地址的活动
  • 路由器提供了两种机制: 路由和转送.
    ①路由是决定数据包从来源到目的地的路径.
    ②转送将输入端的数据转移到合适的输出端.
  • 路由中有一个非常重要的概念叫路由表。路由表本质上就是一个映射表, 决定了数据包的指向。

后端路由阶段:

  • 早期的网站开发整个HTML页面是由服务器来渲染的:
    ①服务器直接生产渲染好对应的HTML页面, 返回给客户端进行展示.
  • 但是一个网站, 这么多页面服务器如何处理呢” />执行:location.hash = ‘/foo’返回:”/foo”执行:location. href返回:”http: //192.168.1.101: 8000/examples/urlChange/#/foo”

    HTML5的history模式:

    • history接口是HTML5新增的, 它有五种模式改变URL而不刷新页面。
    • history接口底层的数据结构是栈。
    • 函数:
      ①history.pushState():插入锚点,改变url,支持前进后退。
      ②history.replaceState():插入锚点,改变url,不支持前进后退。
      ③history.go()
    • 补充说明:
      ①上面只演示了三个方法
      ②因为 history.back() 等价于 history.go(-1)
      ③history.forward() 则等价于 history.go(1)
      ④这三个接口等同于浏览器界面的前进后退
    • 与URL的hash相比,没有了#符号

    vue-router认识:

    • 目前前端流行的三大框架, 都有自己的路由实现:
      ①Angular的ngRouter
      ②React的ReactRouter
      ③Vue的vue-router
    • 当然, 我们的重点是vue-router,vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用。
    • vue-router是基于路由和组件的:
      ①路由用于设定访问路径, 将路径和组件映射起来.
      ②在vue-router的单页面应用中, 页面的路径的改变就是组件的切换.

    安装和使用vue-router:

    • 安装vue-router:npm install vue-router –save
    • 在模块化工程中使用它(因为是一个插件, 所以可以通过Vue.use()来安装路由功能)
      ①导入路由对象,并且调用 Vue.use(VueRouter)
      ②创建路由实例,并且传入路由映射配置
      ③在Vue实例中挂载创建的路由实例
    • 使用vue-router的步骤:
      ①创建路由组件
      ②配置路由映射: 组件和路径映射关系
      ③使用路由: 通过和
    • 路由标签详解:
      ①: 该标签是一个vue-router中已经内置的组件, 它会被渲染成一个标签.
      ②: 该标签会根据当前的路径, 动态渲染出不同的组件。
      ③网页的其他内容, 比如顶部的标题/导航,或者底部的一些版权信息等会和处于同一个等级。
      ④在路由切换时, 切换的是挂载的组件,其他内容不会发生改变。
    ----创建router文件夹,然后创建index.js文件,创建router实例,配置组件和路径的映射关系:----import Vue from 'vue'import VueRouter from 'vue-router'// 1.注入插件Vue.use(VueRouter)// 2.定义路由const routes = [{path: '/home',component: Home}{path: '/about', component: About}]// 3.创建router实例const router = new VueRouter({routes})// 4.导出router实例export default router----main.js文件中挂载到Vue实例中:----import Vuefrom 'vue'import App from './App'import router from './router'new Vue({el: '#app',router,render: h => h(App)})----创建About和Home路由组件--------使用路由:----<template><div id="app"><h1>我是网站的标题<router-link to="/home">首页</router-link><router-link to="/about">关于</router-link><router-view></router-view><h2>我是APP中一些底部版权信息</h2></div></template>----最终效果如下:----一、当路径是根路径时,router-view没有渲染试图二、点击首页,路径切换,router-view渲染home组件伞、点击关于,路径切换,router-view渲染about组件

    vue-router细节处理:

    • 路由的默认路径:
      ①默认情况下, 进入网站的首页, 我们希望渲染首页的内容,但是我们的实现中, 默认没有显示首页组件, 必须让用户点击才可以。
      ②如何可以让路径默认跳到到首页, 并且渲染首页组件呢,非常简单, 我们只需要配置多配置一个映射就可以了。
      ③我们在routes中又配置了一个映射,path配置的是根路径: /,redirect是重定向, 也就是我们将根路径重定向到/home的路径下, 这样就可以得到我们想要的结果了。
    const routes =[{path: '/'redirect: '/home'}]
    • HTML5的History模式:
      ①我们前面说过改变路径的方式有两种:URL的hash,HTML5的history。默认情况下, 路径的改变使用的URL的hash,如果希望使用HTML5的history模式, 非常简单, 进行如下配置即可:
    const router =new VueRouter({routes,mode: 'history'})
    • router-link补充:
      ①在前面的中, 我们只是使用了一个属性: to, 用于指定跳转的路径。
      ②还有一些其他属性:
      tag: tag可以指定之后渲染成什么组件, 比如上面的代码会被渲染成一个
    • 元素, 而不是。
      replace: replace不会留下history记录, 所以指定replace的情况下, 后退键返回不能返回到上一个页面中。
      active-class: 当对应的路由匹配成功时, 会自动给当前元素设置一个router-link-active的class, 设置active-class可以修改默认的名称。在进行高亮显示的导航菜单或者底部tabbar时, 会使用到该类。但是通常不会修改类的属性, 会直接使用默认的router-link-active即可。
    • 修改linkActiveClass:
      ①该class具体的名称也可以通过router实例的属性进行修改。
    const router = new VueRouter({routes,mode: 'history',linkActiveClass:'active'})
    • 路由代码跳转:
      ①有时候, 页面的跳转可能需要执行对应的JavaScript代码, 这个时候, 就可以使用第二种跳转方式了。
    <template><div id="app"><h1>我是网站的标题<button @click="li nkToHomel">首页</button><button @click="l inkToAbout">关于</button><router-view></router-view><h2>我是APP中一些底部版权信息</h2></div><template><script>export default{name:'App',methods: {linkToHome() {this.$router.push('/home')}linkToAbout() {this.$router.push('/about')}}</script>
    • 动态路由:
      ①在某些情况下,一个页面的path路径可能是不确定的,比如我们进入用户界面时,希望是如下的路径:/user/aaaa或/user/bbbb。除了有前面的/user之外,后面还跟上了用户的ID。这种path和Component的匹配关系,我们称之为动态路由(也是路由传递数据的一种方式)。
    -----路由配置页面---{path: '/user/:id',component: User}----使用页面----<div> <h2>{{$route.params.id}}</h2> </div>----组件页面----<router-link to="/user/123">用户</router-link>

    路由懒加载:

    • 官方给出了解释:当打包构建应用时,Javascript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了
    • 官方在说什么呢?首先, 我们知道路由中通常会定义很多不同的页面.这个页面最后被打包在哪里呢? 一般情况下, 是放在一个js文件中.但是, 页面这么多放在一个js文件中, 必然会造成这个页面非常的大.如果我们一次性从服务器请求下来这个页面, 可能需要花费一定的时间, 甚至用户的电脑上还出现了短暂空白的情况.
    • 如何避免这种情况呢? 使用路由懒加载就可以了.路由懒加载做了什么?路由懒加载的主要作用就是将路由对应的组件打包成一个个的js代码块.只有在这个路由被访问到的时候, 才加载对应的组件。
    • 懒加载的方式:
    方式一: 结合Vue的异步组件和Webpack的代码分析.const Home = resolve => { require.ensure(['../components/Home.vue'], () => { resolve(require('../components/Home.vue')) })};方式二: AMD写法const About = resolve => require(['../components/About.vue'], resolve);方式三: 在ES6中, 我们可以有更加简单的写法来组织Vue异步组件和Webpack的代码分割.const Home = () => import('../components/Home.vue')
    //使用懒加载const routes =[{path: '/home', component: () => import(' ../components/Home')},path: '/about', component: () => import('../components/About')},];

    路由嵌套:

    • 嵌套路由是一个很常见的功能。比如在home页面中, 我们希望通过/home/news和/home/message访问一些内容。一个路径映射一个组件, 访问这两个路径也会分别渲染两个组件。路径和组件的关系如下:
    /home --------> Home/home/news --------> News/home/message --------> Message/about --------> About
    • 实现嵌套路由有两个步骤:
      ①创建对应的子组件, 并且在路由映射中配置对应的子路由。
      ②在组件内部使用标签。
    -----一、定义两个组件----------二、配置嵌套路由映射-----import Vue from 'vue'import VueRouter from 'vue-router'const Home = () => import('../components /Home')const Message = () => import('../components/message')const News = () => import('../components/news')const About = ( ) => import('../components/About')// 1.注入插件Vue.use (VueRouter)// 2.定义路由const routes = [{path: '/home',component: Home,children: [{path: 'message'component: Message},{path: 'news',component: News}]}]-----三、在父组件模板中使用-----<template><div id="home"><h2>我是首页标题</h2><router-link to="/home/message">消息</router-link><router-link to="/home/news">新闻<router-view></router-view></div></template>
    • 嵌套路由也可以配置默认的路径, 配置方式如下:
    {path: '',redirect:'message'}

    路由传递参数:

    • 传递参数主要有两种类型: params和query
    • params的类型:
      ①配置路由格式: /router/:id
      ②传递的方式: 在path后面跟上对应的值
      ③传递后形成的路径: /router/123, /router/abc
    • query的类型:
      ①配置路由格式: /router, 也就是普通配置
      ②传递的方式: 对象中使用query的key作为传递方式
      ③传递后形成的路径: /router?id=123, /router?id=abc
    • 如何使用它们呢? 也有两种方式: 的方式和JavaScript代码方式
    ----传递参数方式一: <router-link>:----<router-link :to="{path: '/profile/' + 123,query: { name:'why',age: 18}}">档案</router-link>----传递参数方式二: JavaScript代码:----export default {name:'App',methods: {toProfile() {this.$router.push({path: '/profile/' + 123,query: {name: 'why',age: 18}})}}}
    • 获取参数:
      ①获取参数通过$route对象获取的,在使用了vue-router 的应用中,路由对象会被注入每个组件中,赋值为 this.$route,并且当路由切换时,路由对象会被更新。
      ②通过$route获取传递的信息如下:
    <p>params: {{ $route.params}}</p><p>query: {{$route.query}}</p>
    • $route和$router是有区别的:
      ①$router为VueRouter实例,想要导航到不同URL,则使用$router.push方法
      ②$route为当前router跳转对象里面可以获取name、path、query、params等

    路由导航守卫:

    • 我们来考虑一个需求: 在一个SPA应用中, 如何改变网页的标题呢?
      ①网页标题是通过来显示的, 但是SPA只有一个固定的HTML, 切换不同的页面时, 标题并不会改变.<br /> ②但是我们可以通过JavaScript来修改<title>的内容.window.document.title = ‘新的标题’.<br /> ③那么在Vue项目中, 在哪里修改? 什么时候修改比较合适呢?</li><li>普通的修改方式:<br /> ①我们比较容易想到的修改标题的位置是每一个路由对应的组件.vue文件中.<br /> ②通过mounted声明周期函数, 执行对应的代码进行修改即可.<br /> ③但是当页面比较多时, 这种方式不容易维护(因为需要在多个页面执行类似的代码).</li><li>有没有更好的办法呢? 使用导航守卫即可,什么是导航守卫?<br /> ①vue-router提供的导航守卫主要用来监听监听路由的进入和离开的.<br /> ②vue-router提供了beforeEach和afterEach的钩子函数, 它们会在路由即将改变前和改变后触发.</li><li>详解:<br /> ①我们可以在钩子当中定义一些标题, 可以利用meta来定义。<br /> ②导航钩子的三个参数解析:<br /> to: 即将要进入的目标的路由对象.<br /> from: 当前导航即将要离开的路由对象.<br /> next: 调用该方法后, 才能进入下一个钩子</li></ul><pre><code class="prism language-xml">// 定义路由const routes =[{path:"/home',component: Home,children: [...],meta:{title:'首页'}},{path: '/about',component: About,meta: {title:'关于'}},{path: '/profile/:id',component: Profile ,meta: {title:'档案'}}]//配置路由const router = new VueRouter ({routes,mode: 'history',linkActiveClass: 'active',})router.beforeEach( (to, from, next) => {window.document.title = to.meta.titlenext()})</code></pre><ul><li>补充:<br /> ①如果是后置钩子, 也就是afterEach, 不需要主动调用next()函数.<br /> ②上面我们使用的导航守卫, 被称之为全局守卫.<br /> 路由独享的守卫.<br /> 组件内的守卫.</li></ul><p><strong>路由keep-alive:</strong></p><ul><li>keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。它们有两个非常重要的属性:<br /> ①include – 字符串或正则表达,只有匹配的组件会被缓存<br /> ②exclude – 字符串或正则表达式,任何匹配的组件都不会被缓存</li><li>router-view 也是一个组件,如果直接被包在 keep-alive 里面,所有路径匹配到的视图组件都会被缓存:</li></ul><pre><code class="prism language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>keep-alive</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>router-view</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>!--所有路径匹配到的视图组件都会被缓存!</span> <span class="token attr-name">-</span> <span class="token attr-name">-</span> <span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>router-view</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>keep-alive</span><span class="token punctuation">></span></span></code></pre><ul><li>通过create声明周期函数来验证</li></ul><h1>Promise</h1><p><strong>什么是Promise呢?</strong></p><ul><li>Promise到底是做什么的呢?<br /> ①Promise是异步编程的一种解决方案。</li><li>那什么时候我们会来处理异步事件呢?<br /> ①一种很常见的场景应该就是网络请求了。<br /> ②我们封装一个网络请求的函数,因为不能立即拿到结果,所以不能像简单的3+4=7一样将结果返回。<br /> ③所以往往我们会传入另外一个函数,在数据请求成功时,将数据通过传入的函数回调出去。<br /> ④如果只是一个简单的网络请求,那么这种方案不会给我们带来很大的麻烦。</li><li>但是当网络请求非常复杂时就会出现回调地狱。</li><li>我们更加期望的是一种更加优雅的方式来进行这种异步操作。Promise可以以一种非常优雅的方式来解决这个问题。</li></ul><p><strong>Promise基本使用:</strong></p><ul><li>new Promise很明显是创建一个Promise对象。小括号中((resolve, reject) => {})也很明显就是一个函数,而且我们这里用的是之前刚刚学习过的箭头函数。但是resolve, reject它们是什么呢?</li><li>我们先知道一个事实:在创建Promise时,传入的这个箭头函数是固定的(一般我们都会这样写)<br /> resolve和reject它们两个也是函数,通常情况下,我们会根据请求数据的成功和失败来决定调用哪一个。</li><li>成功还是失败?<br /> ①如果是成功的,那么通常我们会调用resolve(messsage),这个时候,我们后续的then会被回调。<br /> ②如果是失败的,那么通常我们会调用reject(error),这个时候,我们后续的catch会被回调。</li></ul><pre><code class="prism language-xml">//普通方式setTimeout( function () {let data = 'Hello World'console. log (content) ;}, 1000)//Promise方式new Promise((resolve, reject) => {setTimeout( function () {resolve( 'Hello World')reject( 'Error Data')}, 1000)}).then(data => {console. log(data);}).catch(error => { console. log(error);})</code></pre><p><strong>Promise三种状态:</strong></p><ul><li>当我们开发中有异步操作时, 就可以给异步操作包装一个Promise 异步操作之后会有三种状态<br /> ①pending:等待状态,比如正在进行网络请求,或者定时器没有到时间。<br /> ②fulfill:满足状态,当我们主动回调了resolve时,就处于该状态,并且会回调.then()<br /> ③reject:拒绝状态,当我们主动回调了reject时,就处于该状态,并且会回调.catch()<br /> <noscript><img decoding="async" class="aligncenter" src="https://img.maxssl.com/uploads/?url=https://img-blog.csdnimg.cn/b7863f27ed834e29a4cd4964f6fd9f56.png" /></noscript><img decoding="async" class="lazyload aligncenter" src='data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%20210%20140%22%3E%3C/svg%3E' data-src="https://img.maxssl.com/uploads/?url=https://img-blog.csdnimg.cn/b7863f27ed834e29a4cd4964f6fd9f56.png" /></li></ul><p><strong>Promise链式调用:</strong></p><ul><li>我们在看Promise的流程图时,发现无论是then还是catch都可以返回一个Promise对象。所以,我们的代码其实是可以进行链式调用的:<br /> ①这里我们直接通过Promise包装了一下新的数据,将Promise对象返回了<br /> Promise.resovle():将数据包装成Promise对象,并且在内部回调resolve()函数<br /> Promise.reject():将数据包装成Promise对象,并且在内部回调reject()函数</li></ul><pre><code class="prism language-xml">//链式调用的代码new Promise((resolve, reject) => {setTimeout(function () {resolve('Hello World')},1000 )}). then(data => {console. log(data); // => Hello Worldreturn Promise. resolve(data + '111')}). then(data => {console. log(data); // => Hello World111return Promise. resolve(data + '222')}). then(data => {console. log(data); // => Hello World111222return Promise.reject(data + 'error')}). then(data => {console. log(data); //这里没有输出,这部分代码不会执行return Promise. resolve(data + '333')}).catch(data => {console. log(data); // => Hello World111222errorreturn Promise. resolve(data + '444')}).then(data => {console. log(data); // => Hello World111222error444})</code></pre><ul><li>简化版代码:如果我们希望数据直接包装成Promise.resolve,那么在then中可以直接返回数据<br /> 注意下面的代码中,我将return Promise.resovle(data)改成了return data。结果依然是一样的。</li></ul><pre><code class="prism language-xml">//链式调用的简便写法new Promise((resolve, reject) => {setTimeout(function () {resolve( 'Hello World')},1000)}). then(data => {console. log(data); // => Hello Worldreturn data + '111 '}). then(data => {console. log(data); // => Hello World111return data + '222'}). then(data => {console. log(data); // => Hello World111222return Promise. reject(data + 'error')}). then(data => console. log(data); //这里没有输出,这部分代码不会执行return data + ' 333}).catch(data => {console. log(data); // => Hello World111222errorreturn data + ' 444}). then(data => {console. log(data); // => Hello World111222error444 })</code></pre><ul><li><code>如果希望返回的是reject方法,可以直接throw "字符串"。</code></li></ul><h1>Vuex</h1><p><strong>Vuex是做什么的” /></li><li>多界面状态管理:<br /> ①对于某些状态(状态1/状态2/状态3)来说只属于我们某一个试图,但是也有一些状态(状态a/状态b/状态c)属于多个试图共同想要维护的<br /> 状态1/状态2/状态3你放在自己的房间中,你自己管理自己用,没问题。<br /> 但是状态a/状态b/状态c我们希望交给一个大管家来统一帮助我们管理!!!<br /> 没错,Vuex就是为我们提供这个大管家的工具。<br /> ②全局单例模式(大管家)<br /> 我们现在要做的就是将共享的状态抽取出来,交给我们的大管家,统一进行管理。<br /> 之后,你们每个试图,按照我规定好的规定,进行访问和修改等操作。<br /> 这就是Vuex背后的基本思想。<br /> <noscript><img decoding="async" class="aligncenter" src="https://img.maxssl.com/uploads/?url=https://img-blog.csdnimg.cn/3a9d7184a8164a1e9ea50eee55d4250d.png" /></noscript><img decoding="async" class="lazyload aligncenter" src='data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%20210%20140%22%3E%3C/svg%3E' data-src="https://img.maxssl.com/uploads/?url=https://img-blog.csdnimg.cn/3a9d7184a8164a1e9ea50eee55d4250d.png" /></li></ul><p><strong>Vuex基本使用:</strong></p><ul><li>首先,我们需要在某个地方存放我们的Vuex代码: 这里,我们先创建一个文件夹store,并且在其中创建一个index.js文件,在index.js文件中写入如下代码:</li></ul><pre><code class="prism language-xml">import Vuex from 'vuex'import Vue from 'vue'Vue.use(Vuex)const store = new Vuex.Store({state: {count: 0},mutations: {increment(state) {state.count++},decrement(state) {state.count--}}})export default store</code></pre><ul><li>其次,我们让所有的Vue组件都可以使用这个store对象 来到main.js文件,导入store对象,并且放在new Vue中这样,在其他Vue组件中,我们就可以通过this.$store的方式,获取到这个store对象了</li></ul><pre><code class="prism language-xml">import Vue from 'vue'import App from './App'import store from './store'new Vue({el: '#app',store,render: h => h(App) })</code></pre><ul><li>使用Vuex的count:</li></ul><pre><code class="prism language-xml"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>template</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>div</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>app<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>p</span><span class="token punctuation">></span></span>{{count}}<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>p</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>increment<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>+1<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>button</span> <span class="token attr-name">@click</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>decrement<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>-1<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>button</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>div</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>template</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript"><span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span><span class="token literal-property property">name</span><span class="token operator">:</span>" App'<span class="token punctuation">,</span><span class="token literal-property property">components</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token literal-property property">computed</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token function-variable function">count</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span> Sstore<span class="token punctuation">.</span>state<span class="token punctuation">.</span>count<span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token literal-property property">methods</span><span class="token operator">:</span> <span class="token punctuation">{</span><span class="token function-variable function">increment</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>$store<span class="token punctuation">.</span><span class="token function">commit</span><span class="token punctuation">(</span><span class="token string">'increment'</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token function-variable function">decrement</span><span class="token operator">:</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">this</span><span class="token punctuation">.</span>$store<span class="token punctuation">.</span><span class="token function">commit</span><span class="token punctuation">(</span><span class="token string">'decrement'</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token punctuation">}</span></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span></code></pre><ul><li>总结:<br /> ①小结:<br /> 提取出一个公共的store对象,用于保存在多个组件中共享的状态<br /> 将store对象放置在new Vue对象中,这样可以保证在所有的组件中都可以使用到<br /> 在其他组件中使用store对象中保存的状态即可<br /> 1、通过this.$store.state.属性的方式来访问状态<br /> 2、通过this.$store.commit(‘mutation中方法’)来修改状态<br /> ②注意事项:<br /> 我们通过提交mutation的方式,而非直接改变store.state.count。<br /> 这是因为Vuex可以更明确的追踪状态的变化,所以不要直接改变store.state.count的值。</li></ul><p><strong>Vuex核心概念:</strong></p><ul><li>Vuex有几个比较核心的概念:<br /> ①State<br /> ②Getters<br /> ③Mutation<br /> ④Action<br /> ⑤Module</li></ul><p><strong>State简介:</strong></p><ul><li>Vuex提出使用单一状态树, 什么是单一状态树呢?英文名称是Single Source of Truth,也可以翻译成单一数据源。</li><li>这个和我们在应用开发中比较类似:<br /> ①如果你的状态信息是保存到多个Store对象中的,那么之后的管理和维护等等都会变得特别困难。所以Vuex也使用了单一状态树来管理应用层级的全部状态。<br /> ②单一状态树能够让我们最直接的方式找到某个状态的片段,而且在之后的维护和调试过程中,也可以非常方便的管理和维护。</li></ul><p><strong>Getters简介:</strong></p><ul><li>有时候,我们需要从store中获取一些state变异后的状态,我们可以在Store中定义getters。</li><li>getters默认是不能传递参数的, 如果希望传递参数, 那么只能让getters本身返回另一个函数。</li><li><code>Getters类似计算属性。</code></li></ul><pre><code class="prism language-xml">getters: {//直接获取store数据greaterAgesStus: state => {return state.students.filter(s => s.age >= 20)},//获取getters数据greaterAgesCount: (state, getters) => {return getters.greaterAgesstus.length},stuByID: state => {return id => {return state.students.find(s => s.id === id)}}}</code></pre><p><strong>Mutation简介:</strong></p><ul><li>Vuex的store状态的更新唯一方式:提交Mutation</li><li>Mutation主要包括两部分:<br /> ①字符串的事件类型(type)<br /> ②一个回调函数(handler),该回调函数的第一个参数就是state。</li></ul><pre><code class="prism language-xml">//multation的定义方式:mutations: {increment(state) {state.count++}}//通过mutation更新:increment: function () {this.$store.commit('increment')}</code></pre><ul><li>在通过mutation更新数据的时候, 有可能我们希望携带一些额外的参数:参数被称为是mutation的载荷(Payload)。</li></ul><pre><code class="prism language-xml">------单参数:-------//multation的定义方式:decrement(state,n) {state.count -= n}//通过mutation更新:decrement: function () {this.Sstore.commit('decrement',2)}------对象:-------//multation的定义方式:changeCount (state,payload) {state.count = payload.count}//通过mutation更新:changeCount: function () {this.$store.commit('changeCount', {count: 0})}</code></pre><ul><li>Mutation提交风格:<br /> ①上面的通过commit进行提交是一种普通的方式。<br /> ②Vue还提供了另外一种风格, 它是一个包含type属性的对象:</li></ul><pre><code class="prism language-xml">//通过mutation更新:this.$store.commit ({type:'changeCount'count: 100})//Mutation中的处理方式是将整个commit的对象作为payload使用, 所以代码没有改变, 依然如下:changeCount (state,pay1oad) {state.count = payload.count}</code></pre><ul><li>Mutation响应规则:<br /> ①Vuex的store中的state是响应式的, 当state中的数据发生改变时, Vue组件会自动更新.<br /> ②这就要求我们必须遵守一些Vuex对应的规则:<br /> 提前在store中初始化好所需的属性.<br /> 当给state中的对象添加新属性时, 使用下面的方式:<br /> 方式一: 使用Vue.set(obj, ‘newProp’, 123)<br /> 方式二: 用心对象给旧对象重新赋值</li><li>Mutation常量类型:<br /> ①在mutation中, 我们定义了很多事件类型(也就是其中的方法名称),当我们的项目增大时, Vuex管理的状态越来越多, 需要更新状态的情况越来越多, 那么意味着Mutation中的方法越来越多,方法过多, 使用者需要花费大量的经历去记住这些方法, 甚至是多个文件间来回切换, 查看方法名称, 甚至如果不是复制的时候, 可能还会出现写错的情况。<br /> ②在各种Flux实现中, 一种很常见的方案就是使用常量替代Mutation事件的类型,我们可以将这些常量放在一个单独的文件中, 方便管理以及让整个app所有的事件类型一目了然。<br /> ③我们可以创建一个文件: mutation-types.js, 并且在其中定义我们的常量,定义常量时, 我们可以使用ES2015中的风格, 使用一个常量来作为函数的名称。</li></ul><pre><code class="prism language-xml">文件名:mutation-typesjs代码:export const UPDATE_ INFO = 'UPDATE_INFO'</code></pre><ul><li>Mutation同步函数:<br /> ①通常情况下, Vuex要求我们Mutation中的方法必须是同步方法,主要的原因是当我们使用devtools时, 可以devtools可以帮助我们捕捉mutation的快照。<br /> ②但是如果是异步操作, 那么devtools将不能很好的追踪这个操作什么时候会被完成。所以通常情况下, 不要再mutation中进行异步的操作。</li></ul><p><strong>Action简介:</strong></p><ul><li>我们强调, 不要再Mutation中进行异步操作. 但是某些情况, 我们确实希望在Vuex中进行一些异步操作, 比如网络请求,必然是异步的. 这个时候怎么处理呢” />\\定义:const store = new Vuex.Store({state: {count: 0},mutations: {increment(state) {state.count++}},actions: {increment (context) {context.commit(‘increment’)}}})\\使用:methods: {increment() {this.$store.dispatch(‘increment’) }}</code><p><strong>Module简介:</strong></p><ul><li>Module是模块的意思, 为什么在Vuex中我们要使用模块呢?<br /> ①Vue使用单一状态树,那么也意味着很多状态都会交给Vuex来管理,当应用变得非常复杂时,store对象就有可能变得相当臃肿。<br /> ②<code>为了解决这个问题, Vuex允许我们将store分割成模块(Module), 而每个模块拥有自己的state、mutation、action、getters等。</code></li><li>注意:<br /> ①虽然, 我们的<code>getters</code>和<code>mutation</code>都是定义在对象内部的,但是在调用的时候, 依然是通过this.$store来直接调用的。<br /> ②actions:<br /> <code>局部状态通过 context.state 暴露出来,根节点状态则为 context.rootState</code><br /> 如果getters中也需要使用全局的状态, 可以接受更多的参数</li></ul><pre><code class="prism language-xml">const moduleA = {//...actions: {incrementIfoddonRootSum ({state,commit,rootState}) {if ((state.count + rootState.count) %2 ===1) {commit('increment')}}}}</code></pre><ul><li>代码结构:</li></ul><pre><code class="prism language-xml">const moduleA = {state: { ... },mutations: { ... },actions: { ... },getters: { ... }}const moduleB = {state: { ... },mutations: { ... },actions: { ... }}const store = new Vuex.Store({modules: {a: modu1eA,b: modu1eB}})store.state.a // -> moduleA的状态store.state.b // -> moduleB的状态</code></pre><p><strong>项目结构:</strong></p><ul><li>当我们的Vuex帮助我们管理过多的内容时, 好的项目结构可以让我们的代码更加清晰:<br /> <noscript><img decoding="async" class="aligncenter" src="https://img.maxssl.com/uploads/?url=https://img-blog.csdnimg.cn/af372030a77746c894e3829c402814dd.png" /></noscript><img decoding="async" class="lazyload aligncenter" src='data:image/svg+xml,%3Csvg%20xmlns=%22http://www.w3.org/2000/svg%22%20viewBox=%220%200%20210%20140%22%3E%3C/svg%3E' data-src="https://img.maxssl.com/uploads/?url=https://img-blog.csdnimg.cn/af372030a77746c894e3829c402814dd.png" /></li></ul><h1>axios</h1><p><strong>选择什么网络模块” /></li></ul><p><strong>为什么选择axios?</strong></p><ul><li>功能特点:<br /> ①在浏览器中发送 XMLHttpRequests 请求<br /> ②在 node.js 中发送 http请求<br /> ③支持 Promise API<br /> ④拦截请求和响应<br /> ⑤转换请求和响应数据</li></ul><p><strong>axiox请求方式:</strong></p><ul><li>支持多种请求方式:<br /> ①axios(config)<br /> ②axios.request(config)<br /> ③axios.get(url[, config])<br /> ④axios.delete(url[, config])<br /> ⑤axios.head(url[, config])<br /> ⑥axios.post(url[, data[, config]])<br /> ⑦axios.put(url[, data[, config]])<br /> ⑧axios.patch(url[, data[, config]])</li><li>发送get请求演示:</li></ul><pre><code class="prism language-xml">import axios from 'axios'export default {name : 'app',created() {//提问:为什么我这里没有跨域的问题?//1.没有请求参数axios.get( 'http://123.207.32.32:8000/category').then(res => {console.log(res);}).catch(err =>{console.log(err);})//2.有请求参数axios.get( 'http:/ /123.207.32.32:8000/home/data',{params: itype: 'sell', page: 1}}).then(res => {console.log ( res);}).catch(err => {console.log(err);})}}</code></pre><ul><li>发送并发请求:<br /> ①有时候, 我们可能需求同时发送两个请求<br /> ②使用axios.all, 可以放入多个请求的数组.<br /> ③axios.all([]) 返回的结果是一个数组,使用 axios.spread 可将数组 [res1,res2] 展开为 res1, res2</li></ul><pre><code class="prism language-xml">import axios from 'axios'export default {name : 'app',created () {[//发送并发请求axios.all([axios.get('http://123.207.32.32:8000/category'),axios.get('http://123.207.32.32:8000/home/data',{params : {type: 'sell', page: 1}})]).then(axios.spread((res1,res2) => {console.log(res1);console.log(res2);}))}</code></pre><p><strong>全局配置:</strong></p><ul><li>在上面的示例中, 我们的BaseURL是固定的<br /> ①事实上, 在开发中可能很多参数都是固定的.<br /> ②这个时候我们可以进行一些抽取, 也可以利用axiox的全局配置</li></ul><pre><code class="prism language-xml">created( {//提取全局的配置axios.defaults.baseURL = 'http://123.207.32.32:8000'//发送并发请求axios.all([axios.get('/category'),axios.get('/home/data',{params: {type: 'sell', page:1}})]).then(axios.spread((res1,res2) =>{console.log (res1);console.log(res2);}))}</code></pre><ul><li>常见的配置选项:</li></ul><pre><code class="prism language-xml">请求地址url: '/user',请求类型method: 'get',请根路径baseURL: 'http://www.mt.com/api',请求前的数据处理transformRequest:[function(data){}],请求后的数据处理transformResponse: [function(data){}],自定义的请求头headers:{'x-Requested-With':'XMLHttpRequest'},URL查询对象params:{ id: 12 },查询对象序列化函数paramsSerializer: function(params){ }request bodydata: { key: 'aa'},超时设置stimeout: 1000,跨域是否带TokenwithCredentials: false,自定义请求处理adapter: function(resolve, reject, config){},身份验证信息auth: { uname: '', pwd: '12'},响应的数据格式 json / blob /document /arraybuffer / text / streamresponseType: 'json',</code></pre><p><strong>axios的实例:</strong></p><ul><li>为什么要创建axios的实例呢?<br /> ①当我们从axios模块中导入对象时, 使用的实例是默认的实例.<br /> ②当给该实例设置一些默认配置时, 这些配置就被固定下来了.<br /> ③但是后续开发中, 某些配置可能会不太一样.<br /> ④比如某些请求需要使用特定的baseURL或者timeout或者content-Type等.<br /> ⑤这个时候, 我们就可以创建新的实例, 并且传入属于该实例的配置信息.</li></ul><pre><code class="prism language-xml">//创建新的实例const axiosInstance = axios.create({baseURL: 'http:/ /123.207.32.32:8000',timeout: 5000,headers: {'Content-Type' : 'application/x-www-form-urlencoded '}})//发送网络请求axiosInstance({url: '/category',method: 'get'}).then(res => {console. log(res);}).catch(err => {console. log(err);})</code></pre><ul><li>axios封装:</li></ul><pre><code class="prism language-xml">import originAxios from 'axios'export default function axios(option) {return new Promise((resolve, reject) =>{//1.创建axios的实例const instance = originAxios.create({baseURL: '/api',timeout: 5000,headers:''});//2.传入对象进行网络请求instance(option).then(res => {resolve(res)}).catch(err => {reject(err)})})}</code></pre><p><strong>axios拦截器:</strong></p><ul><li>axios提供了拦截器,用于我们在发送每次请求或者得到相应后,进行对应的处理。</li><li>如何使用拦截器呢?</li></ul><pre><code class="prism language-xml">//配置请求和响应拦截instance.interceptors.request.use(config =>{console.log('来到了request拦截success中');return config}, err => {console.log('来到了request拦截failure中');return err}instance.interceptors.response.use(response =>{console.log('来到了response拦截success中');return response.data}, err =>{console.log('来到了response拦截failure中');return err})</code></pre><ul><li>拦截器中都做什么呢?<br /> ①请求拦截中错误拦截较少,通常都是配置相关的拦截。可能的错误比如请求超时,可以将页面跳转到一个错误页面中。<br /> ②响应拦截中完成的事情:<br /> 响应的成功拦截中,主要是对数据进行过滤。<br /> 响应的失败拦截中,可以根据status判断报错的错误码,跳转到不同的错误提示页面。</li></ul><pre><code class="prism language-xml">//请求拦截instance.interceptors.request.use(config =>{console.log('来到了request拦截success中');//1.当发送网络请求时,在页面中添加一个loading组件,作为动画//2.某些请求要求用户必须登录,判断用户是否有token,如果没有token跳转到login页面//3.对请求的参数进行序列化config.data = qs.stringify (config.data)console.log(config);//4.等等return config})//响应的成功拦截instance.interceptors.response.use(response => {console.log('来到了response拦截success中');return response.data})//响应的失败拦截},err =>{console.log('来到了response拦截failure中');if (err && err.response) {switch (err.response.status) {case 400:err.message ='请求错误'breakcase 401:err.message ='未授权的访问'break}}return err</code></pre><h1>Vue开发总结</h1><p><strong>VSCode开发简介:</strong></p><ul><li>我们在html文件上输入【!】叹号(在英文状态下),然后按键盘的【Tab】键,只有在这种情况下按住Tab键可以快速创建一个html模板。</li><li>代码缩进时只缩进两个空格。</li><li>开发快捷键:<br /> ①Ctrl + p:查找文件<br /> ②Ctrl + shift + f:全局搜索字符串<br /> ③Ctrl+j:切换终端<br /> ④Ctrl + b:显示/隐藏左侧目录栏<br /> ⑤Ctrl + shift + p,F1:显示所有命令<br /> ⑥拆分当前编辑窗口:Ctrl + \ ,Ctrl +1 2 3 4 等 在编辑窗口间切换<br /> ⑦选中方法名->Shift + F12,选中方法名->鼠标右键:显示引用 Show References</li><li>链接:VSCode Vue开发推荐插件和VSCode快捷键(小结)</li><li>插件:<br /> ①Volar 是一个 vscode 的插件,volar提供了非常卧槽的功能。</li></ul><p><strong>Vue开发简介:</strong></p><ul><li>src目录分析:<br /> ①apis:请求后台接口文件<br /> ②assets:资源文件,比如存放 css,图片等资源。<br /> ③component​:组件文件夹,用来存放 vue 的公共组件(注册于全局,在整个项目中通过关键词便可直接输出)<br /> ④router​:用来存放 ​index.js​,这个 js 用来配置路由<br /> ⑤views​:用来放主体页面,虽然和组件文件夹都是 vue 文件,但 views 下的 vue 文件是可以用来充当路由 view 的。<br /> ⑥store:Vuex状态管理文件<br /> ⑦tool​/utils:用来存放工具类 js,将 js 代码封装好放入这个文件夹可以全局调用(比如常见的​ api.js​,​http.js​ 是对 http 方法和 api 方法的封装)。<br /> ⑧request:http工具类,可以放在tool/utils中,也可以自定义一个文件夹。</li></ul></article></div><div class="related-posts"><h2 class="related-posts-title"><i class="fab fa-hive me-1"></i>相关文章</h2><div class="row g-2 g-md-3 row-cols-2 row-cols-md-3 row-cols-lg-4"><div class="col"><article class="post-item item-grid"><div class="tips-badge position-absolute top-0 start-0 z-1 m-2"></div><div class="entry-media ratio ratio-3x2"> <a target="" class="media-img lazy bg-cover bg-center" href="https://www.maxssl.com/article/31178/" title="python:给List添加元素" data-bg="/wp-content/themes/ripro-v5/assets/img/thumb.jpg"> </a></div><div class="entry-wrapper"><h2 class="entry-title"> <a target="" href="https://www.maxssl.com/article/31178/" title="python:给List添加元素">python:给List添加元素</a></h2></div></article></div><div class="col"><article class="post-item item-grid"><div class="tips-badge position-absolute top-0 start-0 z-1 m-2"></div><div class="entry-media ratio ratio-3x2"> <a target="" class="media-img lazy bg-cover bg-center" href="https://www.maxssl.com/article/20602/" title="神经网络:激活函数" data-bg="/wp-content/themes/ripro-v5/assets/img/thumb.jpg"> </a></div><div class="entry-wrapper"><h2 class="entry-title"> <a target="" href="https://www.maxssl.com/article/20602/" title="神经网络:激活函数">神经网络:激活函数</a></h2></div></article></div><div class="col"><article class="post-item item-grid"><div class="tips-badge position-absolute top-0 start-0 z-1 m-2"></div><div class="entry-media ratio ratio-3x2"> <a target="" class="media-img lazy bg-cover bg-center" href="https://www.maxssl.com/article/53034/" title="Vue使用fabric.js实现局部截图与大图预览功能" data-bg="https://img.maxssl.com/uploads/?url=https://img.jbzj.com/file_images/article/202402/2024022216581728.png"> </a></div><div class="entry-wrapper"><h2 class="entry-title"> <a target="" href="https://www.maxssl.com/article/53034/" title="Vue使用fabric.js实现局部截图与大图预览功能">Vue使用fabric.js实现局部截图与大图预览功能</a></h2></div></article></div><div class="col"><article class="post-item item-grid"><div class="tips-badge position-absolute top-0 start-0 z-1 m-2"></div><div class="entry-media ratio ratio-3x2"> <a target="" class="media-img lazy bg-cover bg-center" href="https://www.maxssl.com/article/10843/" title="【Pytorch】利用PyTorch实现图像识别" data-bg="https://img.maxssl.com/uploads/?url=https://img-blog.csdnimg.cn/cf97e28622e5477dbb237ed847f6b861.png"> </a></div><div class="entry-wrapper"><h2 class="entry-title"> <a target="" href="https://www.maxssl.com/article/10843/" title="【Pytorch】利用PyTorch实现图像识别">【Pytorch】利用PyTorch实现图像识别</a></h2></div></article></div><div class="col"><article class="post-item item-grid"><div class="tips-badge position-absolute top-0 start-0 z-1 m-2"></div><div class="entry-media ratio ratio-3x2"> <a target="" class="media-img lazy bg-cover bg-center" href="https://www.maxssl.com/article/12691/" title="一文搞定接口幂等性架构设计方案" data-bg="https://img.maxssl.com/uploads/?url=https://img2023.cnblogs.com/other/2893049/202304/2893049-20230420142559135-2006978238.png"> </a></div><div class="entry-wrapper"><h2 class="entry-title"> <a target="" href="https://www.maxssl.com/article/12691/" title="一文搞定接口幂等性架构设计方案">一文搞定接口幂等性架构设计方案</a></h2></div></article></div><div class="col"><article class="post-item item-grid"><div class="tips-badge position-absolute top-0 start-0 z-1 m-2"></div><div class="entry-media ratio ratio-3x2"> <a target="" class="media-img lazy bg-cover bg-center" href="https://www.maxssl.com/article/15506/" title="三步 让你的 vscode 自动编译ts文件" data-bg="https://img.maxssl.com/uploads/?url=https://img2023.cnblogs.com/blog/1055725/202305/1055725-20230504221103378-1777818163.png"> </a></div><div class="entry-wrapper"><h2 class="entry-title"> <a target="" href="https://www.maxssl.com/article/15506/" title="三步 让你的 vscode 自动编译ts文件">三步 让你的 vscode 自动编译ts文件</a></h2></div></article></div><div class="col"><article class="post-item item-grid"><div class="tips-badge position-absolute top-0 start-0 z-1 m-2"></div><div class="entry-media ratio ratio-3x2"> <a target="" class="media-img lazy bg-cover bg-center" href="https://www.maxssl.com/article/17255/" title="“前端”工匠系列(二):合格的工匠,怎么做好价值落地" data-bg="https://img.maxssl.com/uploads/?url=https://p3-sign.toutiaoimg.com/tos-cn-i-qvj2lq49k0/8f31618ea7d444209d8a8e8539112a51~noop.image?_iz=58558&from=article.pc_detail&x-expires=1684980311&x-signature=6W1RT7JAyi6527qUnQCboxM167s%3D"> </a></div><div class="entry-wrapper"><h2 class="entry-title"> <a target="" href="https://www.maxssl.com/article/17255/" title="“前端”工匠系列(二):合格的工匠,怎么做好价值落地">“前端”工匠系列(二):合格的工匠,怎么做好价值落地</a></h2></div></article></div><div class="col"><article class="post-item item-grid"><div class="tips-badge position-absolute top-0 start-0 z-1 m-2"></div><div class="entry-media ratio ratio-3x2"> <a target="" class="media-img lazy bg-cover bg-center" href="https://www.maxssl.com/article/32374/" title="【初识C语言】如何解决“关于未定义的标识符_Bool”" data-bg="https://img.maxssl.com/uploads/?url=https://img-blog.csdnimg.cn/7b7a2094aa30426fb0b37745ec160d36.png"> </a></div><div class="entry-wrapper"><h2 class="entry-title"> <a target="" href="https://www.maxssl.com/article/32374/" title="【初识C语言】如何解决“关于未定义的标识符_Bool”">【初识C语言】如何解决“关于未定义的标识符_Bool”</a></h2></div></article></div></div></div></div><div class="sidebar-wrapper col-md-12 col-lg-3 h-100" data-sticky><div class="sidebar"><div id="recent-posts-4" class="widget widget_recent_entries"><h5 class="widget-title">最新关注</h5><ul><li> <a href="https://www.maxssl.com/article/57859/">【MySQL】InnoDB存储引擎</a></li><li> <a href="https://www.maxssl.com/article/57858/">DB-GPT:强强联合Langchain-Vicuna的应用实战开源项目,彻底改变与数据库的交互方式</a></li><li> <a href="https://www.maxssl.com/article/57857/">TigerBeetle:世界上最快的会计数据库</a></li><li> <a href="https://www.maxssl.com/article/57856/">【SQL server】玩转SQL server数据库:第三章 关系数据库标准语言SQL(二)数据查询</a></li><li> <a href="https://www.maxssl.com/article/57855/">马斯克400条聊天记录被法院公开,原来推特收购是在短信上谈崩的</a></li><li> <a href="https://www.maxssl.com/article/57854/">戏精摩根大通:从唱空比特币到牵手贝莱德</a></li></ul></div><div id="ri_sidebar_posts_widget-2" class="widget sidebar-posts-list"><h5 class="widget-title">热文推荐</h5><div class="row g-3 row-cols-1"><div class="col"><article class="post-item item-list"><div class="entry-media ratio ratio-3x2 col-auto"> <a target="" class="media-img lazy" href="https://www.maxssl.com/article/31346/" title="自学(黑客技术)方法——网络安全" data-bg="https://img.maxssl.com/uploads/?url=https://img-blog.csdnimg.cn/aa40d580b9634cfea21dbfca465da962.png"></a></div><div class="entry-wrapper"><div class="entry-body"><h2 class="entry-title"> <a target="" href="https://www.maxssl.com/article/31346/" title="自学(黑客技术)方法——网络安全">自学(黑客技术)方法——网络安全</a></h2></div></div></article></div><div class="col"><article class="post-item item-list"><div class="entry-media ratio ratio-3x2 col-auto"> <a target="" class="media-img lazy" href="https://www.maxssl.com/article/19622/" title="【猿人学WEB题目专解】猿人学第6题" data-bg="https://img.maxssl.com/uploads/?url=https://img-blog.csdnimg.cn/427f145005904a6b9eb83bd421ee327d.png"></a></div><div class="entry-wrapper"><div class="entry-body"><h2 class="entry-title"> <a target="" href="https://www.maxssl.com/article/19622/" title="【猿人学WEB题目专解】猿人学第6题">【猿人学WEB题目专解】猿人学第6题</a></h2></div></div></article></div><div class="col"><article class="post-item item-list"><div class="entry-media ratio ratio-3x2 col-auto"> <a target="" class="media-img lazy" href="https://www.maxssl.com/article/36310/" title="校园圈子系统丨交友丨地图找伴丨二手市场等功能丨源码交付支持二开丨APP小程序H5三端交付!" data-bg="https://img.maxssl.com/uploads/?url=https://img-blog.csdnimg.cn/direct/a73331c10bb44b0fa5da9b52d424847c.png"></a></div><div class="entry-wrapper"><div class="entry-body"><h2 class="entry-title"> <a target="" href="https://www.maxssl.com/article/36310/" title="校园圈子系统丨交友丨地图找伴丨二手市场等功能丨源码交付支持二开丨APP小程序H5三端交付!">校园圈子系统丨交友丨地图找伴丨二手市场等功能丨源码交付支持二开丨APP小程序H5三端交付!</a></h2></div></div></article></div><div class="col"><article class="post-item item-list"><div class="entry-media ratio ratio-3x2 col-auto"> <a target="" class="media-img lazy" href="https://www.maxssl.com/article/18981/" title="commons.js:2 Channel: Error in handleResponse UNK/SW_UNREACHABLE options getValues" data-bg="https://img.maxssl.com/uploads/?url=https://img-blog.csdnimg.cn/9d91e363614845e0b07085f873225e99.png"></a></div><div class="entry-wrapper"><div class="entry-body"><h2 class="entry-title"> <a target="" href="https://www.maxssl.com/article/18981/" title="commons.js:2 Channel: Error in handleResponse UNK/SW_UNREACHABLE options getValues">commons.js:2 Channel: Error in handleResponse UNK/SW_UNREACHABLE options getValues</a></h2></div></div></article></div><div class="col"><article class="post-item item-list"><div class="entry-media ratio ratio-3x2 col-auto"> <a target="" class="media-img lazy" href="https://www.maxssl.com/article/24761/" title="【机器学习之模型融合】Stacking堆叠法" data-bg="https://img.maxssl.com/uploads/?url=https://img-blog.csdnimg.cn/59ede14b56bd49fa98031e098065591f.png"></a></div><div class="entry-wrapper"><div class="entry-body"><h2 class="entry-title"> <a target="" href="https://www.maxssl.com/article/24761/" title="【机器学习之模型融合】Stacking堆叠法">【机器学习之模型融合】Stacking堆叠法</a></h2></div></div></article></div><div class="col"><article class="post-item item-list"><div class="entry-media ratio ratio-3x2 col-auto"> <a target="" class="media-img lazy" href="https://www.maxssl.com/article/21156/" title="OpenXML库(office文档读写库)的安装" data-bg="https://img.maxssl.com/uploads/?url=https://img-blog.csdnimg.cn/img_convert/ff3087d3b6ec2b2d03672de6852d7b8d.png"></a></div><div class="entry-wrapper"><div class="entry-body"><h2 class="entry-title"> <a target="" href="https://www.maxssl.com/article/21156/" title="OpenXML库(office文档读写库)的安装">OpenXML库(office文档读写库)的安装</a></h2></div></div></article></div></div></div></div></div></div></div></main><footer class="site-footer py-md-4 py-2 mt-2 mt-md-4"><div class="container"><div class="text-center small w-100"><div>Copyright © <script>today=new Date();document.write(today.getFullYear());</script> maxssl.com 版权所有 <a href="https://beian.miit.gov.cn/" target="_blank" rel="nofollow noopener">浙ICP备2022011180号</a></div><div class=""><script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-7656930379472324" crossorigin="anonymous"></script></div></div></div></footer><div class="rollbar"><ul class="actions"><li><a target="" href="https://www.maxssl.com/" rel="nofollow noopener noreferrer"><i class="fas fa-home"></i><span></span></a></li><li><a target="" href="http://wpa.qq.com/msgrd?v=3&uin=6666666&site=qq&menu=yes" rel="nofollow noopener noreferrer"><i class="fab fa-qq"></i><span></span></a></li></ul></div><div class="back-top"><i class="fas fa-caret-up"></i></div><div class="dimmer"></div><div class="off-canvas"><div class="canvas-close"><i class="fas fa-times"></i></div><div class="logo-wrapper"> <a class="logo text" href="https://www.maxssl.com/">MaxSSL</a></div><div class="mobile-menu d-block d-lg-none"></div></div> <script></script><noscript><style>.lazyload{display:none}</style></noscript><script data-noptimize="1">window.lazySizesConfig=window.lazySizesConfig||{};window.lazySizesConfig.loadMode=1;</script><script async data-noptimize="1" src='https://www.maxssl.com/wp-content/plugins/autoptimize/classes/external/js/lazysizes.min.js'></script><script src='//cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.min.js' id='jquery-js'></script> <script src='//cdn.bootcdn.net/ajax/libs/highlight.js/11.7.0/highlight.min.js' id='highlight-js'></script> <script src='https://www.maxssl.com/wp-content/themes/ripro-v5/assets/js/vendor.min.js' id='vendor-js'></script> <script id='main-js-extra'>var zb={"home_url":"https:\/\/www.maxssl.com","ajax_url":"https:\/\/www.maxssl.com\/wp-admin\/admin-ajax.php","theme_url":"https:\/\/www.maxssl.com\/wp-content\/themes\/ripro-v5","singular_id":"1234","post_content_nav":"0","site_notify_auto":"0","current_user_id":"0","ajax_nonce":"bda523f326","gettext":{"__copypwd":"\u5bc6\u7801\u5df2\u590d\u5236\u526a\u8d34\u677f","__copybtn":"\u590d\u5236","__copy_succes":"\u590d\u5236\u6210\u529f","__comment_be":"\u63d0\u4ea4\u4e2d...","__comment_succes":"\u8bc4\u8bba\u6210\u529f","__comment_succes_n":"\u8bc4\u8bba\u6210\u529f\uff0c\u5373\u5c06\u5237\u65b0\u9875\u9762","__buy_be_n":"\u8bf7\u6c42\u652f\u4ed8\u4e2d\u00b7\u00b7\u00b7","__buy_no_n":"\u652f\u4ed8\u5df2\u53d6\u6d88","__is_delete_n":"\u786e\u5b9a\u5220\u9664\u6b64\u8bb0\u5f55\uff1f"}};</script> <script src='https://www.maxssl.com/wp-content/themes/ripro-v5/assets/js/main.min.js' id='main-js'></script> </body></html>