zhanghaoran
文章 文章详情

译问前端笔记,nuxt.js框架

阅读:12 分类:nuxt.js 发布时间:1天前

译问前端笔记

译问地址: http://www.qidulp.com

1.基础配置

1. 项目初始化配置

1.创建项目(下载安装nuxt.js)

npx create-nuxt-app qidu

2.配置css为外联

nuxt.config.js 文件中的 build 中加入以下代码:

build: {
    // css文件外联方式引入(外部引入)
    extractCSS: true,
}

3. 配置element-ui组件和css 为按需加载

3.1. 下载element-ui
npm install element-ui -S
3.2. 在根目录的 plugins文件夹(~/plugins/)下新建 一个 element-ui.js 文件, 然后根据需要引入组件
import Vue from 'vue'
import {button} from "element-ui";
Vue.use(button);
3.3. 把配置添加到全局中:打开 nuxt.config.js文件, 在其中的 plugins 中加入刚才写的element-ui.js文件
plugins: [
    { src: '@/plugins/element-ui', ssr: true }
]
3.4. 按需加载 element-ui 组件所需的css文件

nuxt.config.js 文件,在其中的 build 中加入以下代码:

build: {
    // 按需引入element-ui
    babel: {
        plugins: [
            [ "component", 
            {"libraryName": "element-ui",  "styleLibraryName": "theme-chalk"}
            ]
        ]
    },
}
3.5. 在组件中就可以使用element-uibutton组件和样式了。

4. 配置公共css

4.1. 在~/assets/文件下创建公共css文件
4.2. 在nuxt.config.js文件中添加 res.css 作用于全局样式
css: [
    '~/assets/css/res.css',
],

5. 配置指定IP和port(端口)访问项目

package.json中添加如下代码:

{
  "config": {
    "nuxt": {
        "host": "0.0.0.0",
        "port": "8068"
    }
    }
}

重启项目,局域网内可通过本机IP:8068访问项目

6. 指定页面(~/page/)使用某一模版(~/layout/)

~/page/index.vue文件中,添加如下代码即可使用指定的layout中的模板

<script>
  export default {
    layout: '自定义模板名称'       // ~/layout/下文件名称
  }
</script>

7. 设置meta标签、控制台打印个性内容

~/ 下创建 app.html 文件,键入以下:

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    {{HEAD}}
    <!-- 强制使用chrome内核或IE最新版内核 webkit? -->
    <meta http-equiv="X-UA-Compatible" content="IE=EmulateIE1">
    <meta name="renderer" content="webkit">
    <meta name="force-rendering" content="webkit">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1">
    <!-- DNS预解析 -->
    <link rel="dns-prefetch" href="//www.qidulp.com">
    <link rel="dns-prefetch" href="//ywserver.qidulp.com">
    <link rel="dns-prefetch" href="//passport.qidulp.com">
</head>
<body>
{{APP}}
  <script>
    if (window.console) {
        console.log("%c译问", "color:#0084ff;font-weight:bold")
    }
