vue面试题

第2节 vue面试题(56道)#

摘讲#

  1. 02 vue-cli3搭建项目之webpack配置
  2. 15 vue虚拟dom ***
  3. 17 vue路由传参问题
  4. 25 vue hash 和history的区别 ***
  5. 20 Vue的响应式原理
  6. 28 v-if v-for 在哪个钩子函数中解析 ***
  7. 57 初识vue3(了解)
  8. 58 初识typescript(了解)
  9. 59 初识webpack

01 插件和组件的区别 **#

Vue组件(component)用来构成你的App的业务模块,它的目标是App.vue。 引入 ,注册,html中作为标签名的形式使用

  1. 请说下封装 vue 组件的过程?#

    答:

    1. 建立组件的模板,先把架子搭起来,写写样式,考虑好组件的基本逻辑。(os:思考1小时,码码10分钟,程序猿的准则。)
    2. 准备好组件的数据输入。即分析好逻辑,定好 props 里面的数据、类型。
    3. 准备好组件的数据输出。即根据组件逻辑,做好要暴露出来的方法。
    4. 封装完毕了,直接调用即可
  2. vue插件

    • Vue插件(plugin) 用来增强你的技术栈的功能模块, 它的目标是Vue本身。(插件是对Vue的功能的增强和补充)
    • 插件一般需要写成一个独立的js文件,需要安装,需要 引入,需要 use(使用) 插件的封装 ** 从零开始的vue插件封装 - 简书 我封装过tab标签的插件  ,封装过 弹窗的插件,封装过列表的插件,封装过瀑布式布局的插件 暴露的接口(可变的,用户可以向里面输入内容的,选择不同的显示状态的地方) , VUE常用插件库总结__Boboy的博客-CSDN博客_vue插件库

02 vue-cli3搭建项目之webpack配置#

vue-cli3搭建项目之webpack配置 - 码农教程

const path = require('path')

module.exports = {
  publicPath: './', // 基本路径,配置静态文件的访问路径
  outputDir: 'dist', // 输出文件目录
  lintOnSave: false, // 是否开启eslint检查
  // webpack配置
  chainWebpack: (config) => {
  },
  configureWebpack: (config) => {
    if (process.env.NODE_ENV === 'production') {
      // 为生产环境修改配置...
      config.mode = 'production'
    } else {
      // 为开发环境修改配置...
      config.mode = 'development'
    }
    Object.assign(config, {
      // 开发生产共同配置
      resolve: {
        // 别名配置
        alias: {
          '@': path.resolve(__dirname, './src'),
          '@c': path.resolve(__dirname, './src/components'),
          '@p': path.resolve(__dirname, './src/pages')
        } 
      }
    })
  },
  productionSourceMap: false, // 生产环境是否生成 sourceMap 文件
  // css相关配置
  css: {
    extract: true, // 是否使用css分离插件 ExtractTextPlugin
    sourceMap: false, // 开启 CSS source maps?
    loaderOptions: {
      css: {}, // 这里的选项会传递给 css-loader
      postcss: {} // 这里的选项会传递给 postcss-loader
    }, // css预设器配置项 详见https://cli.vuejs.org/zh/config/#css-loaderoptions
    modules: false // 启用 CSS modules for all css / pre-processor files.
  },
  parallel: require('os').cpus().length > 1, // 是否为 Babel 或 TypeScript 使用 thread-loader。该选项在系统的 CPU 有多于一个内核时自动启用,仅作用于生产构建。
  pwa: {}, // PWA 插件相关配置 
  // webpack-dev-server 相关配置
  devServer: {
    open: process.platform === 'darwin',
    host: '0.0.0.0', // 允许外部ip访问
    port: 8022, // 端口
    https: false, // 启用https
    overlay: {
      warnings: true,
      errors: true
    }, // 错误、警告在页面弹出
    proxy: {
      '/api': {
        target: 'http://www.baidu.com/api',
        changeOrigin: true, // 允许websockets跨域
        // ws: true,
        pathRewrite: {
          '^/api': '' // 重写路径
        }
      }
    } // 代理转发配置,用于调试环境
  },
  // 第三方插件配置
  pluginOptions: {}
}

vue3.0 vue.config.js 配置实战 - 给时光以生命 - 博客园

03 vue webpack打包优化:#

1.babel-plugin-component   ,减少js包的大小,将插件(如element-ui)和自己写的js分开打包,按需加载 2.路由懒加载:使用import(/webpackChunkName:"group-foo"/'./Foo.vue') 可以完成按需加载页面,避免首页加载内容过多而导致的白屏问题 3.使用 UglifyPlugin (webpack.optimize.UglifyJsPlugin)对代码进行压缩 4.使用该插件image-webpack-loader 进行图片压缩

