优秀的编程知识分享平台

网站首页 > 技术文章 正文

vue开启web项目之旅-3(vue打开)

nanyue 2024-10-29 14:50:23 技术文章 4 ℃

安装axios

后面我们需要在前端来获取后端的数据,意味着要发送请求,我们使用axios模块来进行请求的发送,它的特点和ajax一样:异步请求。


然后在main.js文件中引入

import Vue from 'vue'
import App from './App'
import axios from 'axios'

Vue.prototype.$axios = axios // 原型链形式挂载到vue中,后面通过组件对象可以直接调动axios的功能
// Vue.use(ConfigProvider)
Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

我们本次前端使用的插件是Ant Design,能够帮我们快速优雅的完成前端页面效果,下面介绍一下

ant-design插件

介绍

Ant Design 是一个致力于提升『用户』和『设计者』使用体验的中台设计语言。它模糊了产品经理、交互设计师、视觉设计师、前端工程师、开发工程师等角色边界,将进行 UE 设计和 UI 设计人员统称为『设计者』,利用统一的规范进行设计赋能,全面提高中台产品体验和研发效率,是蚂蚁金服出品的开源框架。

Ant Design 官方介绍: "在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,给设计师和工程师带来很多困扰和重复建设,大大降低了产品的研发效率。"

蚂蚁金服体验技术部经过大量的项目实践和总结,沉淀出设计语言 Ant Design,这可不单纯只是设计原则、控件规范和视觉尺寸,还配套有前端代码实现方案。也就是说采用Ant Design后,UI设计和前端界面研发可同步完成,效率大大提升。目前有阿里、美团、滴滴、简书采用。Ant Design有Web版和Moblie版。

如果前端这些插件都是我们通过js或者jquery手撸的话,工作量太重不说,效率还低。

Ant Design 则封装了一系列高质量的 React 组件,十分适用于在企业级的应用中,框架提供的 api 十分详尽,上手和使用相对简单,值得一提的是, Ant Design 使用 ES6 进行编写,因此使用过程中对 ES6 也是一次学习的机会。

我们现在学习的是vue框架和ant-desigin的兼容,那么已经有高手开源出了一套ant-design的vue实现,下面我们就来学习使用。

ant-desigin特点

  • 专为Web应用程序设计的企业级UI。
  • 开箱即用的一组高质量React组件。
  • 用具有可预测的静态类型的TypeScript编写。
  • 整套设计资源和开发工具。
  • 支持数十种语言的国际化。
  • 强大的主题自定义细节。


常用网址


安装上手


在main.js文件中引入

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'

// import Antd from 'ant-design-vue';
import Antd from 'ant-design-vue';
Vue.use(Antd);
import 'ant-design-vue/dist/antd.css';

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

我们现在已经把组件成功运行起来了

但是在开发过程中还有很多问题,例如上面的例子实际上加载了全部的 antd 组件的样式(对前端性能是个隐患)。

此时我们需要对 vue-cli 的默认配置进行自定义。

npm install babel-plugin-import --dev 安装高级配置工具 使用哪些就自动引入哪些,不会将ant的组件全部引入

修改项目根目录下的.babelrc文件,配置 babel-plugin-import

{
    "presets": [
      ["env", {
        "modules": false,
        "targets": {
          "browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
        }
      }],
      "stage-2"
    ],
-   "plugins": ["transform-vue-jsx", "transform-runtime"]
+   "plugins": [
+     "transform-vue-jsx",
+     "transform-runtime",
+     ["import", { "libraryName": "ant-design-vue", "libraryDirectory": "es", "style": "css" }]
+   ]
  }

减号表示去掉的,加号表示需要添加上的

调整一下配置项


将.babelrc文件的
	{ libraryName: "ant-design-vue", libraryDirectory: "es", style: "css"}
改为:
	{ libraryName: "Antd", libraryDirectory: "es", style: "css"}  
	//提醒:这里style:"css"可改为style:true且不会报错,这样改后会加载包里的less文件而非css文件。不改也没影响

调整完配置之后,别忘了主动重启一下项目,vue-cli自动重启会导致加载配置失败

下面测试一下效果,我们在ShowCenter.vue组件中引入一个ant-design的button按钮,看看怎么样


<template>
    <div class="show_center">
      <h1>展示中心页面</h1>
      <a-button type="danger">
        Danger
      </a-button>
    </div>
</template>

<script>
    export default {
        name: "ShowCenter"
    }
</script>

<style scoped>

</style>

好,效果有了

中文支持