</script>
<script>
    Function.prototype.makeMulti = function(){
        let l = new String(this)
        l = l.substring(l.indexOf("/*")+3,l.lastIndexOf("*/"))
        return l
    }
    let string = function(){/*

          _____                    _____                    _____                    _____
         /\    \                  /\    \                  /\    \                  /\    \
        /::\____\                /::\    \                /::\    \                /::\    \
       /:::/    /                \:::\    \              /::::\    \              /::::\    \
      /:::/    /                  \:::\    \            /::::::\    \            /::::::\    \
     /:::/    /                    \:::\    \          /:::/\:::\    \          /:::/\:::\    \
    /:::/____/                      \:::\    \        /:::/__\:::\    \        /:::/__\:::\    \
   /::::\    \                      /::::\    \      /::::\   \:::\    \      /::::\   \:::\    \
  /::::::\    \   _____    ____    /::::::\    \    /::::::\   \:::\    \    /::::::\   \:::\    \
 /:::/\:::\    \ /\    \  /\   \  /:::/\:::\    \  /:::/\:::\   \:::\____\  /:::/\:::\   \:::\    \
/:::/  \:::\    /::\____\/::\   \/:::/  \:::\____\/:::/  \:::\   \:::|    |/:::/__\:::\   \:::\____\
\::/    \:::\  /:::/    /\:::\  /:::/    \::/    /\::/   |::::\  /:::|____|\:::\   \:::\   \::/    /
 \/____/ \:::\/:::/    /  \:::\/:::/    / \/____/  \/____|:::::\/:::/    /  \:::\   \:::\   \/____/
          \::::::/    /    \::::::/    /                 |:::::::::/    /    \:::\   \:::\    \
           \::::/    /      \::::/____/                  |::|\::::/    /      \:::\   \:::\____\
           /:::/    /        \:::\    \                  |::| \::/____/        \:::\   \::/    /
          /:::/    /          \:::\    \                 |::|  ~|               \:::\   \/____/
         /:::/    /            \:::\    \                |::|   |                \:::\    \
        /:::/    /              \:::\____\               \::|   |                 \:::\____\
        \::/    /                \::/    /                \:|   |                  \::/    /
         \/____/                  \/____/                  \|___|                   \/____/


        */ }
    console.log(string.makeMulti());
</script>
</body>
</html>

2. Nuxt下axios配置

2.1. 下载@nuxt/axios

npm install @nuxtjs/axios -S

2.2. 在nuxt.config.js中配置axios

modules: [
    '@nuxtjs/axios',
],

此时,就可以在组件或页面中使用axios了

// ~/page/xx.vue 异步加载
// 异步获取方法内this指向不到axios,需要在先引入下
async asyncData({$axios}) {
  let { res } = await $axios.get(`https://xxx.com/api/xxx`) 
  console.log(res)    
}
// 正常使用axios
a(){
  this.$axios.get('http://ywserver.qidulp.com/api/getData')
  .then(res => {
       consloe.log(res)
  })
}

2.3. 配置baseUrl,拦截器

2.3.1. 在~/plugins/下创建 axios.js文件

// 前两个cookie操作相关,后两个加载进度条相关 <==> 下文介绍
import getCookie from "../utils/getCookie";
import Cookie from "js-cookie";
import NProgress from "nprogress";
import "nprogress/nprogress.css"; //这个样式必须引入

export default function ({store, redirect, req, router, app: { $axios }})  {
    // 数据访问前缀
    $axios.defaults.baseURL = 'http://ywserver/qidulp.com/api';
     // 获取服务端的token
    if(process.server){
        var token = getCookie.getcookiesInServer(req).token;
    }
    // 获取客户端token
    if(process.client){
        var token = getCookie.getcookiesInClient('token');
    }
    // 如果客户端和服务端中未获取到token,尝试获取vuex中的token
    if (token == "") {
        var token = store.state.token;
    }
    // request拦截器
    $axios.onRequest(config => {
        if(process.client){
            // 客户端下,请求进度条开始
            NProgress.start();
        }
        // 将获取到token加入到请求头中
        config.headers.common['Authorization'] = token;
    });
    // response拦截器,数据返回后,可以先在这里进行一个简单的判断
    $axios.interceptors.response.use(
        response => {
            if(process.client){
                // 客户端下, 请求进度条结束
                NProgress.done();
            }
            // return response
            if(response.data.code == 401){
                // 返回401,token验证失败,清除客户端cookie
                Cookie.remove("token");
                  // 重定向到登录页面, 这里做一个判断,容错:req.url 未定义
                if(req.url){
                    redirect("/sign?ref="+req.url)
                }else{
                    redirect("/sign")
                }
            }else if(response.data.code == 404){
                // 重定向到404页面
                redirect("/")
            }
            else{
                // 请求接口数据正常,返回数据
                return response
            }
        },
        error => {
            if(process.client){
                NProgress.done();
            }
            return Promise.reject(error)   // 返回接口返回的错误信息
     });
        // 错误拦截器
      $axios.onError(error => {
        if(error.response == undefined || error.response.status == 500){
            redirect("/500.html")
        }
        if(error.response.status == 404){
            redirect("/404.html")
        }
    });
}

