国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

vue2.0 項(xiàng)目開發(fā)小結(jié)

wuyangnju / 2134人閱讀

摘要:項(xiàng)目架構(gòu)項(xiàng)目目錄項(xiàng)目目錄是采用自動(dòng)生成,其它按需自己新建就好了。

項(xiàng)目架構(gòu) 項(xiàng)目目錄
├── build
├── config
├── dist
│?? └── static
│??     ├── css
│??     ├── fonts
│??     ├── images
│??     ├── js
│??     └── lib
├── src
│?? ├── api
│?? ├── assets
│?? │?? ├── global
│?? │?? └── images
│?? │??     └── footer
│?? ├── components
│?? │?? ├── common
│?? │?? ├── news
│?? │?? └── profile
│?? │??     └── charge
│?? ├── config
│?? ├── mixin
│?? ├── router
│?? ├── service
│?? ├── store
│?? └── util
└── static
    ├── images
    └── lib 

項(xiàng)目目錄是采用 vue-cli 自動(dòng)生成,其它按需自己新建就好了。

開發(fā)實(shí)踐 動(dòng)態(tài)修改 document title

在不同的路由頁(yè)面,我們需要?jiǎng)討B(tài)的修改文檔標(biāo)題,可以將每個(gè)頁(yè)面的標(biāo)題配置在路由元信息 meta 里面帶上,然后在 router.afterEach 鉤子函數(shù)中修改:

import Vue from "vue";
import Router from "vue-router";

Vue.use(Router);
const router = new Router({
  mode: "history",
  routes: [
    { path: "/", component: Index, meta: { title: "推薦產(chǎn)品得豐厚獎(jiǎng)金" } },
    {
      path: "/news",
      component: News,
      meta: { title: "公告列表" },
      children: [
        { path: "", redirect: "list" },
        { path: "list", component: NewsList },
        { path: "detail/:newsId", component: NewsDetail, meta: { title: "公告詳情" } }
      ]
    },
    {
      path: "/guide",
      component: GuideProtocol,
      meta: {
        title: "新手指南"
      }
    }
  ]
});

// 使用 afterEach 鉤子函數(shù),保證路由已經(jīng)跳轉(zhuǎn)成功之后修改 title
router.afterEach((route) => {
  let documentTitle = "xxx商城會(huì)員平臺(tái)";
  route.matched.forEach((path) => {
    if (path.meta.title) {
      documentTitle += ` - ${path.meta.title}`;
    }
  });

  document.title = documentTitle;
});
根據(jù) URL 的變化,動(dòng)態(tài)更新數(shù)據(jù)

通常在一個(gè)列表集合頁(yè),我們需要做分頁(yè)操作,同時(shí)分頁(yè)數(shù)據(jù)需要體現(xiàn)在 URL 中,那么如何動(dòng)態(tài)的根據(jù) URL 的變動(dòng)來(lái)動(dòng)態(tài)的獲取數(shù)據(jù)呢,我們可以使用 watch API,在 watch 里面監(jiān)聽 $route,同時(shí)使用 this.$router.replace API 來(lái)改變 URL 的值。下面是示例代碼 common.js

import qs from "qs";

export default {
  data() {
    return {
      queryParams: {
        currentPage: 1,
        pageSize: 10
      }
    };
  },
  methods: {
    handlePageNoChange(e) {
      this.queryParams.currentPage = e;
      this.replaceRouter();
    },

    replaceRouter() {
      const query = qs.stringify(this.queryParams);
      this.$router.replace(`${location.pathname}?${query}`);
    },

    routeChange() {
      this.assignParams();
      this.fetchData();
    },

    assignParams() {
      this.queryParams = Object.assign({}, this.queryParams, this.$route.query);
    }
  },
  mounted() {
    this.assignParams();
    this.fetchData();
  },
  watch: {
    $route: "routeChange"
  }
};

我們將這部分代碼抽取到一個(gè)公共的 mixin 中,在需要的組件那里引入它,同時(shí)實(shí)現(xiàn)自定義的同名 fetchData() 方法
mixin API 文檔:https://cn.vuejs.org/v2/guide...

export default DemoComponent {
  mixins: [common],
  data() {
    return {
      // 組件內(nèi)部自定義同名查詢參數(shù),將會(huì)和 mixin 中的默認(rèn)參數(shù)合并
      queryParams: {
        categoryId: "",
        pageSize: 12
      },
    }
  },
  methods: {
    fetchData() {
       // 發(fā)送請(qǐng)求
    }
  }
}
Event Bus 使用場(chǎng)景

我們?cè)陧?xiàng)目中引入了 vuex ,通常情況下是不需要使用 event bus 的,但是有一種情況下我們需要使用它,那就是在路由鉤子函數(shù)內(nèi)部的時(shí),在項(xiàng)目中,我們需要在 beforeEnter 路由鉤子里面對(duì)外拋出事件,在這個(gè)鉤子函數(shù)中我們無(wú)法去到 this 對(duì)象。