在使用某些插件(比如时间日期选择框等)的时候,需要我们来做中文支持,玩法如下


<template>
	<a-config-provider :locale="locale">
    <div>
      使用的ant-design插件,尤其是时间选择插件
    </div>
  </a-config-provider>
</template>

<script>
  import zhCN from 'ant-design-vue/lib/locale-provider/zh_CN';

  export default {
    name: 'Workbench',
    data() {
      return {
        locale: zhCN,

      };
    },


  };
</script>

echarts图表插件


下载:


为了方便后面组件的使用,我们在main.js中引入一下:

// import echarts from 'echarts'
let echarts = require('echarts')
Vue.prototype.$echarts = echarts

在ShowCenter.vue组件中简单使用

<template>
    <div class="show_center">
      <h1>展示中心页面</h1>
      <a-button type="danger">
        Danger
      </a-button>

      <div ref="chart" style="height: 200px;width: 200px;">

      </div>

    </div>
</template>

<script>
    export default {
        name: "ShowCenter",
        data(){
          return {

          }
        },
				
        // 注意,我们需要再mounted生命周期钩子函数中完成,因为vue中dom的加载是异步的,如果dom还没有加载完,就执行图表的初始化,不会成功的,或者在延迟回调方法中来完成图表初始化
      	// create(){ this.$nextTick(() => {初始化图表}) } ,
        mounted() {
          // 基于准备好的dom,初始化echarts实例
            let myChart = this.$echarts.init(this.$refs.chart);
            // 绘制图表
            myChart.setOption({
                title: {
                    text: 'ECharts 入门示例'
                },
                tooltip: {},
                xAxis: {
                    data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
                },
                yAxis: {},
                series: [{
                    name: '销量',
                    type: 'bar',
                    data: [5, 20, 36, 10, 10, 20]
                }]
            });
        }

    }
</script>

<style scoped>

</style>

好,到此前端项目初始化完成。

组件初始化

App.vue

<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>

<script>
    export default {
        name: "App"
    }
</script>

<style scoped>

</style>

Login登录组件初始化


<template>
    <div class="login">
      <h1>登录页面</h1>
    </div>
</template>

<script>
    export default {
        name: "Login"
    }
</script>

<style scoped>

</style>

Login页面效果


<template>
	<div class="login box">
		<img src="../../static/login/images/login.jpg" alt="">
		<div class="login">
			<div class="login-title">
				<img src="../../static/login/images/login3.jpeg" alt="">
				<p>Hippo!</p>
			</div>
			<div class="login_box">
				<div class="title">
					<span @click="login_type=0">登录</span>

				</div>
				<div class="inp" v-if="login_type==0">
					<input v-model = "username" type="text" placeholder="用户名" class="user">
					<input v-model = "password" type="password" name="" class="pwd" placeholder="密码">

					<div class="rember">
						<p>
							<input type="checkbox" class="no" name="a"/>
							<span>记住密码</span>
						</p>

					</div>
					<button class="login_btn" @click="login">登录</button>

				</div>

			</div>
		</div>
	</div>
</template>

<script>
export default {
  name: 'Login',
  data(){
    return {
        login_type: 0,
        username:"",
        password:"",
    }
  },

  methods:{
    login(){
      this.$axios.post(`${this.$settings.HOST}/users/login/`,{

      }).then((res)=>{

        // locatStorage或者sessionStorage中存储token
        // 跳转到首页
        // 首页加载时验证token有效性

      })
    },

  },

};
</script>

<style scoped>
.box{
	width: 100%;
  height: 100%;
	position: relative;
  overflow: hidden;
}
.box img{
	width: 100%;
  min-height: 100%;
}
.box .login {
	position: absolute;
	width: 500px;
	height: 400px;
	top: 0;
	left: 0;
  margin: auto;
  right: 0;
  bottom: 0;
  top: -338px;
}
.login .login-title{
     width: 100%;
    text-align: center;
}
.login-title img{
    width: 190px;
    height: auto;
}
.login-title p{
    font-family: PingFangSC-Regular;
    font-size: 18px;
    color: #fff;
    letter-spacing: .29px;
    padding-top: 10px;
    padding-bottom: 50px;
}
.login_box{
    width: 400px;
    height: auto;
    background: rgba(255,255,255,0.3);
    box-shadow: 0 2px 4px 0 rgba(0,0,0,.5);
    border-radius: 4px;
    margin: 0 auto;
    padding-bottom: 40px;
}
.login_box .title{
	font-size: 20px;
	color: #9b9b9b;
	letter-spacing: .32px;
	border-bottom: 1px solid #e6e6e6;
	 display: flex;
    	justify-content: space-around;
    	padding: 50px 60px 0 60px;
    	margin-bottom: 20px;
    	cursor: pointer;
}
.login_box .title span:nth-of-type(1){
	color: #4a4a4a;
    	border-bottom: 2px solid #396fcc;
}