1: 引入:
require("image-webpack-loader")
2:配置:
  module: {
    rules: [
    ...(config.dev.useEslint ? [createLintingRule()] : []),
    {
      test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
      loader: 'url-loader',
      options:   {
       loader: 'image-webpack-loader',
       options: {
        bypassOnDebug: true,
      }
    }
  },

5.由于webpack打包后的js过大,以至于在加载资源时间过长。所以将文件打包成多个js文件,在需要的时候按需加载

new commonsChunkPlugin({
 name:'charts',
 chunks:['commons'] 
 minChunks:function(module){
  return (
   module.resource &&
   /\.js$/.test(module.resource) &&
   module.resource.indexOf(
   path.join(__dirname, '../node_modules')
   ) === 0 && ['jquery.js', 'highcharts.js','echarts'].indexOf( module.resource.substr(module.resource.lastIndexOf('/')+1).toLowerCase() ) != -1
  )
 }
}) 
}

04 v-model的使用。 ***#

答:v-model用于表单数据的双向绑定,vue其实跟react一样是单向数据流, v-model它就是一个语法糖,这个背后就做了两个操作:

  1. v-bind绑定一个value属性;

  2. v-on指令给当前元素绑定input事件。

05 $nextTick的使用  ***#

答:当你修改了data的值然后马上获取这个dom元素的值,是不能获取到更新后的值, vue虚拟dom

06 vue初始化页面闪动问题 ***#

答:使用vue开发时,在vue初始化之前,由于div是不归vue管的,所以我们写的代码在还没有解析的情况下会容易出现花屏现象,看到类似于的字样,虽然一般情况下这个时间很短暂,但是我们还是有必要让解决这个问题的。 首先:在css里加上[v-cloak] { display: none; }。 如果没有彻底解决问题,则在根元素加上style="display: none;" :style="{display: 'block'}"

07 v-show和v-if指令的共同点和不同点? ***#

答: 共同点:都能控制元素的显示和隐藏; 不同点:实现本质方法不同,v-show本质就是通过控制css中的display设置为none,控制隐藏,只会编译一次;v-if是动态的向DOM树内添加或者删除DOM元素,若初始值为false,就不会编译了。而且v-if不停的销毁和创建比较消耗性能。 总结:如果要频繁切换某节点,使用v-show(切换开销比较小,初始开销较大)。如果不需要频繁切换某节点使用v-if(初始渲染开销较小,切换开销比较大)。

08 如何让CSS只在当前组件中起作用? ***#

答:在组件中的style前面加上scoped

09 vue优点? *#

答:轻量级框架:只关注视图层,是一个构建数据的视图集合,大小只有几十kb; 简单易学:国人开发,中文文档,不存在语言障碍 ,易于理解和学习; 双向数据绑定:保留了angular的特点,在数据操作方面更为简单; 组件化:保留了react的优点,实现了html的封装和重用,在构建单页面应用方面有着独特的优势; 视图,数据,结构分离:使数据的更改更为简单,不需要进行逻辑代码的修改,只需要操作数据就能完成相关操作; 虚拟DOM:dom操作是非常耗费性能的, 不再使用原生的dom操作节点,极大解放dom操作,但具体操作的还是dom不过是换了另一种方式; 运行速度更快:相比较与react而言,同样是操作虚拟dom,就性能而言,vue存在很大的优势。

10 写一个列表页需要考虑什么 *#

这是个开放性问题 需要在性能上考虑这个问题

  1. 渲染时列表数据过多考虑分页、考虑做上拉加载更多页
  2. 列表内容需要封装为组件,在页面调用
  3. 列表数据传参时需要做参数格式验证
  4. 列表上有图片时考虑使用图片的懒加载,可以使用插件实现

长列表优化:

  1. 将 table表格替换成其他标签 ,ul li ;
  2. 分页和 触底加载下一页;
  3. onScroll 防抖节流; 需要看一下防抖节流 防抖和节流的区别和实现

11 vue项目打包优化 *#

  1. 组件按需加载

  2. 路由懒加载

  3. 异步组件

  4. 图片压缩合并

  5. cdn加速

  6. 压缩代码

  7. 组件按需加载#

    这是首先可以优化的点。如果频繁使用了第三方组件/UI库,如我的项目中经常同时使用了 element-ui, vant-ui, mint-ui,echarts等组件库,如果全部引入,项目体积非常大,这时可以按需引入组件。

    示例如下:

    element-ui

    首先,安装 babel-plugin-component:

    npm install babel-plugin-component -D
    

    然后,将.babelrc 修改为:

    {
      "presets": [["es2015", { "modules": false }]],
      "plugins": [
        [
          "component",
          {
            "libraryName": "element-ui",
            "styleLibraryName": "theme-chalk"
          }
        ]
      ]
    }
    

    然后引入部分组件,这样一来,就不需要引入样式了,插件会帮我们处理。

    // main.js
    import Vue from 'vue'
    import { Dialog, Loading } from 'element-ui'
    
    Vue.use(Dialog)
    Vue.use(Loading.directive)
    Vue.prototype.$loading = Loading.service
    // 然后正常使用组件
    
  8. 路由懒加载#

    这里需要一个插件

    vue-router官方推荐syntax-dynamic-import插件,不过它要求同时安装@bable/core^7.0.0,如果你安装了babel-core6,是会有版本冲突的。我的做法如下

    npm install babel-plugin-syntax-dynamic-import --save-dev(^6.18.0)
    
    // router.js
    const login = () => import('@/components/login')
    const router = new VueRouter({
      routes: [
        { path: '/login', component: login }
      ]
    })
    

    还有一种魔法注释用法: 有时候我们想把某个路由下的所有组件都打包在同个异步块 (chunk) 中。只需要使用 命名 chunk,一个特殊的注释语法来提供 chunk name (需要 Webpack > 2.4)。

    const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue')
    
  9. 异步组件#

    如果组件在页面加载时不需要,只在调用时用到,这时可以使用异步组件的写法。仅仅是引入和组件注册写法不同

    // template
    <test v-if="showTest"></test>
    
    // script
      components: {
        test: () => import('./test') // 将组件异步引入,告诉webpack,将该部分代码分割打包
      },
      methods:{
          clickTest () {
              this.showTest = !this.showTest
        }
      }
    
  10. 图片的压缩合并#

    无损压缩图片:https://tinypng.com/

    如有可能,将图片制作成精灵图

  11. CDN加速#

    • 在index.html中引入cdn资源
      <head>
        <link href="https://cdn.bootcss.com/element-ui/2.13.0/theme-chalk/index.css" rel="stylesheet">
      </head>
      <body>
        <div id="app">
        </div>
        <!-- built files will be auto injected -->
        <script src="https://cdn.bootcss.com/vue/2.5.2/vue.min.js"></script>
        <script src="https://cdn.bootcss.com/vue-router/3.0.1/vue-router.min.js"></script>
        <script src="https://cdn.bootcss.com/vuex/3.0.1/vuex.min.js"></script>
        <script src="https://cdn.bootcss.com/vue-resource/1.5.1/vue-resource.min.js"></script>
        <script src="https://cdn.bootcss.com/element-ui/2.13.0/index.js"></script>
      </body>
    
    • 修改 build/webpack.base.conf.js
        module.exports = {
          context: path.resolve(__dirname, '../'),
          entry: {
            app: './src/main.js'
          },
          externals:{
            'vue': 'Vue',
            'vue-router': 'VueRouter',
            'vuex':'Vuex',
            'vue-resource': 'VueResource',
            'element-ui':'ELEMENT'
          },
          ...
        }
    
    • 修改src/main.js src/router/index.js 注释掉import引入的vue,vue-resource
        // import Vue from 'vue'
        // import VueResource from 'vue-resource'
        // Vue.use(VueResource)
        // 注释element-ui相关引入,注意如果使用了按需引入,这部分也要去掉
    
  12. 压缩代码#

    vue-cli已经使用UglifyJsPlugin 插件来压缩代码,可以设置成如下配置:

    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false,
        drop_console: true,
        pure_funcs: ['console.log']
      },
      sourceMap: false
    })
    

    其中sourceMap: false是禁用除错功能。

    如果设为true,在部署包中会生成.map结尾的js文件。它用于在代码混淆压缩的情况下仍可进行调试。这个功能虽好,但会大大增加整体资源包的体积,所以将其禁用。

    参考链接:

    vue项目打包优化策略

    Vue性能优化及Vue3.0的新特性

12 vue怎么做动画 *#

  1. Vue 提供了 transition 的封装组件#

    在下列情形中,可以给任何元素和组件添加进入/离开过渡

<div id="demo">
  <button v-on:click="show = !show"> Toggle</button>
  <transition name="fade"> <p v-if="show">hello</p></transition>
</div>
new Vue({
  el: '#demo',
  data: {show: true}
})

<style>
.fade-enter-active, .fade-leave-active { transition: opacity .5s;}
.fade-enter, .fade-leave-to /* .fade-leave-active below version 2.1.8 */ { opacity: 0;}  
</style>

过渡的类名 在进入/离开的过渡中,会有 6 个 class 切换。