2.3.2. 添加axios.jsnuxt.config.js中,全局下axios操作共用上述配置

plugins: [
    '~/plugins/axios',
],

other:

1. nprogress接口请求进度条相关

使用方法:

  1. 下载 npm install nprogress -S
  2. 如在axios.js中,先引入,再在客户端请求时加上

2.1. 下载js-cookie

npm install js-cookie -S

2.2 基本使用

// 1.获取
Cookie.get(key)
// 2.设置
Cookie.set('name', value, {expires: expires})
// 3.删除
Cookie.remove("name")
// 过期时间设置:
let expires = new Date(new Date() * 1 + 86400000 * 20)} // 86400000ms 为一天 ,*20为20天

2.3. 封装cookie在服务端和客户端都可以使用的方法

  • 创建~/utils/cookieGet.js
import Cookie from 'js-cookie'

export default {
  //获取服务端cookie
  getcookiesInServer:function (req) {
    let service_cookie = {};
    req && req.headers.cookie && req.headers.cookie.split(';').forEach(function (val) {
      let parts = val.split('=');
      service_cookie[parts[0].trim()] = (parts[1] || '').trim();
    });
    return service_cookie;
  },
  //获取客户端cookie
  getcookiesInClient:function (key) {
    return Cookie.get(key) ? Cookie.get(key) : ''
  }
}
  • 使用

    vue <script> import getCookie from '../utils/cookieGet.js' export.defaults{ create(){ if(process.server){ let token = getCookie.getcookiesInServer(req).token; } if(process.client){ let token = getCookie.getcookiesInClient('token'); } } } </script>

3. 验证规则

用户相关

手机号验证规则
const reg = /^1[3|4|5|6|7|8|9][0-9]\d{8}$/;
  1. 手机号为11位正整数;
  2. 必须是13,14,15,16,17,18,19号段开头
邮箱验证规则
const emailReg = /^([a-zA-Z]|[0-9])(\w|\-)+@[a-zA-Z0-9]+\.([a-zA-Z]{2,4})$/;

必须包含 @ .(英文字符)

  1. @前包括:小写字母a-z,大写字母A-Z,正整数0-9,-(下划线) : 任意长度;匹配包括下划线的任何单词字符
  2. @后包括:小写字母a-z,大写字母A-Z,正整数0-9 : 任意长度
  3. . 后包括:小写字母a-z,大写字母A-Z : 2-4位字符
密码验证规则
password.length < 6

密码: 大于等于7位的任意字符

2.自定义

1. 无限滚动1

在需要的组件或页面内写入

监听鼠标是否滑动道当前文档最底部,到最底部时调用获取数据方法

<script>
    export default{
    data(){
      dataList: '',
      offset: 1.
      limit: 11,
      loading: true,
    },
    mounted() {
        window.addEventListener('scroll', this.monitorHeight);
    },
    methods:{
      monitorHeight() {
        var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;                    // 鼠标滚动到的位置 距离文档最上部的距离
        var windowHeight = document.documentElement.clientHeight || document.body.clientHeight;          // 当前可视窗高度
        var scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;           // 整个文档的高度
        // 监听高度 获取是否到屏幕底部 返回给子组件状态
        if (scrollHeight - 200 <= scrollTop + windowHeight) {
          if (this.hotData.question_count > this.hotData.questions.length) {
            this.getData()
          }
        }
       },
         getData(){
           if(this.loading){
             this.loading = false;
             let offsetNum = this.limit * this.offset;
             this.$axios.get("/special/?limit="+ this.limit +"&offset="+offsetNum)
               .then(res=>{
               if(res.data.code == 0 && res.data.data.questions.length > 0){
                 let newData = res.data.data;
                 var self = this;
                 newData.forEach(item=>{
                   self.dataList.push(item)
                 });
                 this.offset += 1;
                 this.loading = true
               }else{
                 this.loading = false;
               }
             })
           }
         }
    }
  }