.inp{
	width: 350px;
	margin: 0 auto;
}
.inp input{
    border: 0;
    outline: 0;
    width: 100%;
    height: 45px;
    border-radius: 4px;
    border: 1px solid #d9d9d9;
    text-indent: 20px;
    font-size: 14px;
    background: #fff !important;
}
.inp input.user{
    margin-bottom: 16px;
}
.inp .rember{
     display: flex;
    justify-content: space-between;
    align-items: center;
    position: relative;
    margin-top: 10px;
}
.inp .rember p:first-of-type{
    font-size: 12px;
    color: #4a4a4a;
    letter-spacing: .19px;
    margin-left: 22px;
    display: -ms-flexbox;
    display: flex;
    -ms-flex-align: center;
    align-items: center;
    /*position: relative;*/
}
.inp .rember p:nth-of-type(2){
    font-size: 14px;
    color: #9b9b9b;
    letter-spacing: .19px;
    cursor: pointer;
}

.inp .rember input{
    outline: 0;
    width: 30px;
    height: 45px;
    border-radius: 4px;
    border: 1px solid #d9d9d9;
    text-indent: 20px;
    font-size: 14px;
    background: #fff !important;
}

.inp .rember p span{
    display: inline-block;
  font-size: 12px;
  width: 100px;
  /*position: absolute;*/
/*left: 20px;*/

}
#geetest{
	margin-top: 20px;
}
.login_btn{
     width: 100%;
    height: 45px;
    background: #396fcc;
    border-radius: 5px;
    font-size: 16px;
    color: #fff;
    letter-spacing: .26px;
    margin-top: 30px;
}
.inp .go_login{
    text-align: center;
    font-size: 14px;
    color: #9b9b9b;
    letter-spacing: .26px;
    padding-top: 20px;
}
.inp .go_login span{
    color: #84cc39;
    cursor: pointer;
}
</style>

由于除了登录页面之外我们后面所有的组件都具备顶部导航栏和左侧菜单栏的效果,所以我直接将共有效果放到了一个Base.vue组件中。

里面通过 ant design vue中的


Base组件初始化

布局和导航菜单搭建App页面效果,简单如下

<template>
  <div id="app">


    <a-layout id="components-layout-demo-custom-trigger">
      <a-layout-sider v-model="collapsed" :trigger="null" collapsible>
        <div class="logo"/>
        <a-menu
          :default-selected-keys="['1']"
          :default-open-keys="['sub1']"
          mode="inline"
          theme="dark"
          :inline-collapsed="collapsed"
          @select="selectedHandler"
        >
          <a-menu-item key="1">
            <a-icon type="pie-chart"/>
            <span>Option 1</span>
          </a-menu-item>
          <a-menu-item key="2">
            <a-icon type="desktop"/>
            <span>Option 2</span>
          </a-menu-item>
          <a-menu-item key="3">
            <a-icon type="inbox"/>
            <span>Option 3</span>
          </a-menu-item>
          <a-sub-menu key="sub1">
            <span slot="title"><a-icon type="mail"/><span>Navigation One</span></span>
            <a-menu-item key="5">
              Option 5
            </a-menu-item>
            <a-menu-item key="6">
              Option 6
            </a-menu-item>
            <a-menu-item key="7">
              Option 7
            </a-menu-item>
            <a-menu-item key="8">
              Option 8
            </a-menu-item>
          </a-sub-menu>
          <a-sub-menu key="sub2">
            <span slot="title"><a-icon type="appstore"/><span>Navigation Two</span></span>
            <a-menu-item key="9">
              Option 9
            </a-menu-item>
            <a-menu-item key="10">
              Option 10
            </a-menu-item>
            <a-sub-menu key="sub3" title="Submenu">
              <a-menu-item key="11">
                Option 11
              </a-menu-item>
              <a-menu-item key="12">
                Option 12
              </a-menu-item>
            </a-sub-menu>
          </a-sub-menu>
        </a-menu>
      </a-layout-sider>
      <a-layout>
        <a-layout-header style="background: #fff; padding: 0">
          <a-icon
            class="trigger"
            :type="collapsed ? 'menu-unfold' : 'menu-fold'"
            @click="() => (collapsed = !collapsed)"
          />
        </a-layout-header>