(1) v-enter:定义进入过渡的开始状态。在元素被插入之前生效,在元素被插入之后的下一帧移除。
(2) v-enter-active:定义进入过渡生效时的状态。在整个进入过渡的阶段中应用,在元素被插入之前生效,在过渡/动画完成之后移除。这个类可以被用来定义进入过渡的过程时间,延迟和曲线函数。
(3) v-enter-to:2.1.8 版及以上定义进入过渡的结束状态。在元素被插入之后下一帧生效 (与此同时 v-enter 被移除),在过渡/动画完成之后移除。
(4) v-leave:定义离开过渡的开始状态。在离开过渡被触发时立刻生效,下一帧被移除。
(5) v-leave-active:定义离开过渡生效时的状态。在整个离开过渡的阶段中应用,在离开过渡被触发时立刻生效,在过渡/动画完成之后移除。这个类可以被用来定义离开过渡的过程时间,延迟和曲线函数。
(6) v-leave-to:2.1.8 版及以上定义离开过渡的结束状态。在离开过渡被触发之后下一帧生效 (与此同时 v-leave 被删除),在过渡/动画完成之后移除。
  1. 还可以使用css3的动画效果:#

.bounce-enter-active {animation: bounce-in .5s;}
.bounce-leave-active { animation: bounce-in .5s reverse;}
@keyframes bounce-in {
  0% { transform: scale(0); }
  50% {  transform: scale(1.5);}
  100% { transform: scale(1);}
}
  1. 可以使用 js钩子#

<transition
  v-on:before-enter="beforeEnter"
  v-on:enter="enter"
  v-on:after-enter="afterEnter"
  v-on:enter-cancelled="enterCancelled"
  v-on:before-leave="beforeLeave"
  v-on:leave="leave"
  v-on:after-leave="afterLeave"
  v-on:leave-cancelled="leaveCancelled"
>
  <!-- ... -->
