zoukankan      html  css  js  c++  java
  • 【转】 后端小白的VUE入门笔记, 进阶篇

    【转】 后端小白的VUE入门笔记, 进阶篇

    使用 vue-cli( 脚手架) 搭建项目

    基于vue-cli 创建一个模板项目
    通过 npm root -g 可以查看vue全局安装目录,进而知道自己有没有安装vue-cli
    
    如果没有安装的话,使用如下命令全局安装
    cnpm install -g vue-cli
    
    创建一个基于webpack的新项目,在这过程中, 会安装依赖
    vue init webpack 项目名
    
    启动
    cd vue-router-demo
    npm start
    

    常用的目录结构

    如果我们的项目是通过脚手架搭建的,这已经是一个比较完善的种子项目了

    |-- build : webpack 相关的配置文件夹(基本不需要修改)
    |-- config: webpack 相关的配置文件夹(基本不需要修改)
    |-- index.js: 指定的后台服务的端口号和静态资源文件夹
    |-- node_modules: 在上面安装的依赖,都存放在这个文件夹下
    |-- src : 源码文件夹,我们后续开发的组件和js分门别类的放在这里面
    |-- main.js: 应用入口 js
    |-- static: 静态资源文件夹
    |-- .babelrc: babel 的配置文件
    |-- .editorconfig: 通过编辑器的编码/格式进行一定的配置
    |-- .eslintignore: eslint 检查忽略的配置
    |-- .eslintrc.js: eslint 检查的配置
    |-- .gitignore: git 版本管制忽略的配置
    |-- index.html: 主页面文件
    |-- package.json: 他就相当于maven的pom.xml, 里面存放着相关的依赖信息和项目的版本信息
    |-- README.md: 应用描述说明的 readme 文件
    

    配置config/index.js

    可以在config/index.js中做一下的常用配置

    • 添加跨域的配置
    • 配置项目的主机名,端口号
    • 配置是否打开浏览器
    • 代码检查工具eslint

    在开发的时候我们主要还是关注src文件, 后来需要的路由,store,ajaxApi,以及其他组件全部在创建在这个文件夹下

    const path = require('path')
    module.exports = {
      dev: {
    
        // Paths
        assetsSubDirectory: 'static',
        assetsPublicPath: '/',
        proxyTable: {}, //添加跨域的配置
    
        // Various Dev Server settings
        host: 'localhost', // can be overwritten by process.env.HOST
        port: 9528, // 配置是否打开浏览器
        autoOpenBrowser: true,  //配置是否打开浏览器
        errorOverlay: true,
        notifyOnErrors: false,
        poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
    
        // Use Eslint Loader?
        // If true, your code will be linted during bundling and
        // linting errors and warnings will be shown in the console.
        useEslint: false,
        // If true, eslint errors and warnings will also be shown in the error overlay
        // in the browser.
        showEslintErrorsInOverlay: false,
    

    入口js文件 main.js的主要作用

    • 创建vue实例, 关联index.html中id为app的div代码块
    • 添加项目中的路由模块 router
    • 添加store模块---vuex

    一般做好这不配置之后main就不用再改动了

    import App from './App'
    import router from './router'
    import store from './store'
    
    Vue.use(ElementUI, { locale })
    
    new Vue({
      el: '#app',
      router,
      store,
      template: '<App/>',
      components: { App }
    })
    

    根组件App.vue

    其实每一个组件都可以完整的拥有下面三部分, 当然如果哪个组件中不需要添加css样式,可以把最后一个style或者script标签去掉

    <template>
      <div>
       <!-- 这里存放 -->
      </div>
    </template>
    
    <//script>
    export default {
      name: 'app'
    }
    <///script>
    
    <style>
    </style>
    
    

    组件间的相互调用

    比如根组件想使用hello.vue组件,怎么做呢?

    像下面这样,三步走

    • 第一步:引入组件
    • 第二步:将组件映射成target标签
    • 第三步使用标签
    <template>
    <div>
        <!--第三步使用标签-->
        <hello/>  
    <div/>
    <template/>
    
    <script>
     
    import hello form './XXX/hello.vue'
    
    export default{
        // 将组件映射成标签
        components:{
            hello
        }
    }
    
    <style>
    </style>
    

    第二步中引入标签时也可以去掉.vue后缀

    或者直接这样写,是从@/ 代表的是 src/

    import hello form '@/XXX/hello'
    

    打包与发布

    打包

    • 打包的命令:
    npm run build
    

    项目经过打包,产出是一个dist文件,里面分别是index.html 和 静态资源文件夹, 这也是前后端分离开发的特色,后端想控制view层,也难了,只有一张index.html

    发布方法1-静态服务器工具包

    命令:

    npm install -g serve  // 安装工具
    serve dist 
    

    发布方法2-使用tomcat服务器

    注意点,使用tomcat当服务器,要求文件夹的名字和项目的名字要一样,修改的步骤如下:

    • 修改/build/webpack_prod.conf.js文件
        output:{
            ...
            pathPath:'项目名称'
        }
    
    • 编译重新打包
    npm run build
    
    • 把打包得到的dist文件夹改名,改成项目名
    • 将改名完事后的文件拷贝到tomcat的webapps目录下,运行tomcat

    eslint的编码规范检查

    好的习惯就是使用它,规范自己的代码风格, 但是也得说一下怎么禁用eslint'

    • 方法一: 通过如果是webstorm编译器的话,点击file/settings/ , 搜索eslint,可以去掉enable
    • 方法二: 编辑.eslintignore文件,添加自己想被忽略的文件
    *.js
    *.vue
    一般我们就写这两部分,这一下子全忽略了
    

    因为eslint有个莫名其妙的要求,代码最后一行要求是空行,可以通过下面的方法三取消掉

    • 方法三: 编辑.eslintrc.js
    rules:{
        ...
        // 添加
        'indent':0
    }
    

    父子组件之间数据交互

    在差分组件的时候,本着多个组件共享的数据放在根组件的原则, 于是我们把共用的数据放在根组件,于此同时操作这些数据的方法也被我们定义在根组件,子组件想要使用这些数据,想要操作这些数组怎么办呢? 像下面那样,进行组件之间的数据传递

    • 在父组件中给子组件传递方法或数据

    使用:强制数据绑定的方法, ChildTarget是我们在components模块将子组件映射得来的子组件标签, name可以是vue中data的方法,也可以是属性

    <template>
       <ChildTarget  :name="name"/>
    </template>
    
    
    • 子组件取出父组件传递过来的值
    export default{
        props:['name','name2']
    }
    

    数据的交互@click

    最常用的就是使用@click="方法名", 或者@click="value = !value" 或者@click="value = true

    如果我们向上面那样, 把公共的数据放在父组件中, 那么事件的触发一定是发生在子组件中, 子组件一般通过@click给模板中的元素绑定上指定的动作,进而调用父组件的传递进来的方法,操作父组件传递进来的值

    此外,在所有的组件中,vue的data部分都向下面这样写,是规定

    data(){
        return{
            name:''
        }
    }
    
    • 常用的监视watch模块
    watch:{
        监视的data中的对象
        name:{
            deep:true, // 深度监视
            handler: function(value){ // value就是变化后的新的值
                // todo
            }
        }
    }
    
    • 缓存模块

    从缓存中把去出来的字符串转换成json串

    JSON.parse(window.localStorage.getItem('')||'默认值');
    

    把对象,存储进浏览器的缓存

    window.localStorage.setItem('自定义的key',JSON.stringfy(value))
    

    消息订阅,打破父子组件信息传递的约束

    像上面那样,如果不存在父子组件的关系,父组件不引入子组件,也就没办法把他映射成标签, 既然映射不成标签也就没法像上面那样,通过 : 冒号 强制进行数据的绑定达到传递值的效果,于是有了消息订阅

    组件之间的通信方式: 发布/订阅

    绑定监听: 订阅事件

    触发事件: 发布事件

    借助插件-pubsub.js

    安装命令:

    npm install --save pubsub-js
    

    场景: 我们给模板上的按钮绑定点击事件,一旦被点解他就发布事件

    • 在使用前需要导入PubSub对象
    import PubSub from 'pubsub-js'
    

    使用:消息的发布

    <button @click="search">Search</botton>
    
    export default{
        methods:{
            search(name){
                // search是方法名
                // name 是携带的参数,没参数就不用写
                Publish.publish('search',name)
            }
        }
    }
    
    

    消息的订阅:

    • 依然是第一步:引入PubSub对象
    • 编码实现:
    mounted: {
        PubSub.subscribe("search",(name)=>{
          // todo with name
    });
    

    异步请求

    安装插件axios

    npm install axios --save
    
    • 在使用之间同样是需要引入:
    import axios from 'axios'
    

    发送一个get请求

    axios.get(url)
         .then(res=>{ 
             // todo with res
         })
         .catch(error){
             // todo
         }
    
    

    路由:

    vue是如何做到使后端乖乖交出view层的控制权的?,难道是直接使用window.location.href = url吗?

    其实学过路由才知道, 使用的是vue-router,一个官方提供的路由框架,可以使用我通过组合组件来组成应用程序,仰仗它的路由插件vue-router,我们轻松控制页面的切换

    我们要做的就是将组件components映射到routers,然后告诉vue-router到哪里去渲染他们

    定义路由器

    安装插件

    npm install vue-router --save
    

    编码,其实大家都会把关于路由的编码单独放到一个叫router的文件夹中,而且,它的编码基本上是机械化的编码,分为如下几步

    • 引入Vue,VueRouter
    • 声明Vue.use(VueRouter)
    • 引入路由组件
    • 对外暴露路由器对象,并且把路由组件配置进路由器对象

    注意点 下面的配置部分, routes 不写乱写!!!

    import Vue from 'vue'
    import Router from 'vue-router'
    Vue.use(Router)
    
    import Home from './Home.vue'
    import About from './About.vue'
    import Me from './Me.vue'
    
    
    export default new VueRouter({
    // 添加路由
    routes:[
    {
       path:'/home',
       component:Home,
       meta:{
           // 添加自定义的字段,可以当成flag,也可以文本
       }
    },
    {
       path:'/about',
       component:About,
       meta:{
           // 添加自定义的字段,可以当成flag,也可以文本
       },
       childred:[ // 嵌套路由
            { 
                path:'/about',
                component:About,
                meta:{
                      // 添加自定义的字段,可以当成flag,也可以文本
                     }
            }
       ]
       }
    },
    {
        path:'', // 默认访问空的话,重定向到/home
        redirect:'/home'
    }
    ]
    })
    
    

    使用路由进行页面的跳转

    原来进行页面的跳转我们通常使用a标签,(一般把a标签设计成按钮,或者导航栏的样子,点击发送请求,进而跳转页面了), 而vue的路由其实和a标签差不多,我们使用vue的 router-link标签替换a标签

    <router-link to:'/about' class="可以让我看起来像按钮的css样式"> </router-link>
    <router-link to:'/home' class="可以让我看起来像按钮的css样式"> </router-link>
    
    <router-view ></router-view>
    

    这样用户点击 router-link,就会把相应的子组件移植到标签块中

    补充:

    属性类型含义
    to string | Location 表示目标路由的链接。当被点击后,内部会立刻把 to 的值传到 router.push(),所以这个值可以是一个字符串或者是描述目标位置的对象。
    replace boolean 设置 replace 属性的话,当点击时,会调用 router.replace() 而不是 router.push(),于是导航后不会留下 history 记录。
    append boolean 设置 append 属性后,则在当前(相对)路径前添加基路径。例如,我们从 /a 导航到一个相对路径 b,如果没有配置 append,则路径为 /b,如果配了,则为 /a/b

    回退到上一个路由

    我们可以在按钮上添加下面的动作,是路由回退一级

    <button @click="$router.back()"></button>
    

    缓存路由组件

    使用如下标签包裹我们的router-view,这样当我们再回退到上一个路由时,用户加进去的状态依然存在

    <keep-alive>
     <router-view ></router-view>
    </keep-alive>
    

    $router与$route

    $router是路由器对象,说白了就是用它去跳转页面,美其名曰:编程式路由导航

    $route是路由对象,说白了就是某一个路由对象,既然是某一个,就不能进行页面的跳转,相反是可以获取出当前路由组件的属性,它的结构图如下:

    $route的组成图

    $route的组成图

    向路由组件传递值 一

    需求: 我们想发送这样的请求 http:localhost:8080/home/1/羊肉串,在路径上携带着参数1

    路由怎么接收参数呢?--> 使用:占位

    
    export default new VueRouter({
    // 添加路由
    routes:[
    {
       path:'/home/:id/:type', // 如果想在路径上传递值进来,就使用:占位
       component:Home,
       meta:{
           // 添加自定义的字段,可以当成flag,也可以文本
           flag:true
       }
    },
    

    当我们添加了/:之后,它的组成结构就变成了这个样子

    像下面这样传递值进去,发起请求

    <router-link to:`/home/${id}/${type}` class="可以让我看起来像按钮的css样式"> </router-link>
    

    同时,我们也可以向下面这样使用$route. 在对应不同的路由组件中,把里面的属性取出来, 注意啊,这样取值,前提是我们前面使用 /:id占位,并且也整整传递值进去了

     <h1>id= {{$route.params.id}}</h1>
    

    向路由组件传递值 二

    使用<router-view >标签传递值

     <router-view msg='abc'></router-view>
    

    在路由组件中通过props取出值,然后可以直接使用

    export default{
        props:[
          msg:String
        ]
    }
    

    编程式的路由导航

    编程式的路由导航说白了就是,不用router-link标签转而使用代码路由的跳转呗, 举个例子,我们使用手机qq,最下面有几个导航栏,点击不同的按钮转换到不同的页面去,如果用编程式的路由导航就很好做

    • 第一步就是将需要的路由组件配置进路由器
    • 给按钮绑定上点击事件
    • 点击事件触发我们所谓的编程式路由导航

    vue提供了两种编程式的路由导航实现

    • 第一种:
      这种常用的一种
    this.$router.replace(`/home/${id}`)
    
    • 第二种:
      这种具有栈的特性,也就是说,用户点击返回键,会返回到上一级路由
    this.$router.push(`/home/${id}`)
    

    slot标签

    它是个和 rout-view 和像的标签,都是用来占位的,它可以接受父组件传递给他的一段html

    举个例子: 有四张路由组件,他们共用一个叫header的组件当作自己的头部, 但是他们需要传递进去属于自己的不同的值, 下面使用slot实现

    在 MyHeader.vue中

    <!--首页头部-->
      <header class="header">
    
        <!-- 这里使用插槽占位-->
        <slot name="left"></slot>
    
        <span">
                <span >我是header</span>
        </span>
    
        <!-- 这里使用插槽占位-->
        <slot name="right"></slot>
    
      </header>
    

    在父组件中使用:注意啊,下面的组件想往MyHeader.vue中的插槽中,传递进去代码片段,前提是他要把MyHeader.vue映射成标签,成为他的父组件

    
    <div>
    <MyHeader>
        <span class="header_search" slot="left">
            <i class="iconfont icon-sousuo"></i>  /*在插槽的左边植入一个icon*/
        </span>
    
        <!-- 给右边的插槽传递模板 -->
        <span class="header_login" slot="right">
            <a href="" >登录|注册</a>   /* 在插槽的右边植入一个链接 */
       </span>
    </MyHeader>
    </div>
    

    Vuex

    官方的解释: vuex是专门为Vue.js应用程序开发的状态管理模式,它采用集中式的储存应用中所有组件的状态,并以相应的规则保证状态以一种可预期的方式发生变化

    说白了: 当我们划分组件之后,每一个组件都有自己的属性,但是不同的组件的数据是不能共享的,于是我们可以使用从父组件往子组件传播数据的模式, 而且完全不相干的两个组件可能需要对方data里的数据,又怎么传递呢? vuex 就应对 迎战这个问题

    vuex就是一个单独存储的区域,用于存放公共的属性

    安装命令:

    npm install --save vuex
    

    创建vuex的四个组件对象,如上图

    vuex的组件对象一: state.js

    状态对象,存放一系列的状态,其实就是把子组件中data里面的字段赋复制过来

    state.js文件
    export default {
      arr: []
    }
    

    vuex的组件对象二: actions.js

    超级重要的组件, 在这个组件中我们可以提交异步事件, 最常用的就是用户直接通过$store.dispatch('action中的方法名'), action会触发 mutation的调用, 间接更新状态

    action.js
    // add方法的方法第一个参数是不变的{commit}, 其实他就是 $store 对象
    // 通过这个commit方法,  把数据包装成对象传递给 mutations
    // 第二个参数的可选的,可以是调用者传递进来的参数,也可以是state对象
    export default {
      add({commit},item){
        // 提交mutation请求
         commit(ADD_TODO,{item}); // 把数据包装成对象传递给 mutations
      },
    

    vuex的组件对象三: mutations.js

    真正的去执行action传进来,更新state中数据的操作

    mutations.js
    export default {
    
    add(state,{item}){ 
       state.arr.unshift(item);
    } 
    }
    

    vuex的组件对象四: getters.js

    包含了所有的基于state的 get计算属性, 这一点也很好用,他是一种双向的数据绑定

    getters.js 
    export default {
      // 计算属性
      totalCount (state) {
        return state.arr.length
      },
    }
    

    把四个组件拼装成store对象

    1. 在src下创建store文件夹,在改文件夹下创建store.js
    2. 导入Vue , Vuex
    3. 声明Vue使用Vuex
    4. 将上面的四个组件注册进来store.js
      state: 状态对象,存放的是需要共享数据的字段
      actions: 包含多个事件回调函数的对象
      mutations: 包含真正去更新state中字段的函数
      getter: 计算属性的方法
    5. 对外暴露匿名store对象
    6. 将store配置进main.js vue的入口js中

    编码实现: store.js

    store.js
    
    import Vue from 'vue'
    import Vuex from  'vuex'
    
    import state from './state'
    import actions from './actions'
    import mutations from  './mutations'
    import getters from './getter2'
    
    Vue.use(Vuex)
    
    // 对外暴露你匿名 store对象
    export  default new Vuex.Store({
      state,
      actions,
      mutations,
      getters
    })
    
    把store对象,注册进main.js
    

    更全面的数据处理流程图

    获取state中的值

    做好了上面的配置,在任何地方都能用下面的方式获取出store里面的数据

    this.$store.state.属性
    

    使用vuex,改变状态值

    添加上前缀,再使用

    this.$store.commit('matations中的方法名','可选的参数')
    
    // 注意哦, action中是可以提交异步函数的
    this.$store.dispach('action中的方法名','可选的参数')
    

    也可以像下面这样,先进行映射就可以不再添加任何前缀,直接使用他们

    // 从vuex中引入映射
    import {mapState,mapGetters,mapActions} from 'vuex'
    
    export default {
        computed:{
            ...mapState(['state中的属性值'])
            ...mapGetters(['getters.js中的方法名'])
        },
        methods:{
            ...mapActions(['actions.js中的方法名'])
        }
    }
    
  • 相关阅读:
    我的WCF之旅(1):创建一个简单的WCF程序
    网页设计中颜色的搭配
    CSS HACK:全面兼容IE6/IE7/IE8/FF的CSS HACK
    UVa 1326 Jurassic Remains
    UVa 10340 All in All
    UVa 673 Parentheses Balance
    UVa 442 Matrix Chain Multiplication
    UVa 10970 Big Chocolate
    UVa 679 Dropping Balls
    UVa 133 The Dole Queue
  • 原文地址:https://www.cnblogs.com/Javastudy-note/p/13813781.html
Copyright © 2011-2022 走看看