<a-layout-content
          :style="{ margin: '24px 16px', padding: '24px', background: '#fff', minHeight: '280px' }"
        >
        <router-view></router-view>

  </a-layout-content>
      </a-layout>
    </a-layout>
  </div>
</template>
<script>
  export default {
    name:'App',
    data() {
      return {
        collapsed: false,
        
    },
    methods: {
      toggleCollapsed() {
        this.collapsed = !this.collapsed;
      },
      selectedHandler(item, key, selectedKeys){
        console.log('>>>>>',item, key, selectedKeys);
      }

    },
  };
</script>
<style scoped>
  #components-layout-demo-custom-trigger .trigger {
    font-size: 18px;
    line-height: 64px;
    padding: 0 24px;
    cursor: pointer;
    transition: color 0.3s;
  }

  #components-layout-demo-custom-trigger .trigger:hover {
    color: #1890ff;
  }

  #components-layout-demo-custom-trigger .logo {
    height: 32px;
    background: rgba(255, 255, 255, 0.2);
    margin: 16px;
  }


</style>

Base组件修改

<template>
  <div id="app">


    <a-layout id="components-layout-demo-custom-trigger">
      <a-layout-sider v-model="collapsed" :trigger="null" collapsible style="min-height: 700px;">
        <div class="logo" style="text-align: center;font-size: 20px;color:#fff;">
          Hippo
        </div>
        <a-menu
          :default-selected-keys="['1']"
          :default-open-keys="['sub1']"
          mode="inline"
          theme="dark"
          :inline-collapsed="collapsed"
          @select="selectedHandler"
        >
          <template v-for="(menu,index) in menu_list">

            <a-menu-item v-if="menu.children.length===0" :key="menu.id">
              <!--            <a-icon type="mail" />-->
              <router-link :to="menu.menu_url">
                <a-icon type="mail"/>
                {{menu.title}}
              </router-link>
              <!--            {{menu.title}}-->
            </a-menu-item>
            <a-sub-menu v-else :key="menu.id">
              <span slot="title">
                <a-icon :type="menu.icon"/>
                <span>{{menu.title}}</span>
              </span>


              <a-menu-item v-for="(child_menu,child_index) in menu.children" :key="child_menu.id">
                <router-link :to="child_menu.menu_url">{{child_menu.title}}</router-link>
                <!--              {{child_menu.title}}-->
              </a-menu-item>

            </a-sub-menu>

          </template>

        </a-menu>
      </a-layout-sider>
      <a-layout>
        <a-layout-header style="background: #fff; padding: 0">
          <a-icon
            class="trigger"
            :type="collapsed ? 'menu-unfold' : 'menu-fold'"
            @click="() => (collapsed = !collapsed)"
          />
        </a-layout-header>
        <a-layout-content
          :style="{ margin: '24px 16px', padding: '24px', background: '#fff', minHeight: '280px' }"
        >

          <router-view></router-view>
          <a-layout-footer style="text-align: center">Footer</a-layout-footer>

        </a-layout-content>
      </a-layout>
    </a-layout>
  </div>