</script>

2. 无限滚动2

~/layout/下的模版文件中监听是否滚动到文档最底部,将状态实时在vuex中修改变化

在需要无限滚动的组件或页面中监听vuex中数据的变化

~/store/index.js

import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);

const state = () => ({
    isEndData: false,   // 是否滑倒底部
});
const mutations = {
    isEnd(state) {
        state.isEndData = true
    },
    notEnd(state) {
        state.isEndData = false
    },
};

export default {state, mutations}

~/layout/default.vue

<script>
    export default{
    mounted() {
        window.addEventListener('scroll', this.monitorHeight);          // 监听屏幕高度
    },
    methods:{
      monitorHeight(){
        var scrollTop = document.documentElement.scrollTop||document.body.scrollTop;                    // 鼠标滚动到的位置 距离文档最上部的距离
        var windowHeight = document.documentElement.clientHeight || document.body.clientHeight;          // 当前可视窗高度
        var scrollHeight = document.documentElement.scrollHeight||document.body.scrollHeight;           // 整个文档的高度
        // 监听高度 获取是否到屏幕底部 返回给子组件状态
        if(scrollHeight-200 <= scrollTop+windowHeight){
          this.$store.commit("isEnd");
        }else{
          if(this.$store.state.isEndData){
            this.$store.commit("notEnd");
          }
        }
      }
    }
  }
</script>

~/page/index.vue

在需要无限滚动的页面中:

<script>
    export default{
    data(){
      return{
        recommendData: [],
        loading: true,
        noData: false,
        page: 1, 
        limit: 11,
      }
    },
    computed:{
      getIsEnd(){
        return this.$store.state.isEndData
      }
    },
    watch: {
      getIsEnd(){
        if(this.loading && !this.noData){
          this.loading = false;
          let offsetNum = parseInt(this.page*this.limit);
          this.$axios.get("/homepage/?limit="+ this.limit + "&offset="+ offsetNum)
            .then(res=>{
            if(res.data.code == 0 && res.data.data.length > 0){
              let newData = res.data.data;
              var self = this;
              newData.forEach(item=>{
                self.recommendData.push(item)
              });
              this.page += 1;
              this.loading = true;
            }else{
              this.loading = false;
              this.noData = true
            }
          })
         }
      }
    },
  }
</script>

3. sticky定位

当前元素在屏幕可视区不可见的时候,会自动定位到当前屏幕可视区底部10px的位置。
当前元素在屏幕可视区可见的时候,此定位方式和位置不会生效。

 <!-- 父元素须为relative, 且不能有overflow元素 -->
 postion: sticky;
 <!-- left, right, top, right四个方向都可以指定 -->
 bottom: 10px;

4. 实时监听浏览器屏幕宽度

<script>
    export default(){
    data(){
      return{
        screenWidth : '',
      }
    },
    mounted(){   
      window.onresize = () => {
          return (() => {
              this.screenWidth = document.documentElement.clientWidth;
          })()
      }
        },
    watch: {
      screenWidth (news, old) {
        var self = this;
        if (!this.timer) {
          setTimeout(function () {
            self.timer = false
          }, 4000)
        }
      }
    },
  }
</script>

5. Nuxt.js中使用图片裁剪