beforeEnter: (to, from, next) => {
    const userInfo = localStorage.getItem(userFlag);
    if (isPrivateMode()) {
        EventBus.$emit("get-localdata-error");
        next(false);
        return;
    }
})

App.vuemouted 方法中監(jiān)聽這個(gè)事件

EventBus.$on("get-localdata-error", () => {
    this.$alert("請(qǐng)勿使用無(wú)痕模式瀏覽");
});
自定義指令實(shí)現(xiàn)埋點(diǎn)數(shù)據(jù)統(tǒng)計(jì)

在項(xiàng)目中通常需要做數(shù)據(jù)埋點(diǎn),這個(gè)時(shí)候,使用自定義指令將會(huì)變非常簡(jiǎn)單

在項(xiàng)目入口文件 main.js 中配置我們的自定義指令

// 坑位埋點(diǎn)指令
Vue.directive("stat", {
  bind(el, binding) {
    el.addEventListener("click", () => {
      const data = binding.value;
      let prefix = "store";
      if (OS.isAndroid || OS.isPhone) {
        prefix = "mall";
      }
      analytics.request({
        ty: `${prefix}_${data.type}`,
        dc: data.desc || ""
      }, "n");
    }, false);
  }
});
使用路由攔截統(tǒng)計(jì)頁(yè)面級(jí)別的 PV

由于第一次在單頁(yè)應(yīng)用中嘗試數(shù)據(jù)埋點(diǎn),在項(xiàng)目上線一個(gè)星期之后,數(shù)據(jù)統(tǒng)計(jì)后臺(tái)發(fā)現(xiàn),首頁(yè)的 PV 遠(yuǎn)遠(yuǎn)高于其它頁(yè)面,數(shù)據(jù)很不正常。后來(lái)跟數(shù)據(jù)后臺(tái)的人溝通詢問(wèn)他們的埋點(diǎn)統(tǒng)計(jì)原理之后,才發(fā)現(xiàn)其中的問(wèn)題所在。

傳統(tǒng)應(yīng)用,一般都在頁(yè)面加載的時(shí)候,會(huì)有一個(gè)異步的 js 加載,就像百度的統(tǒng)計(jì)代碼類似,所以我們每個(gè)頁(yè)面的加載的時(shí)候,都會(huì)統(tǒng)計(jì)到數(shù)據(jù);然而在單頁(yè)應(yīng)用,頁(yè)面加載初始化只有一次,所以其它頁(yè)面的統(tǒng)計(jì)數(shù)據(jù)需要我們自己手動(dòng)上報(bào)

解決方案

使用 vue-routerbeforeEach 或者 afterEach 鉤子上報(bào)數(shù)據(jù),具體使用哪個(gè)最好是根據(jù)業(yè)務(wù)邏輯來(lái)選擇。

const analyticsRequest = (to, from) => {
  // 只統(tǒng)計(jì)頁(yè)面跳轉(zhuǎn)數(shù)據(jù),不統(tǒng)計(jì)當(dāng)前頁(yè) query 不同的數(shù)據(jù)
  // 所以這里只使用了 path, 如果需要統(tǒng)計(jì) query 的,可以使用 to.fullPath
  if (to.path !== from.path) {
    analytics.request({
      url: `${location.protocol}//${location.host}${to.path}`
    });
  }
};

router.beforeEach((to, from, next) => {
  if (to.matched.some(record => record.meta.requiresAuth)) {
    // 這里做登錄等前置邏輯判斷
    // 判斷通過(guò)之后,再上報(bào)數(shù)據(jù)
    ...
    analyticsRequest(to, from);
  } else {
    // 不需要判斷的,直接上報(bào)數(shù)據(jù)
    analyticsRequest(to, from);
    next();
  }
});

在組件中使用我們的自定義指令

使用過(guò)濾器實(shí)現(xiàn)展示信息格式化

如下圖中獎(jiǎng)金數(shù)據(jù)信息,我們需要將后臺(tái)返回的獎(jiǎng)金格式化為帶兩位小數(shù)點(diǎn)的格式,同時(shí),如果返回的金額是區(qū)間類型,需要額外加上 字和 金額符號(hào)

在入口文件 main.js 中配置我們自定義的過(guò)濾器

Vue.filter("money", (value, config = { unit: "¥", fixed: 2 }) => {
  const moneyStr = `${value}`;
  if (moneyStr.indexOf("-") > -1) {
    const scope = moneyStr.split("-");
    return `${config.unit}${parseFloat(scope[0]).toFixed(config.fixed).toString()} 起`;
  } else if (value === 0) {
    return value;
  }

  return `${config.unit}${parseFloat(moneyStr).toFixed(config.fixed).toString()}`;
});