</template>
<script>
  export default {
    name: 'App',
    data() {
      return {
        collapsed: false,
        menu_list: [
          {id: 1,icon:'mail', title: '展示中心', tube: '', 'menu_url': '/hippo/workbench', children: []},
          {
            id: 2,icon:'mail', title: '资产管理', 'menu_url': '/hippo/host', children: []
          },
          {
            id: 3,icon:'bold', title: '批量任务', tube: '', 'menu_url': '/hippo/workbench', children: [
              {id: 10, icon:'mail',title: '执行任务', 'menu_url': '/hippo/multi_exec'},
              {id: 11, icon:'mail', title: '命令管理', 'menu_url': '/hippo/template_manage'},
            ]
          },
          {

            id: 4,icon:'highlight', title: '代码发布', tube: '', 'menu_url': '/hippo/workbench', children: [
              {id: 12,  title: '应用管理', 'menu_url': '/hippo/release'},
              {id: 13,  title: '发布申请', 'menu_url': '/hippo/release'},
            ]
          },
          {id: 5,icon:'mail', title: '定时计划', tube: '', 'menu_url': '/hippo/workbench', children: []},
          {
            id: 6,icon:'mail', title: '配置管理', tube: '', 'menu_url': '/hippo/workbench', children: [
              {id: 14,  title: '环境管理', 'menu_url': '/hippo/environment'},
              {id: 15,  title: '服务配置', 'menu_url': '/hippo/workbench'},
              {id: 16,  title: '应用配置', 'menu_url': '/hippo/workbench'},
            ]
          },
          {id: 7,icon:'mail', title: '监控', tube: '', 'menu_url': '/hippo/workbench', children: []},
          {
            id: 8,icon:'mail', title: '报警', tube: '', 'menu_url': '/hippo/workbench', children: [
              {id: 17,  title: '报警历史', 'menu_url': '/hippo/workbench'},
              {id: 18,  title: '报警联系人', 'menu_url': '/hippo/workbench'},
              {id: 19,  title: '报警联系组', 'menu_url': '/hippo/workbench'},
            ]
          },
          {
            id: 9,icon:'mail', title: '用户管理', tube: '', 'menu_url': '/hippo/workbench', children: [
              {id: 20,  title: '账户管理', tube: '', 'menu_url': '/hippo/workbench'},
              {id: 21,  title: '角色管理', tube: '', 'menu_url': '/hippo/workbench'},
              {id: 22,  title: '系统设置', tube: '', 'menu_url': '/hippo/workbench'},
            ]
          },
        ]
      };
    },
    methods: {
      toggleCollapsed() {
        this.collapsed = !this.collapsed;
      },
      selectedHandler(item, key, selectedKeys) {
        console.log('>>>>>', item, key, selectedKeys);
      }

    },
  };
</script>
<style scoped>
  #components-layout-demo-custom-trigger .trigger {
    font-size: 18px;
    line-height: 64px;
    padding: 0 24px;
    cursor: pointer;
    transition: color 0.3s;
  }

  #components-layout-demo-custom-trigger .trigger:hover {
    color: #1890ff;
  }

  #components-layout-demo-custom-trigger .logo {
    height: 32px;
    background: rgba(255, 255, 255, 0.2);
    margin: 16px;
  }


</style>

如果我们自己有必要写一些初始化的全局css样式,可以用如下方式来搞:

App.vue,全局css初始化代码

reset.css

body{
    margin: 0;
    padding: 0;
  }

也可以把App.vue的style标签的css代码放到static外部目录下引用过来

main.js

import "../static/css/reset.css";

接着我们创建两个测试路由的组件

ShowCenter.vue

<template>
    <div class="show_center">
      <h1>展示中心页面</h1>
      <a-button type="danger">
        Danger
      </a-button>

      <div ref="chart" style="height: 200px;width: 200px;">

      </div>

    </div>
</template>

<script>
    export default {
        name: "ShowCenter",
        data(){
          return {

          }
        },

        mounted() {
          // 基于准备好的dom,初始化echarts实例
            let myChart = this.$echarts.init(this.$refs.chart);
            // 绘制图表
            myChart.setOption({
                title: {
                    text: 'ECharts 入门示例'
                },
                tooltip: {},
                xAxis: {
                    data: ['衬衫', '羊毛衫', '雪纺衫', '裤子', '高跟鞋', '袜子']
                },
                yAxis: {},
                series: [{
                    name: '销量',
                    type: 'bar',
                    data: [5, 20, 36, 10, 10, 20]
                }]
            });
        }


    }
</script>

<style scoped>

</style>

Hosts.vue

<template>
    <div class="host">
      <h1>host页面</h1>
    </div>
</template>

<script>
    export default {
        name: "Host"
    }
</script>

<style scoped>

</style>

路由配置

由于我们使用了组件嵌套,所以我们要通过路由嵌套来进行控制

Router/index.js

import Vue from 'vue'
import Router from 'vue-router'
import ShowCenter from '@/components/ShowCenter'
import Login from '@/components/Login'
import Base from '@/components/Base'
import Host from '@/components/Host'

Vue.use(Router)

export default new Router({
  mode:'history',
  routes: [
    {
      path: '/',
      name: 'Login',
      component: Login
    },
    {
      path: '/hippo',
      // name: 'hippo',
      component: Base,
      
      // 路由嵌套
      children:[
        {
          // 访问 /hippo/hosts/
          path: '',  // 访问/hippo路径时显示的组件内容
          component: ShowCenter
        },
        {
          path: 'showcenter/',
          component: ShowCenter
        },
        {
          path: 'hosts/',
          component: Host
        },
      ]

    },


  ],

})


最终效果图:



喜欢的请关注转发评论 谢谢[爱慕][舔屏]

Tags:

最近发表
标签列表