用户上传图片时

  1. 判断图片尺寸大小,宽高不能小于1200px240;小于这个尺寸将无法完美裁剪。
  2. 将图片转化为base64格式,即时回显图片和不浪费服务器资源。
  3. 这两步完成后,将进入到vue-cropper的裁剪操作了,具体操作可见文档,我在下面写了我的配置供参考;vue-cropper地址: https://github.com/xyxiao001/vue-cropper
  4. 裁剪操作结束,点击确认,得到裁剪后返回图片对象为blod类型,但服务器只接收file类型,故需转为file类型给服务器;得到服务器图片路径后,替换掉原本图片路径,完成✅
  1. 下载安装vue-cropper

    npm install vue-cropper -S

  2. 全局注入配置

    1. ~/plugins/文件下,创建cropper.js

      js import vueCropper from 'vue-cropper'; import Vue from 'vue'; Vue.use(vueCropper);

    2. ~/nuxt.config.js文件中,添加到全局插件配置中

      plugins: [ { src: '~/plugins/cropper', ssr: false } ]

  3. 使用

    1. template中:

      ```

      取 消 确认

      ```

    2. style中:

      .cropper-content{ width: 100%; height: 300px; } .cropper { width: 100%; height: 240px; } .btnGroup{ float: right; margin-top: 10px; margin-right: 15px; }

    3. script中:

      ``` export default{ data(){ status: true, option: { img: '', // 裁剪图片的地址 info: true, // 裁剪框的大小信息 outputSize: 0.8, // 裁剪生成图片的质量 outputType: 'jpeg', // 裁剪生成图片的格式 canScale: true, // 图片是否允许滚轮缩放 autoCrop: true, // 是否默认生成截图框 autoCropWidth: 1200, // 默认生成截图框宽度 autoCropHeight: 240, // 默认生成截图框高度 fixedBox: true, // 固定截图框大小 不允许改变 fixed: true, // 是否开启截图框宽高固定比例 fixedNumber: [25, 6], // 截图框的宽高比例 // full: true, // 是否输出原图比例的截图 canMoveBox: false, // 截图框能否拖动 original: false, // 上传图片按照原始比例渲染 centerBox: true, // 截图框是否被限制在图片里面 infoTrue: false, // true 为展示真实输出图片宽高 false 展示看到的截图框宽高 mode: 'cover', // cover 图片铺满容器 }, }, methods:{ // 触发 input:file uploadFile() { try{ this.$refs.upload.querySelector('input').click(); }catch (e) {} }, // 点击上传按钮后的事件 upload(e) { let file = e.target.files[0]; var self = this; this.createReader(file, function (w, h) { if(w<1200 || h<240){ self.$message.error("请上传宽度大于 1200px,高度大于 240px 的封面图片。"); let UFI = document.getElementById("uploadFileInput"); UFI.value = ''; }else{ self.file2base64(file) } }) } ,

      // 获取图片宽高

      createReader(file, whenReady) { var reader = new FileReader; reader.onload = function (evt) { var image = new Image(); image.onload = function () { var width = this.width; var height = this.height; if (whenReady) whenReady(width, height); }; image.src = evt.target.result; }; reader.readAsDataURL(file); },

      // file类型文件 转base64文件类型

      file2base64(file){ var reader = new FileReader(); reader.readAsDataURL(file); var self = this; reader.onload = function (e) { // 图片base64化 let newUrl = this.result; //图片路径 self.$nextTick(() => { self.pageImage = newUrl; self.option.img = newUrl; self.dialogVisible = true }) } },

      // 点击确定,这一步是可以拿到处理后的地址, 然后上传到服务器 finish() { this.$refs.cropper.getCropBlob((data) => { // 将接收到blod文件对象转为file let file = new File([data], 'proFileCover.jpg',{type: data.type, lastModified: Date.now()}); let params = new FormData(); params.append("image", file); var self = this; self.$axios.post("upload_image", params) .then(res=>{ if(res.data.code == 0){ // 显示图片 self.pageImage = res.data.data; // 关闭隐藏div,显示图片 self.status = false; }
      }) } }, }

      ```


联系邮箱:manbanzhen@qq.com