实际项目中的编码技巧总结(Vue篇)

本文目录

  • 1.node-sass安装失败
  • 2.动态引入和绑定背景图片
  • 3.写在data中的数据无法将改变动态渲染到页面上
    -4.vue中定义全局变量的方法
  • 5.beforeRouteEnter的书写位置
  • 6.解决vue路由警告问题
  • 7.让VScode保存时自动匹配ESlint规则
  • 8.封装公用方法(以格式化数据为例)
  • 9.修改第三方组件样式
  • 10.监听组件生命周期
  • 11.路由分区以及动态添加路由
  • 12.v-for循环拿到的item值动态渲染文字内容
  • 13.路由跳转,页面不刷新
  • 14.Vue部署与部署后刷新页面404
  • 15.列表进入详情页的传参问题
  • 16.组件的事件拿到额外的参数
  • 17.子组件改变父组件传递过来的数据
  • 18.父组件调用子组件的方法
  • 19.改变数组

1.node-sass安装失败

使用别人的一个模板项目的时候,在npm install的时候报错提示node-sass啊没装失败,出现原因是npm 安装 node-sass 依赖时,会从 github.com 上下载 .node 文件。由于国内网络环境的问题,这个下载时间可能会很长,甚至导致超时失败。
解决方法是首先把node_modules文件夹删除,然后运行指令npm i node-sass --sass_binary_site=https://npm.taobao.org/mirrors/node-sass/先单独安装node-sass,再启用npm install安装其他依赖。

2.动态引入和绑定背景图片

vue中动态改变backgroundimage的写法
:style="{backgroundImage:'url(\''+themeBg+'\')'}"
动态的在data中引入路径的写法
themeBg: require("../../assets/images/e_center.png"),
这个themeBg也可以是在缓存中获取的
themeBg: sessionStorage.getItem("themeBg")

3.写在data中的数据无法将改变动态渲染到页面上

场景:数据确定会正常改变,但是变化不会自动触发页面上的显示,但是功能是正常的。
可能原因1:就算数据是在data存在了,但是赋值的时候把某个属性给丢失了,vue也就失去了对其的检测能力。也就是说,在data中存在的数据以及对象属性需要一直存在,否则vue就会失去对其变化的监控。
可能原因2:vue中在data里定义的变量,在ajax获取数据后进行改变,但是变量的改变无法动态渲染到视图中,折腾了很长时间发现是回调函数中的this的指向发生了改变,回调函数应该使用箭头函数来保持this指向的不变。
可能原因3:computed里面数据的改变不会自动触发视图的更新,写在data里的对象,需要新增加flag用来控制视图元素的显示和隐藏,需要进行动态的添加,如果flag本来就定义在data中,则可以直接赋值。

this.$set(this.regionOptions[i].options[si], 'flag', false);

如果像下面这样添加,则无法和视图进行实时动态渲染的绑定

this.regionOptions[i].options[si].flag = false;

4.vue中定义全局变量的方法

在mainjs中进行定义并将其挂载到vue实例中
var baseUrl = "http://110.50.111:8090";
Vue.prototype.$baseUrl = baseUrl
组件内进行使用

methods: {
  asd() {
    console.log(this.$baseUrl);
  }
},
mounted() {
  this.asd()
}

全局引用js直接在main.js中引用就可以,import remtools from './assets/js/setrem'
但是这个js只有在项目第一次加载的时候执行一次,切换路由的时候并不触发这个js

5.beforeRouteEnter的书写位置

beforeRouteEnter必须放在页面文件中,组件是监听不到路由的

beforeRouteEnter (to, from, next) {
  if (from.path === '/detail') {
    next((vm) => {
      // 更新列表数据方法
      vm.updateData()
    })
  }
  next()
},

6.解决vue路由警告问题

下面这三行是解决vue项目路由出现message: "Navigating to current location (XXX) is not allowed"的方法,把代码放置到router文件夹的index.js文件中即可

const routerPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
  return routerPush.call(this, location).catch(error=> error)
}

7.让VScode保存时自动匹配ESlint规则

首先需要找到VScode配置文件setting.json

  1. ctrl+shift+p
    2.输入setting
    3.选择 首选项:打开设置(json)即可.
    这个文件存放的是一个JSON格式的数据,在{}中的最后增加如下代码
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }

这样的话,在修改代码只需要ctrl+s保存代码,代码规则就会自动按照ESlint的配置规则进行调整。

8.封装公用方法(以格式化数据为例)

我们封装组件在多个地方用到的不同的接口数据,这些请求来的数据有可能会名称不同,所以我们需要封装一个方法,专门用来格式化我们请求来的数据,从而能够在组件中得到统一的调用。
在src文件夹中新建一个common文件夹,然后再新建一个js文件夹,然后再新建一个util.js文件,这个文件是用来存放我们自己写的一些工具方法的。