在組件中使用:

{{detail.priceScope | money}}

比率:{{detail.commissionRateScope}}%

獎(jiǎng)金:{{detail.expectedIncome | money}}

axios 使用配置

在項(xiàng)目中,我們使用了 axios 做接口請(qǐng)求

在項(xiàng)目中全局配置 /api/common.js

import axios from "axios";
import qs from "qs";
import store from "../store";

// 全局默認(rèn)配置
// 設(shè)置 POST 請(qǐng)求頭
axios.defaults.headers.post["Content-Type"] = "application/x-www-form-urlencoded";
// 配置 CORS 跨域
axios.defaults.withCredentials = true;
axios.defaults.crossDomain = true;

// 請(qǐng)求發(fā)起前攔截器
axios.interceptors.request.use((config) => {
  // 全局 loading 狀態(tài),觸發(fā) loading 效果
  store.dispatch("updateLoadingStatus", {
    isLoading: true
  });
  
  // POST 請(qǐng)求參數(shù)處理成 axios post 方法所需的格式
  if (config.method === "post") {
    config.data = qs.stringify(config.data);
  }
  
  // 這句不能省,不然后面的請(qǐng)求就無(wú)法成功發(fā)起,因?yàn)樽x不到配置參數(shù)
  return config;
}, () => {
  // 異常處理
  store.dispatch("updateLoadingStatus", {
    isLoading: false
  });
});

// 響應(yīng)攔截
axios.interceptors.response.use((response) => {
  // 關(guān)閉 loading 效果
  store.dispatch("updateLoadingStatus", {
    isLoading: false
  });

  // 全局登錄過(guò)濾,如果沒有登錄,直接跳轉(zhuǎn)到登錄 URL
  if (response.data.code === 300) {
    // 未登錄
    window.location.href = getLoginUrl();
    return false;
  }

  // 這里返回的 response.data 是被 axios 包裝過(guò)的一成,所以在這里抽取出來(lái)
  return response.data;
}, (error) => {
  store.dispatch("updateLoadingStatus", {
    isLoading: false
  });
  return Promise.reject(error);
});

// 導(dǎo)出
export default axios;

然后我們?cè)诮涌谥惺褂镁头奖愫芏嗔?/api/xxx.js

import axios from "./common";

const baseURL = "/api/profile";
const USER_BASE_INFO = `${baseURL}/getUserBaseInfo.json`;
const UPDATE_USER_INFO = `${baseURL}/saveUserInfo.json`;

// 更新用戶實(shí)名認(rèn)證信息
const updateUserInfo = userinfo => axios.post(UPDATE_USER_INFO, userinfo);

// 獲取用戶基礎(chǔ)信息
const getUserBaseInfo = () => axios.get(USER_BASE_INFO);
vuex 狀態(tài)在響應(yīng)式頁(yè)面中的妙用

由于項(xiàng)目是響應(yīng)式頁(yè)面,PC 端和移動(dòng)端在表現(xiàn)成有很多不一致的地方,有時(shí)候單單通過(guò) CSS 無(wú)法實(shí)現(xiàn)交互,這個(gè)時(shí)候,我們的 vuex 狀態(tài)就派上用場(chǎng)了,

我們一開始在 App.vue 里面監(jiān)聽了頁(yè)面的 resize 事件,動(dòng)態(tài)的更新 vuex 里面 isMobile 的狀態(tài)值

window.onresize = throttle(() => {
 this.updatePlatformStatus({
   isMobile: isMobile()
 });
}, 500);

然后,我們?cè)诮M件層,就能響應(yīng)式的渲染不同的 dom 結(jié)構(gòu)了。其中最常見的是 PC 端和移動(dòng)端加載的圖片需要不同的規(guī)格的,這個(gè)時(shí)候我們可以這個(gè)做

methods: {
  loadImgAssets(name, suffix = ".jpg") {
    return require(`../assets/images/${name}${this.isMobile ? "-mobile" : ""}${suffix}`);
  },
}



// 動(dòng)態(tài)渲染不同規(guī)格的 dislog

下圖分別是 PC 端和移動(dòng)短的表現(xiàn)形式,然后配合 CSS 媒體查詢實(shí)現(xiàn)各種布局

開發(fā)相關(guān)配置 反向代理

在項(xiàng)目目錄的 config 文件下面的 index.js 配置我們的本地反向代理和端口信息

