<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Vue-Element-UI-Vuex-Vue-router梳理前端知識點

          共 63246字,需瀏覽 127分鐘

           ·

          2021-09-18 19:22

          Github來源: | 求星星 ? | 給個??關注,??點贊,??鼓勵一下作者

          前端工程師的職業(yè)

          • 初級工程師(對應薪資:5000-1w):初步掌握前端開發(fā),技術棧比較局限;
          • 中級工程師(對應薪資:1w-2w):技術棧進一步豐富,對實現(xiàn)細節(jié)不清楚;
          • 高級工程師(對應薪資:2w-3w):清楚實現(xiàn)細節(jié),不再局限某一技術棧;
          • 專家工程師(對應薪資:3w-4w):靈活運用各種技術,解決復雜的技術問題。

          on

          <html>
            <head>
              <title>$emit 和 $on</title>
              <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
            </head>
            <body>
              <div id="root">
                <button @click="boost">觸發(fā)事件</button>
              </div>
              <script>
                new Vue({
                  el: '#root',
                  data() {
                    return {
                      message: 'hello vue'
                    }
                  },
                  created() {
                    this.$on('my_events', this.handleEvents)
                  },
                  methods: {
                    handleEvents(e) {
                      console.log(this.message, e)
                    },
                    boost() {
                      this.$emit('my_events''my params')            
                    }
                  }
                })
              </script>
            </body>
          </html>

          directive 用法

          <html>
            <head>
              <title>directive 用法</title>
              <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
            </head>
            <body>
              <div id="root">
                <div v-loading="isLoading">{{data}}</div>
                <button @click="update">更新</button>
              </div>
              <script>
                Vue.directive('loading', {
                  update(el, binding, vnode) {
                    if (binding.value) {
                      const div = document.createElement('div')
                      div.innerText = '加載中...'
                      div.setAttribute('id''loading')
                      div.style.position = 'absolute'
                      div.style.left = 0
                      div.style.top = 0
                      div.style.width = '100%'
                      div.style.height = '100%'
                      div.style.display = 'flex'
                      div.style.justifyContent = 'center'
                      div.style.alignItems = 'center'
                      div.style.color = 'white'
                      div.style.background = 'rgba(0, 0, 0, .7)'
                      document.body.append(div)
                    } else {
                      document.body.removeChild(document.getElementById('loading'))
                    }
                  }
                })
                new Vue({
                  el: '#root',
                  data() {
                    return {
                      isLoading: false,
                      data: ''
                    }
                  },
                  methods: {
                    update() {
                      this.isLoading = true
                      setTimeout(() => {
                        this.data = '用戶數(shù)據(jù)'
                        this.isLoading = false
                      }, 3000)
                    }
                  }
                })
              </script>
            </body>
          </html>

          Vue.component 用法

          <html>
            <head>
              <title>Vue.component 用法</title>
              <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
            </head>
            <body>
              <div id="root">
                <Test :msg="message"></Test>
              </div>
              <script>
                Vue.component('Test', {
                  template: '<div>{{msg}}</div>',
                  props: {
                    msg: {
                      type: String,
                      default: 'default message'
                    }
                  }
                })
                new Vue({
                  el: '#root',
                  data() {
                    return {
                      message: "Test Component"
                    }
                  }
                })
              </script>
            </body>
          </html>

          Vue.extend 用法

          <html>
            <head>
              <title>Vue.extend 用法</title>
              <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
            </head>
            <body>
              <div id="root">
                <Test :msg="message"></Test>
              </div>
              <script>
                const component = Vue.extend({
                  template: '<div>{{msg}}</div>',
                  props: {
                    msg: {
                      type: String,
                      default: 'default message'
                    }
                  },
                  name: 'Test'
                })
                Vue.component('Test')
                new Vue({
                  el: '#root',
                  data() {
                    return {
                      message: "Test Extend Component"
                    }
                  }
                })
              </script>
            </body>
          </html>
          <html>
            <head>
              <title>Vue.extend 用法2</title>
              <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
              <style>
                #loading-wrapper {
                  position: fixed;
                  top: 0;
                  left: 0;
                  display: flex;
                  justify-content: center;
                  align-items: center;
                  width: 100%;
                  height: 100%;
                  background: rgba(0,0,0,.7);
                  color: #fff;
                }
              </style>
            </head>
            <body>
              <div id="root">
                <button @click="showLoading">顯示Loading</button>
              </div>
              <script>
                function Loading(msg) {
                  const LoadingComponent = Vue.extend({
                    template: '<div id="loading-wrapper">{{msg}}</div>',
                    props: {
                      msg: {
                        type: String,
                        default: msg
                      }
                    },
                    name: 'LoadingComponent'
                  })
                  const div = document.createElement('div')
                  div.setAttribute('id''loading-wrapper')
                  document.body.append(div)
                  new LoadingComponent().$mount('#loading-wrapper')
                  return () => {
                    document.body.removeChild(document.getElementById('loading-wrapper'))
                  }
                }
                Vue.prototype.$loading = Loading
                new Vue({
                  el: '#root',
                  methods: {
                    showLoading() {
                      const hide = this.$loading('正在加載,請稍等...')
                      setTimeout(() => {
                        hide()
                      }, 2000)
                    }
                  }
                })
              </script>
            </body>
          </html>

          Vue.use 用法

          <html>
            <head>
              <title>Vue.use 用法</title>
              <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
              <style>
                #loading-wrapper {
                  position: fixed;
                  top: 0;
                  left: 0;
                  display: flex;
                  justify-content: center;
                  align-items: center;
                  width: 100%;
                  height: 100%;
                  background: rgba(0,0,0,.7);
                  color: #fff;
                }
              </style>
            </head>
            <body>
              <div id="root">
                <button @click="showLoading">顯示Loading</button>
              </div>
              <script>
                const loadingPlugin = {
                  install: function(vm) {
                    const LoadingComponent = vm.extend({
                      template: '<div id="loading-wrapper">{{msg}}</div>',
                      props: {
                        msg: {
                          type: String,
                          default: 'loading...'
                        }
                      }
                    }, 'LoadingComponent')
                    function Loading(msg) {
                      const div = document.createElement('div')
                      div.setAttribute('id''loading-wrapper')
                      document.body.append(div)
                      new LoadingComponent({
                        props: {
                          msg: {
                            type: String,
                            default: msg
                          }
                        } 
                      }).$mount('#loading-wrapper')
                      return () => {
                        document.body.removeChild(document.getElementById('loading-wrapper'))
                      }
                    }
                    vm.prototype.$loading = Loading
                  }
                }
                Vue.use(loadingPlugin)
                new Vue({
                  el: '#root',
                  methods: {
                    showLoading() {
                      const hide = this.$loading('正在加載,請稍等...')
                      setTimeout(() => {
                        hide()
                      }, 2000)
                    }
                  }
                })
              </script>
            </body>
          </html>

          組件通信 provide 和 inject

          <html>
            <head>
              <title>組件通信 provide 和 inject</title>
              <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
            </head>
            <body>
              <div id="root">
                <Test></Test>
              </div>
              <script>
                function registerPlugin() {
                  Vue.component('Test', {
                    template: '<div>{{message}}<Test2 /></div>',
                    provide() {
                      return {
                        elTest: this
                      }
                    }, // function 的用途是為了獲取運行時環(huán)境,否則 this 將指向 window
                    data() {
                      return {
                        message: 'message from Test'
                      }
                    },
                    methods: {
                      change(component) {
                        this.message = 'message from ' + component
                      }
                    }
                  })
                  Vue.component('Test2', {
                    template: '<Test3 />'
                  })
                  Vue.component('Test3', {
                    template: '<button @click="changeMessage">change</button>',
                    inject: ['elTest'],
                    methods: {
                      changeMessage() {
                        this.elTest.change(this.$options._componentTag)
                      }
                    }
                  })
                }
                Vue.use(registerPlugin)
                new Vue({
                  el: '#root'
                })
              </script>
            </body>
          </html>

          過濾器 filter

          <html>
            <head>
              <title>過濾器 filter</title>
              <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
            </head>
            <body>
              <div id="root">
                {{message | lower}}
              </div>
              <script>
                new Vue({
                  el: '#root',
                  filters: {
                    lower(value) {
                      return value.toLowerCase()
                    }
                  },
                  data() {
                    return {
                      message: 'Hello Vue'
                    }
                  }
                })
              </script>
            </body>
          </html>

          監(jiān)聽器 watch

          <html>
            <head>
              <title>監(jiān)聽器 watch</title>
              <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
            </head>
            <body>
              <div id="root">
                <h3>Watch 用法1:常見用法</h3>
                <input v-model="message">
                <span>{{copyMessage}}</span>
              </div>
              <div id="root2">
                <h3>Watch 用法2:綁定方法</h3>
                <input v-model="message">
                <span>{{copyMessage}}</span>
              </div>
              <div id="root3">
                <h3>Watch 用法3:deep + handler</h3>
                <input v-model="deepMessage.a.b">
                <span>{{copyMessage}}</span>
              </div>
              <div id="root4">
                <h3>Watch 用法4:immediate</h3>
                <input v-model="message">
                <span>{{copyMessage}}</span>
              </div>
              <div id="root5">
                <h3>Watch 用法5:綁定多個 handler</h3>
                <input v-model="message">
                <span>{{copyMessage}}</span>
              </div>
              <div id="root6">
                <h3>Watch 用法6:監(jiān)聽對象屬性</h3>
                <input v-model="deepMessage.a.b">
                <span>{{copyMessage}}</span>
              </div>
                
              <script>
                new Vue({
                  el: '#root',
                  watch: {
                    message(value) {
                      this.copyMessage = value
                    }
                  },
                  data() {
                    return {
                      message: 'Hello Vue',
                      copyMessage: ''
                    }
                  }
                })
                new Vue({
                  el: '#root2',
                  watch: {
                    message: 'handleMessage'
                  },
                  data() {
                    return {
                      message: 'Hello Vue',
                      copyMessage: ''
                    }
                  },
                  methods: {
                    handleMessage(value) {
                      this.copyMessage = value
                    }
                  }
                })
                new Vue({
                  el: '#root3',
                  watch: {
                    deepMessage: {
                      handler: 'handleDeepMessage',
                      deep: true
                    }
                  },
                  data() {
                    return {
                      deepMessage: {
                        a: {
                          b: 'Deep Message'
                        }
                      },
                      copyMessage: ''
                    }
                  },
                  methods: {
                    handleDeepMessage(value) {
                      this.copyMessage = value.a.b
                    }
                  }
                })
                new Vue({
                  el: '#root4',
                  watch: {
                    message: {
                      handler: 'handleMessage',
                      immediate: true,
                    }
                  },
                  data() {
                    return {
                      message: 'Hello Vue',
                      copyMessage: ''
                    }
                  },
                  methods: {
                    handleMessage(value) {
                      this.copyMessage = value
                    }
                  }
                }),
                new Vue({
                  el: '#root5',
                  watch: {
                    message: [{
                      handler: 'handleMessage',
                    },
                    'handleMessage2',
                    function(value) {
                      this.copyMessage = this.copyMessage + '...'
                    }]
                  },
                  data() {
                    return {
                      message: 'Hello Vue',
                      copyMessage: ''
                    }
                  },
                  methods: {
                    handleMessage(value) {
                      this.copyMessage = value
                    },
                    handleMessage2(value) {
                      this.copyMessage = this.copyMessage + '*'
                    }
                  }
                })
                new Vue({
                  el: '#root6',
                  watch: {
                    'deepMessage.a.b''handleMessage'
                  },
                  data() {
                    return {
                      deepMessage: { a: { b: 'Hello Vue' } },
                      copyMessage: ''
                    }
                  },
                  methods: {
                    handleMessage(value) {
                      this.copyMessage = value
                    }
                  }
                })
              </script>
            </body>
          </html>

          class 和 style 綁定的高級用法

          <html>
            <head>
              <title>class 和 style 綁定的高級用法</title>
              <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
            </head>
            <body>
              <div id="root">
                <div :class="['active', 'normal']">數(shù)組綁定多個class</div>
                <div :class="[{active: isActive}, 'normal']">數(shù)組包含對象綁定class</div>
                <div :class="[showWarning(), 'normal']">數(shù)組包含方法綁定class</div>
                <div :style="[warning, bold]">數(shù)組綁定多個style</div>
                <div :style="[warning, mix()]">數(shù)組包含方法綁定style</div>
                <div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }">style多重值</div>
              </div>
              <script>
                new Vue({
                  el: '#root',
                  data() {
                    return {
                      isActive: true,
                      warning: {
                        color: 'orange'
                      },
                      bold: {
                        fontWeight: 'bold'
                      }
                    }
                  },
                  methods: {
                    showWarning() {
                      return 'warning'
                    },
                    mix() {
                      return {
                        ...this.bold,
                        fontSize: 20
                      }
                    }
                  }
                })
              </script>
            </body>
          </html>

          Vue.observable

          <html>
            <head>
              <title>Vue.observable</title>
              <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
            </head>
            <body>
              <div id="root">
                {{message}}
                <button @click="change">Change</button>
              </div>
              <script>
                const state = Vue.observable({ message: 'Vue 2.6' })
                const mutation = {
                  setMessage(value) {
                    state.message = value
                  }
                }
                new Vue({
                  el: '#root',
                  computed: {
                    message() {
                      return state.message
                    }
                  },
                  methods: {
                    change() {
                      mutation.setMessage('Vue 3.0')
                    }
                  }
                })
              </script>
            </body>
          </html>

          插槽 slot

          <html>
            <head>
              <title>插槽 slot</title>
              <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
            </head>
            <body>
              <div id="root">
                <div>案例1:slot的基本用法</div>
                <Test>
                  <template v-slot:header="{user}">
                    <div>自定義header({{user.a}})</div>
                  </template>
                  <template v-slot="{user}">
                    <div>自定義body({{user.b}})</div>
                  </template>
                </Test>
              </div>
              <div id="root2">
                <div>案例2:Vue2.6新特性 - 動態(tài)slot</div>
                <Test>
                  <template v-slot:[section]="{section}">
                    <div>this is {{section}}</div>
                  </template>
                </Test>
                <button @click="change">switch header and body</button>
              </div>
              <script>
                Vue.component('Test', {
                  template: 
                    '<div>' +
                      '<slot name="header" :user="obj" :section="'header'">' +
                        '<div>默認header</div>' +
                      '</slot>' +
                      '<slot :user="obj" :section="'body'">默認body</slot>' +
                    '</div>',
                  data() {
                    return {
                      obj: { a: 1, b: 2 }
                    }
                  }
                })
                new Vue({ el: '#root' })
                new Vue({ 
                  el: '#root2',
                  data() {
                    return {
                      section: 'header'
                    }
                  },
                  methods: {
                    change() {
                      this.section === 'header' ?
                        this.section = 'default' :
                        this.section = 'header'
                    }
                  }
                })
              </script>
            </body>
          </html>

          Element-UI

          vue create element-test
          vuex+router ([Vue 2] router, vuex, dart-sass, babel, eslint)
            Default ([Vue 2] babel, eslint)
            Default (Vue 3) ([Vue 3] babel, eslint)
            Manually select features
          image.png
          1. 初始化項目
          vue create element-test
          1. 安裝
          npm i element-ui -S
          1. Vue 插件
          import ElementUI from 'element-ui'

          Vue.use(ElementUI)
          1. 引用樣式
          import 'element-ui/lib/theme-chalk/index.css'

          按需加載

          Entrypoints:
            app (1.03 MiB)
                css/chunk-vendors.a16c4353.css
                js/chunk-vendors.29976e71.js
                css/app.601d2ada.css
                js/app.29e7d705.js
          For more info visit https://webpack.js.org/guides/code-splitting/

            File                                   Size              Gzipped

            dist\js\chunk-vendors.29976e71.js      845.63 KiB        225.63 KiB
            dist\js\app.29e7d705.js                2.77 KiB          1.30 KiB
            dist\css\chunk-vendors.a16c4353.css    209.55 KiB        33.63 KiB
            dist\css\app.601d2ada.css              0.25 KiB          0.19 KiB

            Images and other types of assets omitted.

          按需加載的用法如下:

          1. 安裝 babel-plugin-component
          npm install babel-plugin-component -D
          1. 修改 babel.config.js:
          {
            "presets": [["es2015", { "modules"false }]],
            "plugins": [
              [
                "component",
                {
                  "libraryName""element-ui",
                  "styleLibraryName""theme-chalk"
                }
              ]
            ]
          }

          Vuex 原理解析

          Vuex 的原理關鍵:使用 Vue 實例管理狀態(tài)

          <html>
            <head>
              <title>vuex 原理解析</title>
              <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
            </head>
            <body>
              <div id="root">{{data}}</div>
              <div id="root2">{{data2}}</div>
              <div id="root3">
                <button @click="change">change</button>
              </div>
              <script>
                function registerPlugin(Vue) {
                  const vuex = {}
                  vuex._vm = new Vue({
                    data: {
                      message: 'hello vue.js'
                    }
                  })
                  vuex.state = vuex._vm
                  vuex.mutations = {
                    setMessage(value) {
                      vuex.state.message = value
                    }
                  }
                  function init() {
                    this.$store = vuex
                  }
                  Vue.mixin({
                    beforeCreate: init
                  })
                }
                Vue.use(registerPlugin)
                new Vue({
                  el: '#root',
                  computed: {
                    data() {
                      return this.$store.state.message
                    }
                  }
                })
                new Vue({
                  el: '#root2',
                  computed: {
                    data2() {
                      return this.$store.state.message
                    }
                  }
                })
                new Vue({
                  el: '#root3',
                  methods: {
                    change() {
                      const newValue = this.$store.state.message + '.'
                      this.$store.mutations.setMessage(newValue)
                    }
                  }
                })
              </script>
            </body>
          </html>

          vue-router 實現(xiàn)原理

          vue-router 實例化時會初始化 this.history,不同 mode 對應不同的 history

          constructor (options: RouterOptions = {}) {
              this.mode = mode
              
              switch (mode) {
                case 'history':
                  this.history = new HTML5History(this, options.base)
                  break
                case 'hash':
                  this.history = new HashHistory(this, options.base, this.fallback)
                  break
                case 'abstract':
                  this.history = new AbstractHistory(this, options.base)
                  break
                default:
                  if (process.env.NODE_ENV !== 'production') {
                    assert(false, `invalid mode: ${mode}`)
                  }
              }
          }

          這里以 HashHistory 為例,vue-router 的 push 方法實現(xiàn)如下:

          push (location: RawLocation, onComplete?: Function, onAbort?: Function) {
              // $flow-disable-line
              if (!onComplete && !onAbort && typeof Promise !== 'undefined') {
                return new Promise((resolve, reject) => {
                  this.history.push(location, resolve, reject)
                })
              } else {
                this.history.push(location, onComplete, onAbort)
              }
          }

          HashHistory 具體實現(xiàn)了 push 方法:

          function pushHash (path) {
            if (supportsPushState) {
              pushState(getUrl(path))
            } else {
              window.location.hash = path
            }
          }

          對路由的監(jiān)聽通過 hash 相應的事件監(jiān)聽實現(xiàn):

          window.addEventListener(
            supportsPushState ? 'popstate' : 'hashchange',
            () => {
              const current = this.current
              if (!ensureSlash()) {
                return
              }
              this.transitionTo(getHash(), route => {
                if (supportsScroll) {
                  handleScroll(this.router, route, current, true)
                }
                if (!supportsPushState) {
                  replaceHash(route.fullPath)
                }
              })
            }
          )

          除此之外,vue-router 還提供了兩個組件:

          Vue.component('RouterView', View)
          Vue.component('RouterLink', Link)

          vue-router 路由守衛(wèi)

          創(chuàng)建 router.js:

          import Vue from 'vue'
          import Route from 'vue-router'
          import HelloWorld from './components/HelloWorld'

          Vue.use(Route)
          const routes = [
            { path: '/hello-world', component: HelloWorld }
          ]
          const router = new Route({
            routes
          })

          export default router

          在 main.js 中引用 router,并加入 vue 實例:

          import router from './router'

          new Vue({
            render: h => h(App),
            router
          }).$mount('#app')

          全局守衛(wèi)

          router.beforeEach((to, from, next) => {
            console.log('beforeEach', to, from)
            next()
          })

          router.beforeResolve((to, from, next) => {
            console.log('beforeResolve', to, from)
            next()
          })

          router.afterEach((to, from) => {
            console.log('afterEach', to, from)
          })

          局部守衛(wèi)

          beforeRouteEnter (to, from, next) {
            // 不能獲取組件實例 `this`
            console.log('beforeRouteEnter', to, from)
            next()
          },
          beforeRouteUpdate (to, from, next) {
            console.log('beforeRouteUpdate', to, from)
            next()
          },
          beforeRouteLeave (to, from, next) {
            console.log('beforeRouteLeave', to, from)
            next()
          }

          路由元信息

          通過 meta 定義路由元信息

          const routes = [
            { path: '/a', component: A, meta: { title: 'Custom Title A' } }
          ]

          使用 meta 信息動態(tài)修改標題

          router.beforeEach((to, from, next) => {
            console.log('beforeEach', to, from)
            if (to.meta && to.meta.title) {
              document.title = to.meta.title
            } else {
              document.title = 'default title'
            }
            next()
          })

          路由 API

          使用 router.addRoutes 動態(tài)添加路由

          addRoute() {
              this.$router.addRoutes([{
                path: '/b', component: B, meta: { title: 'Custom Title B' },
              }])
          }

          此時可以訪問到 B 組件

          <router-link to='/b'>to B</router-link>

          項目初始化

          git clone https://github.com/PanJiaChen/vue-element-admin
          cd vue-element-admin
          npm i
          npm run dev

          項目精簡

          • 刪除 src/views 下的源碼,保留:

            • dashboard:首頁
            • error-page:異常頁面
            • login:登錄
            • redirect:重定向
          • 對 src/router/index 進行相應修改

          • 刪除 src/router/modules 文件夾

          • 刪除 src/vendor 文件夾

          vue-element-admin 初始化項目

          vue-element-admin 實現(xiàn)了登錄模塊,包括 token 校驗、網(wǎng)絡請求等

          項目配置

          通過 src/settings.js 進行全局配置:

          • title:站點標題,進入某個頁面后,格式為:
          頁面標題 - 站點標題
          • showSettings:是否顯示右側懸浮配置按鈕
          • tagsView:是否顯示頁面標簽功能條
          • fixedHeader:是否將頭部布局固定
          • sidebarLogo:菜單欄中是否顯示LOGO
          • errorLog:默認顯示錯誤日志的環(huán)境

          源碼調(diào)試

          如果需要進行源碼調(diào)試,需要修改 vue.config.js:

          config
            // https://webpack.js.org/configuration/devtool/#development
            .when(process.env.NODE_ENV === 'development',
              config => config.devtool('cheap-source-map')
            )

          將 cheap-source-map 改為 source-map,如果希望提升構建速度可以改為 eval

          通常建議開發(fā)時保持 eval 配置,以增加構建速度,當出現(xiàn)需要源碼調(diào)試排查問題時改為 source-map

          項目結構

          • api:接口請求

          • assets:靜態(tài)資源

          • components:通用組件

          • directive:自定義指令

          • filters:自定義過濾器

          • icons:圖標組件

          • layout:布局組件

          • router:路由配置

          • store:狀態(tài)管理

          • styles:自定義樣式

          • utils:通用工具方法

            • auth.js:token 存取
            • permission.js:權限檢查
            • request.js:axios 請求封裝
            • index.js:工具方法
          • views:頁面

          • permission.js:登錄認證和路由跳轉(zhuǎn)

          • settings.js:全局配置

          • main.js:全局入口文件

          • App.vue:全局入口組件

          后端框架搭建

          npm init -y

          安裝依賴

          npm i -S express

          創(chuàng)建 app.js

          const express = require('express')

          // 創(chuàng)建 express 應用
          const app = express()

          // 監(jiān)聽 / 路徑的 get 請求
          app.get('/'function(req, res) {
            res.send('hello node')
          })

          // 使 express 監(jiān)聽 5000 端口號發(fā)起的 http 請求
          const server = app.listen(5000, function() {
            const { address, port } = server.address()
            console.log('Http Server is running on http://%s:%s', address, port)
          })

          Express 三大基礎概念

          中間件

          中間件是一個函數(shù),在請求和響應周期中被順序調(diào)用

          const myLogger = function(req, res, next) {
            console.log('myLogger')
            next()
          }

          app.use(myLogger)

          提示:中間件需要在響應結束前被調(diào)用

          路由

          應用如何響應請求的一種規(guī)則

          響應 / 路徑的 get 請求:

          app.get('/'function(req, res) {
            res.send('hello node')
          })

          響應 / 路徑的 post 請求:

          app.post('/'function(req, res) {
            res.send('hello node')
          })

          異常處理

          通過自定義異常處理中間件處理請求中產(chǎn)生的異常

          app.get('/'function(req, res) {
            throw new Error('something has error...')
          })

          const errorHandler = function (err, req, res, next) {
            console.log('errorHandler...')
            res.status(500)
            res.send('down...')
          }

          app.use(errorHandler)

          使用時需要注意兩點:

          • 第一,參數(shù)一個不能少,否則會視為普通的中間件
          • 第二,中間件需要在請求之后引用

          項目框架搭建

          路由

          安裝 boom 依賴:

          npm i -S boom

          創(chuàng)建 router 文件夾,創(chuàng)建 router/index.js:

          const express = require('express')
          const boom = require('boom')
          const userRouter = require('./user')
          const {
            CODE_ERROR
          } = require('../utils/constant')

          // 注冊路由
          const router = express.Router()

          router.get('/'function(req, res) {
            res.send('歡迎學習管理后臺')
          })

          // 通過 userRouter 來處理 /user 路由,對路由處理進行解耦
          router.use('/user', userRouter)

          /**
           * 集中處理404請求的中間件
           * 注意:該中間件必須放在正常處理流程之后
           * 否則,會攔截正常請求
           */
          router.use((req, res, next) => {
            next(boom.notFound('接口不存在'))
          })

          /**
           * 自定義路由異常處理中間件
           * 注意兩點:
           * 第一,方法的參數(shù)不能減少
           * 第二,方法的必須放在路由最后
           */
          router.use((err, req, res, next) => {
            const msg = (err && err.message) || '系統(tǒng)錯誤'
            const statusCode = (err.output && err.output.statusCode) || 500;
            const errorMsg = (err.output && err.output.payload && err.output.payload.error) || err.message
            res.status(statusCode).json({
              code: CODE_ERROR,
              msg,
              error: statusCode,
              errorMsg
            })
          })

          module.exports = router

          創(chuàng)建 router/use.js:

          const express = require('express')

          const router = express.Router()

          router.get('/info'function(req, res, next) {
            res.json('user info...')
          })

          module.exports = router

          創(chuàng)建 utils/constant:

          module.exports = {
            CODE_ERROR: -1
          }

          驗證 /user/info:

          "user info..."

          驗證 /user/login:

          {"code":-1,"msg":"接口不存在","error":404,"errorMsg":"Not Found"}

          登錄

          • 用戶名密碼校驗
          • token 生成、校驗和路由過濾
          • 前端 token 校驗和重定向

          Nginx 服務器搭建

          修改配置文件

          打開配置文件 nginx.conf:

          • windows 位于安裝目錄下
          • macOS 位于:/usr/local/etc/nginx/nginx.conf

          修改一:添加當前登錄用戶為da

          user sam da;

          修改二:在結尾大括號之前添加:

          include /Users/sam/upload/upload.conf;

          這里 /Users/sam/upload 是資源文件路徑,/Users/sam/upload/upload.conf 是額外的配置文件,當前把 /Users/sam/upload/upload.conf 配置文件的內(nèi)容加入 nginx.conf 也是可行的!

          修改三:添加 /Users/sam/upload/upload.conf 文件,配置如下:

          server

            charset utf-8;
            listen 8089;
            server_name http_host;
            root /Users/sam/upload/;
            autoindex on;
            add_header Cache-Control "no-cache, must-revalidate";
            location / { 
              add_header Access-Control-Allow-Origin *;
            }
          }

          如果需要加入 https 服務,可以再添加一個 server:

          server
          {
            listen 443 default ssl;
            server_name https_host;
            root /Users/sam/upload/;
            autoindex on;
            add_header Cache-Control "no-cache, must-revalidate";
            location / {
              add_header Access-Control-Allow-Origin *;
            }
            ssl_certificate /Users/sam/Desktop/https/da.pem;
            ssl_certificate_key /Users/sam/Desktop/https/da.key;
            ssl_session_timeout  5m;
            ssl_protocols  SSLv3 TLSv1;
            ssl_ciphers  ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
            ssl_prefer_server_ciphers  on;
          }
          • https證書:/Users/sam/Desktop/https/da.pem
          • https:私鑰:/Users/sam/Desktop/https/da.key

          啟動服務

          啟動 nginx 服務:

          sudo nginx

          重啟 nginx 服務:

          sudo nginx -s reload

          停止 nginx 服務:

          sudo nginx -s stop

          檢查配置文件是否存在語法錯誤:

          sudo nginx -t

          訪問地址:

          • http: http://localhost:8089
          • https: https://localhost

          ??掘金文章

          • 前端日??偨Y
          • 一份不可多得的TypeScript系統(tǒng)入門整理
          • JS葵花寶典秘籍筆記,為你保駕護航金三銀四
          • TypeScript趁早學習提高職場競爭力
          • 前端模擬面試字數(shù)過23477萬內(nèi)容
          • JavaScript數(shù)據(jù)結構之鏈表 | 技術點評
          • JavaScript的數(shù)據(jù)結構-集合 |技術點評
          • 這是我的第一次JavaScript初級技巧
          • 一個合格的初級前端工程師需要掌握的模塊筆記
          • 【初級】個人分享Vue前端開發(fā)教程筆記
          • localStorage和sessionStorage本地存儲
          • HTML5中的拖放功能
          • 挑戰(zhàn)前端知識點HTTP/ECMAScript
          • 前端170面試題+答案學習整理(良心制作)

          ??關注+點贊+收藏+評論+轉(zhuǎn)發(fā)??

          點贊、收藏和評論

          我是Jeskson(達達前端),感謝各位人才的:點贊、收藏和評論,我們下期見!(如本文內(nèi)容有地方講解有誤,歡迎指出?謝謝,一起學習了)

          我們下期見!

          文章持續(xù)更新,可以微信搜一搜「 程序員哆啦A夢 」第一時間閱讀,回復【資料】有我準備的一線大廠資料,本文 https://www.1024bibi.com 已經(jīng)收錄

          github收錄,歡迎Star:https://github.com/webVueBlog/WebFamily

          瀏覽 41
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美激情另类 | 中文字幕一区在线 | 亚洲综合免费观看高清完整版在线观 | 亚洲天堂一区在线观看 | wwwCn一起操 |