export function formatSongDetail(val){
    const newVal = []
    val.forEach((item) =>{
        const detail = {}
        detail.id = item.id
        detail.al = Object.assign({}, item.al || item.album || item.song.album)
//Object.assign方法的第一个参数是目标对象,后面的参数都是源对象。
//注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。
        detail.ar = [].concat(item.ar || item.artists || item.song.artists)
        detail.name = item.name
        newVal.push(detail)
    })
    return newVal
}

接下来,在要格式化数据的组件中先引入这个方法
``import { formatSongDetail } from "../../common/js/util";`
然后可以在data中新建一个formatData,用来存放我们格式化之后的数据

data() {
    return {
       formatData: []
    };
}

在ajax获取到数据的时候,调用formatSongDetail方法,然后将数据格式化之后的数据存储到formatData中
this.formatData = formatSongDetail(data.result);

9.修改第三方组件样式

在使用vue构建项目的时候,引用了第三方组件库,只需要在当前页面修改第三方组件库的样式以做到不污染全局样式。通过在样式标签上使用scoped达到样式只制作用到本页面,但是此时再修改组件样式不起作用。
解决方法:通过 >>> 穿透scoped
父组件中修改子组件的样式使用样式穿透
.parent >>> .child
父组件的 class或ID >>>(三个箭头表示样式穿透) 子组件的class或ID


有些Sass 、Less之类的预处理器无法正确解析 >>>。可以使用 /deep/操作符( >>> 的别名)


10.监听组件生命周期

通常我们监听组件生命周期会使用 $emit ,父组件接收事件来进行通知
子组件代码:

export default {
    mounted() {
        this.$emit('listenMounted')
    }
}

父组件代码:


其实还有一种简洁的方法,使用 @hook 即可监听组件生命周期,组件内无需做任何改变。同样的, created 、 updated 等也可以使用此方法。


12.v-for循环拿到的item值动态渲染文字内容

{{item.status === 1 ? '待确认' : item.status === 2 ? '已拒绝' :item.status === 3 ? '已绑定' :item.status === 100 ? '已过期' : '' }}

总结:{{}}中是可以写三元表达式的。

13.路由跳转,页面不刷新

假设我们在写一个博客网站,需求是从/post-page/a,跳转到/post-page/b。然后我们惊人的发现,页面跳转后数据竟然没更新?!原因是vue-router"智能地"发现这是同一个组件,然后它就决定要复用这个组件,所以你在created函数里写的方法压根就没执行。通常的解决方案是监听$route的变化来初始化数据,如下:

data() {
  return {
    loading: false,
    error: null,
    post: null
  }
}, 
watch: {
  '$route': {
    handler: 'resetData',
    immediate: true
  }
},
methods: {
  resetData() {
    this.loading = false
    this.error = null
    this.post = null
    this.getPost(this.$route.params.id)
  },
  getPost(id){

  }
}

bug是解决了,可每次这么写也太不优雅了吧。
其实可以借助router-view添加一个unique的key,这样即使是公用组件,只要url变化了,就一定会重新创建这个组件。(虽然损失了一丢丢性能,但避免了无限的bug)。
同时,注意我将key直接设置为路由的完整路径,一举两得。


14.Vue部署与部署后刷新页面404

我们先来看一下打包出来的的dist文件


dist文件夹.png

可以看到dist下只有一个 index.html 文件及一些静态资源,这个是因为Vue是单页应用(SPA),只有一个index.html作为入口文件,其它的路由都是通过JS来进行跳转
我们只需要将这个目录上传至目标服务器即可
让web容器跑起来,以nginx为例

server {
  listen  80;
  server_name website.com;
  location / {
    index  /data/dist/index.html;
  }
}

配置完成记得重启nginx

// 检查配置是否正确
nginx -t 
// 平滑重启
nginx -s reload

操作完后就可以在浏览器输入域名进行访问了
当然上面只是提到最简单也是最直接的一种布署方式
什么自动化,镜像,容器,流水线布署,本质也是将这套逻辑抽象,隔离,用程序来代替重复性的劳动。

接着我们再回头来看下web容器的 nginx 配置

server {
  // 监听80端口
  listen 80;
  // 定义你的站点名称
  server_name website.com;
  // 根据请求 URI 设置配置
  location / {
      // 站点根目录,这里为 vue 构建出来的 dist 目录
      root   /www/dist;
      // 站点初始页为index.html 或 index.htm
      index  index.html;
  }
}

我们现在可以根据 nginx 配置得出,当我们在地址栏输入 website.com 时,这时会打开我们 dist 目录下的 index.html 文件,然后我们在跳转路由进入到 website.com/login
关键在这里,当我们在 website.com/login 页执行刷新操作,nginx location 是没有相关配置的,所以就会出现 404 的情况

为什么hash模式下没有问题
router hash 模式我们都知道是用符号#表示的,如 website.com/#/login, hash 的值为 #/login
它的特点在于:hash 虽然出现在 URL 中,但不会被包括在 HTTP 请求中,对服务端完全没有影响,因此改变 hash 不会重新加载页面
hash 模式下,仅 hash 符号之前的内容会被包含在请求中,如 website.com/#/login 只有 website.com 会被包含在请求中 ,因此对于服务端来说,即使没有配置location,也不会返回404错误

产生问题的本质是因为我们的路由是通过JS来执行视图切换的,
当我们进入到子路由时刷新页面,web容器没有相对应的页面此时会出现404
所以我们只需要配置将任意页面都重定向到 index.html,把路由交由前端处理

location / {
  index  /data/dist/index.html;
  try_files $uri $uri/ /index.html;
}

这里有一个小细节,如果出现真的 404 页面了呢?比如 website.com/notfound
因为这么做以后,你的服务器就不再返回 404 错误页面,因为对于所有路径都会返回 index.html 文件。为了避免这种情况,应该在 Vue 应用里面覆盖所有的路由情况,然后在给出一个 404 页面

const router = new VueRouter({
  mode: 'history',
  routes: [
    { path: '*', component: NotFoundComponent }
  ]
})

15.列表进入详情页的传参问题

例如商品列表页面前往商品详情页面,需要传一个商品id;

前往detail页面

c页面的路径为http://localhost:8080/#/detail?id=1,可以看到传了一个参数id=1,并且就算刷新页面id也还会存在。此时在c页面可以通过id来获取对应的详情数据,获取id的方式是this.$route.query.id
vue传参方式有:query、params+动态路由传参。
说下两者的区别:
1.query通过path切换路由,params通过name切换路由

// query通过path切换路由
前往Detail页面
// params通过name切换路由
前往Detail页面

2.query通过this.route.params来接收参数。

// query通过this.$route.query接收参数
created () {
    const id = this.$route.query.id;
}

// params通过this.$route.params来接收参数
created () {
    const id = this.$route.params.id;
}

3.query传参的url展现方式:/detail?id=1&user=123&identity=1&更多参数
params+动态路由的url方式:/detail/123
4.params动态路由传参,一定要在路由中定义参数,然后在路由跳转的时候必须要加上参数,否则就是空白页面:

{      
    path: '/detail/:id',      
    name: 'Detail',      
    component: Detail    
}

注意,params传参时,如果没有在路由中定义参数,也是可以传过去的,同时也能接收到,但是一旦刷新页面,这个参数就不存在了。这对于需要依赖参数进行某些操作的行为是行不通的,因为你总不可能要求用户不能刷新页面吧。例如

{
    path: 'detail/:id',
    name: 'Detail',
    components: Detail
}

// template中的路由传参,
// 传了一个id参数和一个token参数
// id是在路由中已经定义的参数,而token没有定义
前往Detail页面

// 在详情页接收
created () {
    // 以下都可以正常获取到
    // 但是页面刷新后,id依然可以获取,而token此时就不存在了
    const id = this.$route.params.id;
    const token = this.$route.params.token;
}

16.组件的事件拿到额外的参数

本来的写法@search-keyup=keyupSearchItem"
自定义事件keyupSearchItem拿到默认的参数

keyupSearchItem (e){}

优化后的写法@search-keyup="argument => keyupSearchItem(index,argument)",自定义事件拿到额外的自定义参数

keyupSearchItem (index,e){}

index和argument的顺序更换也没问题

17.子组件改变父组件传递过来的数据

引用的组件


会触发一些页面传入的数据

props: {
  show:{
      type:Boolean,
      default:false
  }
},

设置computed的set和get完美解决

computed: {
    showFlag:{
        get() {
            return this.show
        },
        set(v) {
            this.$emit('closeHelpContainer')
        }
    }
},

如果只是下面这样

computed: {
    showFlag (){
        return this.show
    }
},

则当关闭组件的时候,页面会报错

Computed property "showFlag" was assigned to but it has no setter.

18.父组件调用子组件的方法

this.$refs.Category.getFormData();
给子组件添加上ref="Category",上面的代码就直接可以调用到子组件的getFormData方法,并获取到其中的返回值。

19.改变数组

vue2中定义一个数组demoArr: [1,2,3,4,5],然后渲染到页面上,在methods中通过this.demoArr = [10,20,30,40,50]改变demoArr可以动态改变到页面上吗?
可以
this.set(this.demoArr,[10,20,30,40,50])这样会报错吗 不会报错,但也不起作用 vue2中改变数组项和对象属性的正确方法:this.set(object, key, value)

你可能感兴趣的:(实际项目中的编码技巧总结(Vue篇))