dev: {
  env: require("./dev.env"),
  port: 80,
  autoOpenBrowser: true,
  assetsSubDirectory: "static",
  assetsPublicPath: "/",
  proxyTable: {
    "/api/profile": {
      target: "[真實(shí)接口地址]:[端口號(hào)]", // 例如: http://api.xxx.com
      changeOrigin: true,
      pathRewrite: {
        "^/api/profile": "/profile"
      }
    }
    ...
  },

然后我們調(diào)用接口的形式就會(huì)變成如下映射,當(dāng)我們調(diào)用 /api/profile/xxxx 的時(shí)候,其實(shí)是調(diào)用了 [真實(shí)接口地址]/profile/xxxx

/api/profile/xxxx => [真實(shí)接口地址]/profile/xxxx

nginx 配置

upstream api.xxx.com
{
 #ip_hash;
  server [接口服務(wù)器 ip 地址]:[端口];
}

server {
  ...
  location ^~ /api/profile {
    index index.php index.html index.html;
    proxy_redirect off;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass http://api.xxx.com;
    
    rewrite ^/api/profile/(.*)$ /profile/$1 break;
  }
  ...
}
線上部署

如果路由使用的是 history 模式的話,需要在 nginx 里面配置將所有的請(qǐng)求到轉(zhuǎn)發(fā)到 index.html

nginx.conf 或者對(duì)應(yīng)的站點(diǎn) vhost 文件下面配置

location / {
    try_files $uri $uri/ /index.html;
}
優(yōu)化

開啟靜態(tài)資源長(zhǎng)緩存

location ~ .*.(gif|jpg|jpeg|png|bmp|swf|woff|ttf|eot|svg)$ {
    expires 1y;
}

location ~ .*.(js|css)$ {
    expires 1y;
}

開啟靜態(tài)資源 gzip 壓縮

// 找到 nginx.conf 配置文件
vim /data/nginx/conf/nginx.conf

gzip on;
gzip_min_length  1k;
gzip_buffers     4 8k;
gzip_http_version 1.1;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/xml text/css;

開啟了 gzip 壓縮之后,頁(yè)面資源請(qǐng)求大小將大大減小,如下圖所示,表示已經(jīng)開啟了 gzip 壓縮

Q&A

文章到這就結(jié)束了,如果有遺漏或者錯(cuò)誤的地方,歡迎私信指出。
希望這篇文章能帶給大家一絲絲收獲。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/88422.html

相關(guān)文章

  • vue2.0 項(xiàng)目開發(fā)小結(jié)

    摘要:項(xiàng)目架構(gòu)項(xiàng)目目錄項(xiàng)目目錄是采用自動(dòng)生成,其它按需自己新建就好了。 項(xiàng)目架構(gòu) 項(xiàng)目目錄 ├── build ├── config ├── dist │?? └── static │?? ├── css │?? ├── fonts │?? ├── images │?? ├── js │?? └── lib ├── src │?? ├── api │?...

    yagami 評(píng)論0 收藏0
  • vue2.0 項(xiàng)目開發(fā)小結(jié)

    摘要:項(xiàng)目架構(gòu)項(xiàng)目目錄項(xiàng)目目錄是采用自動(dòng)生成,其它按需自己新建就好了。 項(xiàng)目架構(gòu) 項(xiàng)目目錄 ├── build ├── config ├── dist │?? └── static │?? ├── css │?? ├── fonts │?? ├── images │?? ├── js │?? └── lib ├── src │?? ├── api │?...

    1treeS 評(píng)論0 收藏0
  • Vue2.0利用vue-resource上傳文件到七牛

    摘要:年底,公司項(xiàng)目番茄表單的前端部分,開始了從傳統(tǒng)的到的徹底重構(gòu)。上傳流程圖不重要看文字事件觸發(fā)后,先去如果是圖片,可以同時(shí)通過(guò)以及將圖片預(yù)覽在頁(yè)面上后臺(tái)請(qǐng)求七牛的上傳,將拿到的和以及通過(guò)傳遞過(guò)來(lái)的一起到中。 關(guān)于上傳,總是有很多可以說(shuō)道的。16年底,公司項(xiàng)目番茄表單的前端部分,開始了從傳統(tǒng)的jquery到vue 2.0的徹底重構(gòu)。但是上傳部分,無(wú)論是之前的傳統(tǒng)版本,還是Vue新版本,都是...

    lcodecorex 評(píng)論0 收藏0
  • 推送近期三波關(guān)于Vue.js的資訊

    摘要:原文來(lái)自集前端最近很火的框架資源定時(shí)更新,歡迎一下。推送自己整理近期三波關(guān)于的資訊這里就拋磚引玉了,望有更屌的資源送助攻。 原文來(lái)自:集web前端最近很火的vue2框架資源;定時(shí)更新,歡迎Star一下。 推送自己整理近期三波關(guān)于Vue.js的資訊; 這里就拋磚引玉了,望有更屌的資源送助攻。 showImg(https://segmentfault.com/img/bVVeiZ); 第...

    Anonymous1 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<