</transition>
methods: {
  // --------// 进入中// --------
  beforeEnter: function (el) {   // ...},
  // 当与 CSS 结合使用时 // 回调函数 done 是可选的
  enter: function (el, done) { // ... done() },
  afterEnter: function (el) {  // ...},
  enterCancelled: function (el) { // ...},
  // -------- // 离开时 // --------
 beforeLeave: function (el) {  // ...},
  // 当与 CSS 结合使用时
  // 回调函数 done 是可选的
  leave: function (el, done) { // ... done() },
  afterLeave: function (el) {// ...},
  // leaveCancelled 只用于 v-show 中
  leaveCancelled: function (el) { // ... }
}
  1. 可以引入Velocity#

13 空#

14 vue3新特性#

  1. 更快#

    • 虚拟DOM重写

    • 优化slots的生成

    • 静态树提升

    • 静态属性提升

    • 基于Proxy的响应式系统

  2. 更小:#

    通过摇树优化核心库体积

  3. 更容易维护:#

    1. TypeScript + 模块化
  4. 更加友好#

    跨平台:编译器核心和运行时核心与平台无关,使得Vue更容易与任何平台(Web、Android、iOS)一起使用

  5. 更容易使用#

    • 改进的TypeScript支持,编辑器能提供强有力的类型检查和错误及警告
  6. 更好的调试支持#

  7. 独立的响应化模块#

  8. Composition API(组合式API)#

Vue性能优化及Vue3.0的新特性 - bob_zb - 博客园

15 vue虚拟dom ***#

  1. 我们都知道在前端性能优化的一个秘诀就是尽可能少地操作DOM,不仅仅是DOM相对较慢,更因为频繁变动DOM会造成浏览器的回流或者重绘,这些都是性能的杀手
  2. 现在的框架, 不管是vue还是react都有虚拟dom,虚拟dom是在内存生成一个虚拟的dom对象,来记录对应的真实dom节点的属性和方法,这样避免了直接操作真实dom节点,提高性能

16 vuex  *#

vuex 流程

  1. 在组件中使用dispatch 将状态值分发action;
  2. 在actions中将 状态值commit提交到 mutations;
  3. 在mutations中修改store中的状态值;
  4. 当状态值发生变化时,自动触发render重新渲染页面。

vuex核心概念

  1. vuex 属性  state action mutation module getter
  2. vuex action  mutation 区别  :action 可以异步, 大数据量的操作;mutation 可以直接更改store中的数据值
  3. vuex getters 作用  相当于vue组件中的计算属性
  4. vuex辅助函数  mapState mapAction mapMutation mapGetter

vuex与缓存区别

  1. vuex刷新后数据就没有了,localStorage刷新后值还存在
  2. vuex是响应式的,localStorage不是响应式的
  3. vuex数据持久化 vuex-persistedstate

17 vue路由传参问题#

  1. vue从a页面跳到b页面,b页面的值是从a页面带过来的,b页面刷新,a页面带过来的值没有了怎么解决?

    答: 使用动态路由传参或者query传参可以解决此问题

  2. vue从a页面跳到b页面,操作一番后, 再跳回a页面, 发a页面的值没有, 是怎么回事, 怎么解决?

    原因: a页面也是从别的页面跳过来的, 带有参数, 从b页面跳回来的时候没有带参数, 所有会到a页面, a页面的值就没有了

    解决方案1: a页面跳到b页面的时候把上个页面传给它的参数都传给b页面, 从b页面回来的时候, 把参数带回来

    解决方案2: 使用vuex

18 Vue生命周期 *#

  1. 什么是 vue 生命周期?有什么作用?#

    答:每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听、编译模板、将实例挂载到 DOM 并在数据变化时更新 DOM 等。同时在这个过程中也会运行一些叫做 生命周期钩子 的函数,这给了用户在不同阶段添加自己的代码的机会。(ps:生命周期钩子就是生命周期函数)例如,如果要通过某些插件操作DOM节点,如想在页面渲染完后弹出广告窗, 那我们最早可在mounted 中进行。

  2. 第一次页面加载会触发哪几个钩子?#

    答:beforeCreate, created, beforeMount, mounted

  3. 简述每个周期具体适合哪些场景#

    答:beforeCreate:在new一个vue实例后,只有一些默认的生命周期钩子和默认事件,其他的东西都还没创建。在beforeCreate生命周期执行的时候,data和methods中的数据都还没有初始化。不能在这个阶段使用data中的数据和methods中的方法 create:data 和 methods都已经被初始化好了,如果要调用 methods 中的方法,或者操作 data 中的数据,最早可以在这个阶段中操作 beforeMount:执行到这个钩子的时候,在内存中已经编译好了模板了,但是还没有挂载到页面中,此时,页面还是旧的 mounted:执行到这个钩子的时候,就表示Vue实例已经初始化完成了。此时组件脱离了创建阶段,进入到了运行阶段。 如果我们想要通过插件操作页面上的DOM节点,最早可以在和这个阶段中进行 beforeUpdate: 当执行这个钩子时,页面中的显示的数据还是旧的,data中的数据是更新后的, 页面还没有和最新的数据保持同步 updated:页面显示的数据和data中的数据已经保持同步了,都是最新的 beforeDestory:Vue实例从运行阶段进入到了销毁阶段,这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于可用状态。还没有真正被销毁 destroyed: 这个时候上所有的 data 和 methods , 指令, 过滤器 ……都是处于不可用状态。组件已经被销毁了。

  4. created和mounted的区别#

    答:created:在模板渲染成html前调用,即通常初始化某些属性值,然后再渲染成视图。 mounted:在模板渲染成html后调用,通常是初始化页面完成后,再对html的dom节点进行一些需要的操作。

  5. vue获取数据在哪个周期函数#

    答:一般 created/beforeMount/mounted 皆可. 比如如果你要操作 DOM , 那肯定 mounted 时候才能操作.

  6. 请详细说下你对vue生命周期的理解?#

    答:总共分为8个阶段创建前/后,载入前/后,更新前/后,销毁前/后。 创建前/后: 在beforeCreated阶段,vue实例的挂载元素el和数据对象data都为undefined,还未初始化。在created阶段,vue实例的数据对象data有了,el还没有。 **载入前/后:**在beforeMount阶段,vue实例的$el和data都初始化了,但还是挂载之前为虚拟的dom节点,data.message还未替换。在mounted阶段,vue实例挂载完成,data.message成功渲染。 **更新前/后:**当data变化时,会触发beforeUpdate和updated方法。 **销毁前/后:**在执行destroy方法后,对data的改变不会再触发周期函数,说明此时vue实例已经解除了事件监听以及和dom的绑定,但是dom结构依然存在。 *** Vue 的父组件和子组件生命周期钩子函数执行顺序可以归类为以下 4 部分:

    加载渲染过程 父 beforeCreate -> 父 created -> 父 beforeMount -> 子 beforeCreate -> 子 created -> 子 beforeMount -> 子 mounted -> 父 mounted

19 vue插槽 ***#

  1. 在父组件调用子组件时,写在子组件标签中间的的内容,可以传递到子组件的slot标签的相应位置;
  2. 使用场景:类似于element-ui里面的组件封装,对组件的扩展,
  3. 插槽分类
    • 匿名插槽:没名字
    • 具名插槽:有名字
    • 作用域插槽:所以作用域插槽是一种子传父传参的方式,解决了普通slot在parent中无法访问child数据的去问题

20 Vue的响应式原理, *#

  1. 核心原理:#

    ​ vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

     // Object.defineProperty例子解释
     <!DOCTYPE html>
     <html lang="en">
     
     <head>
         <meta charset="UTF-8">
         <meta name="viewport" content="width=device-width, initial-scale=1.0">
         <title>Document</title>
     </head>
     
     <body>
         <div>
             <input type="text" id="input">
             <span id="text"></span> <br/><br/>
     
             <button onclick="click1()">取值</button>
             <button onclick="click2()">修改</button>
     
         </div>
     </body>
     
     </html>
     <script>
         var obj = {};
         Object.defineProperty(obj, 'msg', {
             get: function () {
                 console.log('get')
                 return window.val&&val;
             },
             set: function (newVal) {
                 console.log('set');
                 val = newVal;
                 document.getElementById('text').innerHTML = val;
                 document.getElementById('input').value = val;
             }
         });
         document.addEventListener('keyup', function (e) {
             obj.msg = e.target.value;
         });
     
         function click1() {
             let msg = obj.msg;
             console.log('msg的值:',msg);
         }
     
         function click2() {
             obj.msg = 'hello';
         }
     </script>
    
  2. 整体思路(具体实现)#

    vue数据双向绑定是通过数据劫持结合发布者-订阅者模式的方式来实现的。实现步骤:

    1. 在vue框架里编写一个监听器Observer,用来劫持并监听所有属性,如果有变动的,就通知订阅者。
    2. 在vue框架里编写一个订阅者Watcher,每一个Watcher都绑定一个更新函数,watcher可以收到属性的变化通知并执行相应的函数,从而更新视图。
    3. 在vue框架里编写一个解析器Compile,可以扫描和解析每个节点的相关指令(v-model,v-on等指令),如果节点存在v-model,v-on等指令,则解析器Compile初始化这类节点的模板数据,使之可以显示在视图上,然后初始化相应的订阅者(Watcher)。
    <!DOCTYPE html>
    <html lang="en">
    <head>  
        <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.js"></script>
    </head>
    <body>
        <div id="app"> </div> 
    
        <script>
            new Vue({
                el: '#app',
                data: {
                    msg: 'hello',
                    username: '张三'
                },
                template: `
                <div>
                    <button @click="handClick">修改msg</button>
                    <button @click="handClick2">修改username</button>
                    <p>{{msg}} {{username}}</p>
                </div>`,
    
                methods: {
                    handClick() {
                        this.msg = 'hi';
                    },
                    handClick2() {
                       this.username = '李四';
                    }
                }
            })
        </script>
    </body> 
    </html>
    

  1. vue2和vue3对比#

    1. Vue32020年9月发布的正式版本
    2. Vue3支持大多数的Vue2的特性
    3. Vue3设计了一套强大的组合API替代了Vue2中的option API, 复用性更强了
    4. 更好的支持TS
    5. 最主要: Vue3中使用了Proxy配合Reflect 替代了Vue2中Object.defineProperty() 方法实现数据的响应式(数据代理)
    6. 重写了虚拟DOM, 速度更快了
    7. 新的组件: Fragment(片段) / Teleport(瞬移) / Suspense(不确定)
    8. 设计了一个新的教授叫工具, Vite
  2. vue3.0响应式原理:#

    1. Vue3.x是用ES6的语法 Proxy对象来实现的,这个玩意儿也可以实现数据的劫持
    2. 相比于vue2.x,使用proxy的优势如下
      • defineProperty只能监听某个属性,不能对全对象监听
      • 可以省去for in、闭包等内容来提升效率(直接绑定整个对象即可)
      • 可以监听数组,不用再去单独的对数组做特异性操作
      • vue3.x可以检测到数组内部数据的变化 vue2.0与vue3.0 双向数据绑定原理 区别 - HOUY - 博客园
  3. mvvm框架(补充了解)#

    MVVM是Model-View-ViewModel的简写

    1. Model 数据模型,用来存储数据

    2. View 视图界面,用来展示UI界面和响应用户交互

    3. ViewModel 视图模型, 每一个vue组件的实例都是一个ViewModel

  4. MVC框架 (补充了解)#

    Model-View- Controller的简写, angular.js就是mvc框架, 很多后台语言用的也是mvc架构

    1. Model 数据模型,用来存储数据
    2. Controller 控制器
    3. View 视图界面,用来展示UI界面和响应用户交互

21 vue-router实现路由懒加载( 动态加载路由 )#

vue项目实现路由按需加载(路由懒加载)的3种方式_小胖梅的博客-CSDN博客_vue路由懒加载 答:三种方式 第一种:vue异步组件技术 ==== 异步加载,vue-router配置路由 , 使用vue的异步组件技术 , 可以实现按需加载 .但是,这种情况下一个组件生成一个js文件。 第二种:路由懒加载(使用import)。 第三种:webpack提供的require.ensure(),vue-router配置路由,使用webpack的require.ensure技术,也可以实现按需加载。这种情况下,多个路由指定相 同的chunkName,会合并打包成一个js文件。

22 Vue实现弹窗组件需要暴露哪些接口 ***#

例如:暴露了width、title、确定按钮、取消按钮的事件函数、弹窗的内容,

<div id="app">
      <base-dialog width="30%" title="我的标题" :visible.sync="dialogVisible">
        <span>我是模态框的主体内容</span>
        <span slot="footer">
          <button class="btn danger">取消</button>
          <button class="btn primary">确定</button>
        </span>
      </base-dialog>
      <button @click="showM">显示模态框</button>
    </div>
    
    <!--模板-->
    <script type="text/template" id="myDialog">
      <div class="myDialog" v-if="visible">
        <div id="dialogMain" :style="{'width':width}" >
          <div id="dialogHeader">
            <span>{{title}}</span>
            <span @click="hiddenM">×</span>
          </div>
          <div id="dialogContent">
            <slot></slot>
          </div>
          <div id="dialogFooter">
            <slot name="footer"></slot>
          </div>
        </div>
      </div>
    </script>
    
    <script type="text/javascript">
      //1.创建模态框组件
      Vue.component('base-dialog',{
        props:['width','title','visible'],
        template:'#myDialog',
        methods:{
          hiddenM:function(){
            //将子组件的模态框的状态值传递给 父组件
            this.$emit('update:visible');
          }
        }
      });
      /***************************************************/
      var vm = new Vue({
        el:"#app",
        data:{
          dialogVisible:false
        },
        methods:{
          showM:function(){
            this.dialogVisible =true;
          }
        }
        
      })
    </script>

23 Vue路由 ***#

  1. 路由创建
  2. 路由跳转
  3. 路由传参
  4. 路由模式(25点)

24 路由守卫,路由钩子 ***#

  1. 全局钩子  beforeEach(全局前置守卫,如果你的项目中有一个以上的功能需要守卫建议使用 这个)  afterEach  beforeResolve (解析守卫)
  2. 某个路由的钩子   beforeEnter
  3. 组件内钩子
    • beforeRouteEnter
    • beforeRouteUpdate (2.2 新增)
    • beforeRouteLeave
  4. 参数:from  to  next
  5. 路由懒加载
  6. 子路由

25 vue hash 和history的区别 ***#

  1. 为什么需要路由#

    • 因为现在的项目, 绝大部分都是单页应用(Single page application, 简称spa)
    • 单页应用的特点就是"单页", 也就是只有一个html页面, 以前使用location.href进行跳转的日子结束了, 所以就需要一种新的跳转方式
  2. 前端路由主要有两种实现方法:#

    • Hash 路由
    • History 路由
  3. Hash 路由#

    1. url 的 hash 是以 # 开头,原本是用来作为锚点,从而定位到页面的特定区域。当 hash 改变时,页面不会因此刷新,浏览器也不会向服务器发送请求。
    2. 同时, hash 改变时,并会触发相应的 hashchange 事件。所以,hash 很适合被用来做前端路由。当 hash 路由发生了跳转,便会触发 hashchange 回调,回调里可以实现页面更新的操作,从而达到跳转页面的效果。
    <!DOCTYPE html>
    <html lang="en"> 
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
        <style>
            body {
                background-color: gray;
            } 
            footer {
                height: 50px;
                display: flex;
                justify-content: space-around;
                position: fixed;
                bottom: 0;
                width: 100%;
                background-color: #fff;
                align-items: center;
            }
        </style>
    </head>
    
    <body>
        <div id="app"></div> 
    
        <footer>
            <a href="#">首页</a>
            <a href="#cart">购物车</a>
            <a href="#my">我的</a>
        </footer>
    
        <script>
            let $app = document.getElementById('app');
            window.onhashchange = function (a, b, c) {
                render();
            }
    
            function render() {
                let hash = window.location.hash.slice(1);
                switch (hash) {
                    case 'my':
                        $app.innerHTML = '<h3>我的</h3>';
                        break;
                    case 'cart':
                        $app.innerHTML = '<h3>购物车</h3>';
                        break;
                    default:
                        $app.innerHTML = '<h3>首页</h3>';
                }
            }
            render();
        </script>
    </body> 
    </html>
    
    1. history路由#

      1. HTML5 规范中提供了 history.pushState 和 history.replaceState 来进行路由控制。通过这两个方法,可以实现改变 url 且不向服务器发送请求。同时不会像 hash 有一个 # ,更加的美观。但是 History 路由需要服务器的支持,并且需将所有的路由重定向到根页面。

      2. 有以下两种方式会改变 url:

        1. 调用 history.pushState 或 history.replaceState, 给其绑定一个渲染方法, 实现页面的改变;

          function push (url) {
           window.history.pushState({}, null, url);
           render();
          }
           
          function render () {
           console.log('渲染页面');
          }
          
        2. 点击浏览器的前进与后退, 浏览器的前进与后退会触发 popstate 事件。给事件绑定渲染页面的方法, 实现页面的改变

          window.addEventListener('popstate', render);
          
          function render () {
           console.log('渲染页面');
          }
          

        ​ https://www.jb51.net/article/143009.htm

26 Vue使用函数式组件还是类组件 *#

Vue 函数式组件原理和使用详解_陆小森_红齐飘飘的博客-CSDN博客_vue 函数式组件 ##12. vue页面第一次渲染执行的几个钩子函数 beforeCreate created beforeMounte mounted

27 vue页面跳转时执行那几个钩子, ***#

  1. beforeCreate
  2. created
  3. beforeMounte
  4. mounted
  5. beforeDestory
  6. destoryed

28  v-if v-for 在哪个钩子函数中解析 ***#

当 Vue 处理指令时,v-for 比 v-if 具有更高的优先级 避免 v-if 和 v-for 用在一起必要 永远不要把 v-if 和 v-for 同时用在同一个元素上

// 错误写法
<template>
	<ul>
		<li v-for="list" v-if="item.flag">{{item.name}}</li>
	</ul> 
</template> 

// 正确写法
<template>
	<ul>
		<li v-for="list.filter(item=>item.flag)">{{item.name}}</li>
	</ul> 
</template> 

// 正确写法2: 使用computed
<template>
	<ul>
		<li v-for="list2">{{item.name}}</li>
	</ul> 
</template> 


<script>
export default {
    data() {
        return {list:[
            {flag: tue,name:'aa'},
            {flag: false,name:'bb'},
            {flag: tue,name:'cc'},
        ]}
    },

    computed: {
        list2() {
                return this.list.filter(item=>item.flag)
        }
    }
}
</script>


29 vue前端路由原理  路由模式#

history  hash    html5 历史记录

30 计算属性#

计算属性 watch  ,计算属性就是当其依赖属性的值发生变化时,这个属性的值会自动更新,与之相关的DOM部分也会同步自动更新。 计算属性有缓存,计算属性的函数会自动调用。普通函数需要手动触发 计算属性和watch  ,异步操作或大数据量操作使用watch 1.watch擅长处理的场景:一个数据影响多个数据 2.computed擅长处理的场景:一个数据受多个数据影响

<!DOCTYPE html>
<html lang="en"> 
<head> 
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.13/vue.min.js"></script>
</head> 
<body>
    <div id="app">
        <ul>
            <li>{{sum}}</li>
            <li>{{sum}}</li>
            <li>{{sum}}</li>
        </ul>

        <ul>
            <li>{{add()}}</li>
            <li>{{add()}}</li>
            <li>{{add()}}</li>
        </ul>
    </div>
 
    <script>
        new Vue({
            el: '#app',
            data: {
                a: 2,
                b: 3
            },
            methods: {
                add() {
                    console.log('methods');
                    return this.a + this.b;
                }
            },

            computed: {
                sum() {
                    console.log('computed');
                    return this.a + this.b;
                }
            }
        })
    </script>
</body>

</html>

vue中,计算属性 computed 和 watch 的区别 - 简书

31 以下全局属性都是做什么用的 **#

$props $attrs $listeners el $options $refs $watch() $emit $on $off $once

32 vue和jquery的区别 *#

jquery对dom操作 是单向的 vue 使用双向绑定

33 $route $router的区别  ***#

33 $route $router的区别  ***#

$route对象表示当前的路由信息,包含了当前 URL 解析得到的信息。包含当前的路径,参数,query对象等。 $router对象是全局路由的实例,是router构造方法的实例。路由实例方法有: push:跳转到一个新页面,push方法的跳转会向 history 栈添加一个新的记录,当我们点击浏览器的返回按钮时可以看到之前的页面。 go前进或后退 replace:push方法会向 history 栈添加一个新的记录,而replace方法是替换当前的页面, 不会向 history 栈添加一个新的记录

34 vue组件中data为什么必须是一个函数? *#

答:因为JavaScript的特性所导致,在component中,data必须以函数的形式存在,不可以是对象。   组建中的data写成一个函数,数据以函数返回值的形式定义,这样每次复用组件的时候,都会返回一份新的data,相当于每个组件实例都有自己私有的数据空间,它们只负责各自维护的数据,不会造成混乱。而单纯的写成对象形式,就是所有的组件实例共用了一个data,这样改一个全都改了。

35 vue后台项目怎么做拦截 ***#

axios 请求拦截  ,验证token ,防攻击 全局路由守卫,除了登录页面,其他页面都需要守卫 token有过期时间,在后台管理,如果过期了,会跳转到登录页,再重新获取token,token 保存到缓存

36  v-if v-show区别为什么v-show没有else  ***#

v-if dom节点改变  少量切换使用 v-show 是css样式修改 大量切换使用show

37 vue常用的修饰符 *#

答:.stop:等同于JavaScript中的event.stopPropagation(),防止事件冒泡; .prevent:等同于JavaScript中的event.preventDefault(),防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播); .capture:与事件冒泡的方向相反,事件捕获由外到内; .self:只会触发自己范围内的事件,不包含子元素; .once:只会触发一次。

38 vue初始化页面闪动问题  ***#

答:使用vue开发时,在vue初始化之前,由于div是不归vue管的,所以我们写的代码在还没有解析的情况下会容易出现花屏现象,看到类似于的字样,虽然一般情况下这个时间很短暂,但是我们还是有必要让解决这个问题的。 首先:在css里加上[v-cloak] { display: none; }。 如果没有彻底解决问题,则在根元素加上style="display: none;" :style="{display: 'block'}"

39 为什么有时候修改了值,可以打印修改的值,但是页面上不会改变#

由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。尽管如此我们还是有一些办法来回避这些限制并保证它们的响应性。 对于对象: Vue 无法检测 property 的添加或移除 Vue 不能检测以下数组的变动: 当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue 当你修改数组的长度时,例如:vm.items.length = newLength 当页面上的值不发生变化时,可以使用 $.set 对象还可以使用 :assign 数组还可以使用:splice Vue 将被侦听的数组的变更方法进行了包裹,所以它们也将会触发视图更新。push() pop() shift() unshift() splice() sort() reverse() 也有非变更方法,例如 filter()、concat() 和 slice()。它们不会变更原始数组,而总是返回一个新数组。

40 用过哪些vue ui组件  element ui里面的#

41 vue项目首页加载图标和地图插件很慢怎么解决  ??#

42 vue组件传参  *#

父传子 : props接收 子传父: $emit 手动触发自定义事件  (因为 vue组件间传递数据时单向的) 兄弟: bus  vuex(我) vue组件传参,调用方法的几种方式_kangkang_95的博客-CSDN博客_vue组件传参vue中8种组件传参方式

  1. props/$emit
  2. $children/ $parent
  3. provideinjectprovideinject 是vue2.2.0新增的api, 简单来说就是父组件中通过provide来提供变量, 然后再子组件中通过inject来注入变量。

概念:

注意: 这里不论子组件嵌套有多深, 只要调用了inject 那么就可以注入provide中的数据,而不局限于只能从当前父组件的props属性中回去数据

4.ref / refs 5.eventBus 6.Vuex 7.localStorage / sessionStorage 8.$attrs与 $listeners 在vue2.4中,为了解决该需求,引入了$attrs 和$listeners , 新增了inheritAttrs 选项。 在版本2.4以前,默认情况下,父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外),将会“回退”且作为普通的HTML特性应用在子组件的根元素上

43 vue的路由守卫,原理  ?#

44 vue的动态组件有哪些,是怎样实现的  ***#

和计算属性一起使用的,组件的名字可以更改的组件 一般的动态组件的外面合一使用keep-alive进行缓存

45 怎样通过refs获取子组件的数据和方法 *#

<template>
  <div>
    <children ref='ch'>
    </children>
    <h1 @click="onclick">父组件</h1>
  </div>
</template>

<script>
import children from './coms/children'
export default {
  data() {
    return {}
  },
  components: {
    children
  },
  methods: {
    onclick() {
    // 或者 let chil = this.$refs['ch']
      let chil = this.$refs.ch

    // 父组件可以通过$refs拿到子组件的对象
    // 然后直接调用子组件的 methods里的方法和data里的数据
      console.log(chil) //子组件对象
      console.log(chil.sonData) // 我是子组件的数据
      console.log(chil.sonMethod()) // 我是子组件的方法
    }
  }
}
</script>

46 vue如何创建一个路由表 **#

  • 31.1 引入 vue-router
  • 31.2 使用 路由 插件 Vue.use(VueRouter);
  • 31.3 定义路由表  写路由表中的配置信息path(路径)  component(跳转到的组件)  name(名称)  meta(路由原信息)
const routes = [
  {"path":"/","component":recommend},
  {"path":"/mymask","component":mymask}
];
  • 31.4 创建路由对象 new vueRouter
const router = new VueRouter({
	routes:routes
})

47 nextTick的作用 ***#

答:当你修改了data的值然后马上获取这个dom元素的值,是不能获取到更新后的值, 你需要使用$nextTick这个回调,让修改后的data值渲染更新到dom元素之后在获取,才能成功。

48 vue3.0将mixin替换成了Composition API  ***#

49 vue项目中哪些部分使用了全局管道符,哪些地方使用了局部的 *#

filter 过滤器  后台项目 ,

50 vue项目中你做过哪些复杂编写,遇到的问题 ,解决方法  *#

  1. 从详情页返回列表时保存浏览位置 用到keep-alive来缓存页面 当详情页中改变列表数据时,配合keep-alive,需要在vue钩子函数activated中,对数据进行更改 activated keep-alive组件激活时调用。 deactivated keep-alive组件停用时调用。 1.用到keep-alive来缓存页面 2.当详情页中改变列表数据时,配合keep-alive,需要在vue钩子函数activated中,对数据进行更改 3.在从其他页面进入时,页面要重新加载数据。页面从列表进入其他页面(非详情页)时,销毁当前的vue实例。此时需用到组件内的路由守卫,beforeRouteEnter和beforeRouteLeave vue中keep-alive的使用及详解_半度℃温热的博客-CSDN博客_keep-alive详解vue组件的keep-alive - 古兰精 - 博客园
  2. 路由全局守卫        router.beforeEach(to,from,next) 当从一个路由跳转到另一个路由时触发此守卫,也叫全局前置守卫。 所以它是跳转前触发的。任何路由跳转都会触发。 每个守卫都有三个参数: to:这是你要跳去的路由对象; from:这是你要离开的路由对象; next:是一个方法,它接收参数; next()    跳转 next(flase)  中断跳转 next({path:"/"}) 中断跳转,跳转到一个新的路径
  3. axios拦截器 使用axios 实现登录功能的流程(拦截器) 先添加拦截器判断, 利用interceptors 调用request ,判断token 是否存在,如果存在,直接跳转

axios拦截器: // 请求拦截,可以将请求的配置进行二次处理。 axios.interceptors.request.use(config=>{ // config 是axios的配置信息. // console.log(config); if(localStorage.token){ config.headers = { authorization:localStorage.token //将 token的值在 header中传给后台,在后台判断token是否正确 } } store.commit("CHANGE_LOADING",true); config.url = "/ele"+config.url; return config; }) // 响应拦截  数据没出来时的旋转小图标,报错码对应的报错信息的提示,正确获取数据,返回 promise对象 axios.interceptors.response.use(({data})=>{ console.log(44444444); // 返回的值即是axios得到的值 store.commit("CHANGE_LOADING",false); if(data.ok === 2 || data.ok === 3){ store.commit("OUT_LOGIN"); }else{ return data; }

  1. css引用图片打包后找不到文件资源的问题 css引入图片再打包后,style-loader无法设置自己的publicPath,所以只要改变style-loader中的publicPath即可,一行代码即可以搞定, 找到build/util.js文件中ExtractTextPlugin的css路径,手动添加publicPath参数, if (options.extract) { return ExtractTextPlugin.extract({ use: loaders, publicPath: '../../', fallback: 'vue-style-loader' }) } else { return ['vue-style-loader'].concat(loaders) } 重新build一次,问题解决了
  2. mixin 可以提高代码的复用性,同时减少代码的耦合度,但是另一方面给代码维护造成了不小的困扰,用的时候需要衡量其使用频率。 比如后台项目:添加 、修改,下拉级联菜单,数据,请把它放到 mixin中,在添加和修改页面中调用就可以了 前台:好多个页面都有 筛选、分页、上拉夹杂爱更多、排序,只要功能是重复出现的,请封装到mixin中 3.0时用新的 Composition API 提供了更好的解决方案
  3. 多了解一下vue的生命周期,包括公开的以及未公开的,必要时可以方便写个vue插件,在生命周期函数中注入新的功能,包括新的钩子函数,或者新的业务集成。比如:keep-alive的两个钩子
  4. 如有必要,beforeDestory钩子中手动回收一些变量或者注销一些事件,培养自己垃圾回收的意识,以免出现内存问题。如:定时器、事件的解除绑定、轮播的停止等
  5. 状态需要统一管理时考虑使用 vuex  ,项目中哪个地方使用了?购物车、用户登录后的数据(比如:用户名、用户权限、用户的相关信息,)、 左侧菜单的打开或关闭,从后台获取的异步数据
  6. mounted钩子函数中请求数据导致页面闪屏问题 其实就是加载时机问题,放在created里会比mounted触发早一点,如果在页面挂载完之前请求完成的话就不会看到闪屏了
  7. el-input手动获取焦点问题 情景:输入框一开始是隐藏的,点击按钮显示输入框并获取焦点 把手动获取焦点那段代码写在nextTick(() => { this.$refs.searchBox.focus() })

vue项目中遇到的问题汇总 - 简书该回答已被删除 - 知乎

51 vue中v-html会导致哪些问题  *#

你的站点上动态渲染的任意 HTML 可能会非常危险,因为它很容易导致 XSS 攻击。请只对可信内容使用 HTML 插值,绝不要对用户提供的内容使用插值。 可能会导致xss攻击 V-html更新的是元素的 innerHTML 。内容按普通 HTML 插入, 不会作为 Vue 模板进行编译 。 但是有的时候我们需要渲染的html片段中有插值表达式,或者按照Vue模板语法给dom元素绑定了事件。 在单文件组件里,scoped 的样式不会应用在 v-html 内部,因为那部分 HTML 没有被 Vue 的模板编译器处理。如果你希望针对 v-html 的内容设置带作用域的 CSS,你可以替换为 CSS Modules 或用一个额外的全局 style元素手动设置类似 BEM 的作用域策略。 后台返回的html片段,以及css样式和js,但是返回的js是不执行的,因为浏览器在渲染的时候并没有将js渲染,这时要在$nextTick中动 态创建script标签并插入 vue ---根据白名单过滤HTML(防止XSS攻击)_logytar的博客-CSDN博客_vue xss

52 Vue的路由实现:hash模式 和 history模式  ***#

hash模式:在浏览器中符号“#”,#以及#后面的字符称之为hash,用window.location.hash读取; 特点:hash虽然在URL中,但不被包括在HTTP请求中;用来指导浏览器动作,对服务端安全无用,hash不会重加载页面。 hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如 http://www.xxx.com,因此对于后端来说,即使没有做到对路由的全覆盖,也不会返回 404 错误。 history模式:history采用HTML5的新特性;且提供了两个新方法:pushState(),replaceState()可以对浏览器历史记录栈进行修改,以及popState事件的监听到状态变更。 history 模式下,前端的 URL 必须和实际向后端发起请求的 URL 一致,如 http://www.xxx.com/items/id。后端如果缺少对 /items/id 的路由处理,将返回 404 错误。Vue-Router 官网里如此描述:“不过这种模式要玩好,还需要后台配置支持……所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。”

53 vue解决跨域问题的方法:  ***#

vue项目解决跨域: proxy ,但是打包后不能用 ;打包后需要在后台设置 nginx vue中解决跨域问题 - 火星黑洞 - 博客园

54 vue项目的兼容性问题处理   **#

pc: 1、ES6语法不支持 解决方法: 引入babel-polyfill npm install --save bable-polyfill webpack.base.conf.js中修改为 app: ['event-source-polyfill', 'babel-polyfill', './src/main.js'] main.js 中引入 import 'babel-polyfill'; 2、GET非首次请求时,IE默认使用缓存而不是去后台请求 解决方法: 在request拦截时,加时间戳 service.interceptors.request.use(config => { // Do something before request is sent // // 时间戳 if (config.method === 'get') { config.params = { t: Date.parse(new Date()) / 1000, ...config.params } } return config; }, error => { // Do something with request error console.log(error); // for debug Promise.reject(error); }) 3、上传文件时,文件类型检查。如果为.apk文件,则file.type为" ".而jpg/png等文件正常 导致上传apk文件时,会报类型检查错误 解决方法: export function validateApk(file) { if (file.type === 'application/vnd.android.package-archive') { return true; } else { if (file.name.substring(file.name.lastIndexOf('.') + 1) === 'apk') { return true; } } return false; } 4、上传文件时,后台读取file.getName或者file.getOriginalName为全路径名称 解决方法: 后台去处理,如果为全路径,则进行字符串截取 IE目前已经放弃了自己的独特化,正一步步迎入互联网的主流怀抱。但迫于有用户存在,还是要兼容到IE8,9, 以上。 下面聊一下如何在vue框架中兼容IE 1.首先在index.html 问题:Vue2.0的官方脚手架工具构建的项目,chrome中跑一直没有问题,但ie打开出现了bug: 原因:Babel 默认只转换新的 JavaScript 句法(syntax),而不转换新的 API ,比如 Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局对象,以及一些定义在全局对象上的方法(比如 Object.assign)都不会转码。为了解决这个问题,我们使用一种叫做 Polyfill (代码填充,也可译作兼容性补丁) 的技术。 简单地说,polyfill即是在当前运行环境中用来复制(意指模拟性的复制,而不是拷贝)尚不存在的原生 api 的代码。 方案:安装babel-polyfill

步骤
1.安装babel-polyfill
npm install --save-dev babel-polyfill
2.然后再main.js中引入
import 'babel-polyfill'
3.如果也是用了官方脚手架vue-cli,还需要在webpack.config.js配置文件中做各修改,用
module.exports = {
  entry: {
    app: ["babel-polyfill", "./src/main.js"]   // 替换 app: './src/main.js'
  } 
};

55 如何给vue自定义组件添加点击事件?#

需要在@click后面加上.native,官方对于native的解释为: .native -——监听组件根元素的原生事件

56 vue项目做seo优化  *#

关于vue的seo优化_养只猫的博客-CSDN博客_seo vuevue项目如何做seo优化?_红烧金鱼草的博客-CSDN博客_vue项目seo怎么做

57 初识vue3(了解)#

  1. 创建vue3项目, 还是可以使用vue-cli进行创建, 也可以使用vite进行创建
  2. vue create myapp
// HelloWorld.vue
<template>
  <div>
    <span>{{ msg }}</span> <button @click="changeMsg">修改msg</button>
  </div>

  <h3>分类列表</h3>
  <ul>
    <li v-for="(item,index) in list" :key="item.id" @click="select(index)" :class="{on:index===activeIndex}">
      {{ item.name }}
    </li>
  </ul>
</template>

<script>
import { defineComponent, ref, onMounted } from "vue";
import axios from "axios";
export default defineComponent({
  setup() {
    // msg相关的操作
    let msg = ref("hello");
    let changeMsg = () => {
      msg.value = "hello world";
    };

    let activeIndex = ref(0);
    let select = (index)=> {
      activeIndex.value = index;
    }

    // 列表相关操作
    let list = ref([]);
    let getList = () => {
      axios.get("http://huruqing.cn:3003/category/all").then(res=> {
        list.value = res.data.list;
      });
    }; 
    onMounted(getList);

    return {
      msg,
      changeMsg,
      list,
      activeIndex,
      select,
    };
  },
});
</script>

<style>
li {
  cursor: pointer;
  margin-top:20px;
}
.on {
  color: red;
}
</style>

58 初识typescript (了解)#

  1. 安装ts npm install -g typescript

  2. 初识化项目 tsc --init

  3. 开始自动编译ts文件 tsc -w

  4. demos

    // 变量
    let num: number = 100;
    num = 200;
    // num = 'aaa'; // error
    
    let str: string = "hello";
    let boo: boolean = true;
    // boo = 20; // error
    
    // 数组
    let list:Array<number> = [1,10,100] 
    
    // 函数参数限制
    function add(a: number, b: number) {
      let sum: number = a + b;
      console.log(sum);
    }
    
    // 返回值限制
    function add2(a: number, b: number): number {
      let sum: number = a + b;
      console.log(sum);
      return sum;
    }
    
    // 定义一个新数据的类型
    type film = {
        id:string,
        name:string,
        poster:string
    }
    
    let obj:film = {
        id: 'asdfasdfasdf',
        name: '速10',
        poster: 'http://sdfsdf.com/aa.png'
    }
    
    // 接口
    interface person{
        username:string,
        age:number,
        // ?可有可无
        addr?:string
    }
    
    let zhangsan:person = {
        username: '张三',
        age: 100,
        addr: '广东深圳'
    }
    
    

59 初识webpack#

  1. 入口和出口
  2. loader配置: css-loader和less-loader
  3. 插件配置
  4. dev-server配置
  5. 别名配置
const path = require("path");
var HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
  mode: "development",
  entry: "./main.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "main-webpack.js",
  },

  module: {
    rules: [
      {
        test: /\.css$/,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.less$/,
        use: [
          {
            loader: "style-loader", // creates style nodes from JS strings
          },
          {
            loader: "css-loader", // translates CSS into CommonJS
          },
          {
            loader: "less-loader", // compiles Less to CSS
          },
        ],
      },
    ],
  },

  resolve:{
    alias:{
      '@': path.resolve(__dirname,'src')
    }, 
  },

  plugins: [
    new HtmlWebpackPlugin({ filename: "index.html", template: "./index.html" }),
  ],
  devServer: {
    open: true, //是否自动打开默认浏览器
    port: 9000, // 端口号
  },
};

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

牛马小先锋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值