项目开发过程中遇到的一些问题

431 阅读3分钟

1. v-for中使用v-model

1.1 报错实例

<div v-for="(shopitem, index) in productsGroup" :key="index">
  <checkout-comment v-model="shopitem"></checkout-comment>
</div>

1.2 报错信息

You are binding v-model directly to a v-for iteration alias. This will not be able to modify the v-for source array because writing to the alias is like modifying a function local variable. Consider using an array of objects and use v-model on an object property instead.

翻译内容

您正在将v-model直接绑定到v-for迭代别名。这将无法修改v-for源数组,因为写入别名就像修改函数局部变量。考虑使用一个对象数组,对对象属性使用v-model。

1.3 解决方案

v-model不可以直接修改 v-for循环迭代时别名上的数据, 可以通过index下标来引用所需的数据, 达到目的

<div v-for="(shopitem, index) in productsGroup" :key="index">
  <checkout-comment v-model="productsGroup[index]"></checkout-comment>
</div>

2. 网页双击不选中html文字

在DOM元素上添加onselectstart="return false"即可,该DOM元素及其子元素均不可双击选中

3. 单选框取消选中

3.1 方法1:使用复选框模拟(手动更改样式,以elementui为例)

// 设置max属性,缺点:需要将选中的先取消选中,才可以选别的
<el-checkbox-group v-model="check" :max="1">
  <el-checkbox label="1"></el-checkbox>
  <el-checkbox label="2"></el-checkbox>
</el-checkbox-group>

// 绑定change方法,缺点:需要手动去设置
<el-checkbox-group v-model="check" @change="change">
  <el-checkbox label="1"></el-checkbox>
  <el-checkbox label="2"></el-checkbox>
</el-checkbox-group>

change(val) {
  this.check = this.check.length > 1 ? [this.check[1]] : val;
}

3.2 方法2:手动设置单选框状态

<el-radio-group v-model="radio">
  <el-radio label="1" @click.native.prevent="change('1')"></el-radio>
  <el-radio label="2" @click.native.prevent="change('2')"></el-radio>
</el-radio-group>

change(val) {
  this.radio = this.radio == val ? "" : val;
},

4. token过期一次提示

4.1 起因

token过期后,同时向后端发起n个请求,根据后端返回的过期提示,提示用户重新登录

4.2 解决方案

思路:定义一个变量,来标识是否弹窗,当第一次接受到token过期code码,进行弹窗,并将标识置为其他值

// 全局变量 -> tokenInvaildFlag
if (error.response.data.code === 403 && globalVariable.tokenInvaildFlag == 0) {
  globalVariable.tokenInvaildFlag = 1;
  ELEMENT.MessageBox.alert("登录已过期,请重新登录", "提示", {
    confirmButtonText: "确定",
    callback: (action) => {
      // do sth
    },
  });
}

5. Vue项目配置问题

5.1 全局scss变量

  1. 安装插件

npm i sass-resources-loader --save-dev

  1. 修改配置文件
  • 老版本 build/utils.js
// scss: generateLoaders('sass')
->
scss: generateLoaders("sass").concat({
  loader: "sass-resources-loader",
  options: {
    resources: path.resolve(__dirname, "../src/styles/variables.scss"),
  },
}),
  • 新版本 vue.config.js
css: {
  loaderOptions: {
    // 全局配置scss
    scss: {
      prependData: `@import "~@/assets/css/mixin.scss";@import "~@/assets/css/variables.scss";`,
    },
  },
},
  1. 定义变量 variables.scss
$themeColor: #123456
  1. 页面中引用
<style lang="scss" scoped>
div {
  color: $themeColor;
}
</style>

5.2 cdn配置

  1. 修改配置文件
  • 老版本 build/webpack.base.conf.js
module.exports = {
  externals: {
    vue: "Vue",
    vueRouter: "vue-router",
    vuex: "Vuex",
    axios: "axios",
    element: "element-ui",
    echarts: "echarts", //默认是配置引用的库(这里是echarts)暴露出的全局变量
  },
}
  • 新版本 vue.config.js
module.exports = {
  chainWebpack: (config) => {
    config.externals({
      vue: "Vue",
      vueRouter: "vue-router",
      vuex: "Vuex",
      axios: "axios",
      element: "element-ui",
      echarts: "echarts", //默认是配置引用的库(这里是echarts)暴露出的全局变量
    });
  }
}

5.3 别名配置

  • 老版本 build/webpack.base.conf.js
module.exports = [
  resolve: {
    alias: {
      vue$: 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    }
  },
}
  • 新版本 vue.config.js
module.exports = {
  chainWebpack: (config) => {
    config.resolve.alias
      .set("img", resolve("src/assets/images")) // html中引用需要加~
      .set("api", resolve("src/api"));
  },
}

6. Vue实例创建时初始化顺序(源码)

initLifecycle(vm);
initEvents(vm);
initRender(vm);
callHook(vm, 'beforeCreate');
initInjections(vm); // resolve injections before data/props
initState(vm);
initProvide(vm); // resolve provide after data/props
callHook(vm, 'created');

其中initState方法如下

function initState (vm) {
  vm._watchers = [];
  var opts = vm.$options;
  if (opts.props) { initProps(vm, opts.props); }
  if (opts.methods) { initMethods(vm, opts.methods); }
  if (opts.data) {
    initData(vm);
  } else {
    observe(vm._data = {}, true /* asRootData */);
  }
  if (opts.computed) { initComputed(vm, opts.computed); }
  if (opts.watch && opts.watch !== nativeWatch) {
    initWatch(vm, opts.watch);
  }
}

可以看出,初始化顺序为:props, methods, data, computed, watch

7. Vue多路由引用同一组件,切换时组件更新问题

示例代码:

{
  path: '/user',
  component: A
},
{
  path: '/role',
  component: A
}

当从/user切换到/role时,组件A并不会重新加载

解决方法:

  • 在组件A中监听路由,变化时重新调用接口
  • <router-view :key="$route.fullPath">,该方法在做<keep-alive>缓存时,会使缓存失效,慎用

8. vue-router组件导航守卫不生效问题

示例代码:

// 路由
{
  path: '/user',
  component: User
}

// 父组件 User.vue
<div>
  <Child />
</div>

beforeRouteEnter(to, from, next) {
  console.log('parent')
}

// 子组件 Child.vue
...DOM

beforeRouteEnter(to, from, next) {
  console.log('child')
}

当路由跳转到/user时,控制台只会输出parent,这是因为组件导航守卫只会作用到以<router-view>作为出口的组件身上,即例子中的User.vue

9. vue create创建vue项目,报spawn yarn enoent

9.1 原因

设置yarn为默认包管理工具,但是没有找到yarn

9.2 解决方案

  1. 安装yarn

  2. 修改默认包管理工具

// C:/user/.vuerc
{
  "useTaobaoRegistry": false,
  "latestVersion": "4.5.15",
  "lastChecked": 1636436558444,
  "packageManager": "yarn" // 将这里修改为npm
}
  1. 创建项目时指定包管理工具

vue create <projectname> -m, --packageManager npm