Vue学习笔记

  7 分钟   20963 字    |    

Vue项目实战

小试身手

使用 webpack 搭建 vue 工程实例,结合 ElementUI 组件库快速部署项目

创建

  1. 安装 webpack:npm install webpack -g,npm install webpack-cli -g
  2. 创建项目:vue init webpack hello-vue
  3. 安装路由:npm install vue-router --save-dev
  4. 安装 element-ui:npm i element-ui -S
  5. 安装 node:npm install
  6. 安装 sass 加载器:npm install sass-loader@7.3.1 --save-dev npm i -D sass
  7. 启动测试:npm run dev

目录

  • assets:用于存放资源文件
  • components:用于存放Vue功能组件
  • views:用于存放Vue视图组件
  • router:用于存放vue-router配置
  • main.js:入口文件,主要作用是初始化 vue 实例,并引入所需要的插件
  • App.vue:主组件,所有页面都是在 App.vue 下进行切换

views

  1. 创建首页视图,在 views 目录下新建 Main.vue 视图组件
<template>
	<div>首页</div>
</template>
<script>
	export default {
			name:"Main"
	}
</script>
<style scoped>
</style>
  1. 创建登录页视图在views目录下创建名为Login.vue的视图组件(其中el-*的元素为ElementUI组件)
<template>
  <div>
    <el-form ref="loginForm" :model="form" :rules="rules" label-width="80px" class="login-box">
      <h3 class="login-title">欢迎登录</h3>
      <el-form-item label="账号" prop="username">
        <el-input type="text" placeholder="请输入账号" v-model="form.username"/>
      </el-form-item>
      <el-form-item label="密码" prop="password">
        <el-input type="password" placeholder="请输入密码" v-model="form.password"/>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" v-on:click="onsubmit('loginForm')">登录</el-button>
      </el-form-item>
    </el-form>

    <el-dialog title="温馨提示" :visible.sync="dialogVisiable" width="30%" :before-close="handleClose">
      <span>请输入账号和密码</span>
      <span slot="footer" class="dialog-footer">
          <el-button type="primary" @click="dialogVisible = false">确定</el-button>
        </span>
    </el-dialog>
  </div>
</template>

<script>
    export default {
        name: "Login",
      data(){
          return{
            form:{
              username:'',
              password:''
            },
            //表单验证,需要在 el-form-item 元素中增加prop属性
            rules:{
              username:[
                {required:true,message:"账号不可为空",trigger:"blur"}
              ],
              password:[
                {required:true,message:"密码不可为空",tigger:"blur"}
              ]
            },

            //对话框显示和隐藏
            dialogVisible:false
          }
      },
      methods:{
          onSubmit(formName){
            //为表单绑定验证功能
            this.$refs[formName].validate((valid)=>{
              if(valid){
                //使用vue-router路由到指定界面,该方式称为编程式导航
                this.$router.push('/main');
              }else{
                this.dialogVisible=true;
                return false;
              }
            });
          }
      }
    }
</script>

<style lang="scss" scoped>
  .login-box{
    border:1px solid #DCDFE6;
    width: 350px;
    margin:180px auto;
    padding: 35px 35px 15px 35px;
    border-radius: 5px;
    -webkit-border-radius: 5px;
    -moz-border-radius: 5px;
    box-shadow: 0 0 25px #909399;
  }
  .login-title{
    text-align:center;
    margin: 0 auto 40px auto;
    color: #303133;
  }
</style>

route

router目录下存在名为index.js的vue-router路由配置文件

//导入vue
import Vue from 'vue';
import VueRouter from 'vue-router';
//导入组件
import Main from "../views/Main";
import Login from "../views/Login";
//使用
Vue.use(VueRouter);
//导出
export default new VueRouter({
  routes: [
    {
      //登录页
      path: '/main',
      component: Main
    },
    //首页
    {
      path: '/login',
      component: Login
    },
  ]

})

入口

  1. App.vue
<template>
  <div id="app">
    <router-view></router-view>
  </div>
</template>

<script>


export default {
  name: 'App',

}
</script>

<style>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}
</style>
  1. 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 ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'

Vue.use(router)
Vue.use(ElementUI)

/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  render:h=>h(App)
})

测试:在浏览器打开 http://localhost:8080/#/login

(如果出现错误: 可能是因为sass-loader的版本过高导致的编译错误,当前最高版本是8.0.2,需要退回到7.3.1 ;在package.json文件里面的 "sass-loader"的版本更换成7.3.1,然后重新cnpm install即可)

进阶

路由嵌套

写两个vue 组件 List 和 Profile,路径分别为/views/user/List/views/user/Profile

route.js

...
//导入子模块
import UserList from "../views/user/List";
import UserProfile from "../views/user/Profile";
...
//嵌套路由children
routes: [
    {
      //登录页
      path: '/main',
      component: Main,
      //  写入子模块
      children: [
        {
          path: '/user/profile',
          component: UserProfile,
        }, {
          path: '/user/list',
          component: UserList,
        },
      ]
    },

main.vue

...
<el-menu-item index="1-1">
<!--插入的地方-->
	<router-link to="/user/profile">个人信息</router-link>
</el-menu-item>
<el-menu-item index="1-2">
<!--插入的地方-->
	<router-link to="/user/list">用户列表</router-link>
</el-menu-item>
...
<el-main>
<!--在这里展示视图-->
	<router-view />
</el-main>

传参

  1. 路由增加 props: true 属性,参数为 id

index.js

{
	path: '/user/profile/:id', 
	name:'UserProfile', 
	component: UserProfile, 
	props: true
}
  1. 传递参数,绑定 link

main.vue

<!--name是组件的名字 params是传的参数 如果要传参数的话就需要用v:bind:来绑定-->
<router-link :to="{name:'UserProfile',params:{id:1}}">个人信息</router-link>
  1. 接收参数,增加 prop 属性

Profile.vue

<template>
  <div>
    个人信息
    {{ id }}
  </div>
</template>
<script>
    export default {
      props: ['id'],
      name: "UserProfile"
    }
</script>
<style scoped>
</style>

重定向

index.js

export default new Router({
  mode: 'history',# 路径去除#号
{
  path: '/goHome',
  redirect: '/main'
})

说明:这里定义了两个路径,一个是 /main ,一个是 /goHome,其中 /goHome 重定向到了 /main 路径,由此可以看出重定向不需要定义组件

404

NotFound.vue

<template>
    <div>
      <h1>404,你的页面走丢了</h1>
    </div>
</template>
<script>
    export default {
        name: "NotFound"
    }
</script>
<style scoped>
</style>

index.js

import NotFound from '../views/NotFound'
//写了写组件后一定要记得在 index.jx 中导入
{
   path: '*',
   component: NotFound
}

钩子函数

在 Profile.vue中

  export default {
    name: "UserProfile",
    //在进入路由前执行
    beforeRouteEnter: (to, from, next) => {
      console.log("准备进入个人信息页");
      next();
    },
    //在进入路由后执行
    beforeRouteLeave: (to, from, next) => {
      console.log("准备离开个人信息页");
      next();
    }
  }

参数说明:
to:路由将要跳转的路径信息
from:路径跳转前的路径信息
next:路由的控制参数
next() 跳入下一个页面
next(’/path’) 改变路由的跳转方向,使其跳到另一个路由
next(false) 返回原来的页面
next((vm)=>{}) 仅在 beforeRouteEnter 中可用,vm 是组件实例

  1. 安装 axios
  • cnpm install --save vue-axios
  • main.js
import axios from 'axios'
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)
  1. Profile.vue
  export default {
    //第二种取值方式
    // props:['id'],
    name: "UserProfile",
    //钩子函数 过滤器
    beforeRouteEnter: (to, from, next) => {
      //加载数据
      console.log("进入路由之前")
      next(vm => {
        //进入路由之前执行getData方法
        vm.getData()
      });
    },
    beforeRouteLeave: (to, from, next) => {
      console.log("离开路由之前")
      next();
    },
    //axios
    methods: {
      getData: function () {
        this.axios({
          method: 'get',
          url: 'http://localhost:8080/static/mock/data.json'
        }).then(function (response) {
          console.log(response)
        })
      }
    }
  }

Axios

  • 安装:npm install axios
  • main.js
...
import axios from 'axios'
# 基准路径的配置
axios.default.baseURL = 'http://localhost:8888'
# 挂载到原型对象,别的组件中使用 this.$http 
Vue.prototype.$http = axios

Echarts

  • 安装:npm install echarts -S
    • 也可在 index.html 中直接引入 echarts.js文件(渲染路径:index.html->main.js->App.vue->router/index.js)
  • main.js
import * as echarts from "echarts"
# 使用this.$echarts
Vue.prototype.$echarts = window.echarts
  • xxx.vue
<template>
  <div class="com-container">
    <div class="com-chart" ref="sellerRef"></div>
  </div>
</template>

<script>
//基本流程:初始化 echart 对象 =>(分辨率监听)=> 获取数据=>(定时器)=> 更新图表(定时器更新)=>离开时销毁定时器及监听器
// import { getSellerData } from '@/api/seller'
export default {
  data () {
    return {
      chartInstance: null,
      allData:null //发起请求后得到的数据
    }
  mounted () {
    this.initChart()
    this.getData()
    // 分辨率适配
    window.addEventListener('resize', this.screenAdapter)
    // 界面加载完成后主动屏幕适配
    this.screenAdapter()
  }
  destroyed(){
    //销毁监听器、定时器等
    window.removeEventlisterner('resize', this.screenAdapter)
  }
  methods: {
    // 初始化图表
    initChart () {
      this.chartInstance = this.$echarts.init(
        this.$refs.sellerRef
        )
    const initOption = {...}
    this.chartInstance.setOption(initOption)                      
    }
    async getData(){
      // http://localhost:8888/api/seller
      // axios返回的为 Promise 对象
      const (data:ret) = await this.$http.get('seller')
      this.allData = ret
      this.updataCharts()
    }
    updataChart(){
      // 增量更新
      const dataOption = {...}
      this.chartInstance.setOption(dataOption)
  }
    
    screenAdapter(){
      //获取 echart 图表组件宽度
      //标题大小
      const titleFontSize = this.$refs.seller_ref.offersetWidth/100*3.6
      const adapterOption = {
        title: {
          textStyle: {
            fontSize: titleFontSize
          }
        }
      this.chartInstance.setOption(adapterOption)
      // 手动的调用图表对象的resize,才能产生效果
      this.chartInstance.resize()
    }

服务器部署

  1. config/index.js
build: {
    ...
    assetsPublicPath: '/dist/' //修改为 /var/www/html/ 下的文件夹名称
    //即 build 后的文件(index.html、static)所在文件夹
}
  1. router/index.js
export default new Router({
  mode: 'history',
  base: '/dist/',//修改这里
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    }
  ]
})
  1. 打包:npm run build

    生成了 dist 文件夹,将其传输到服务器/var/www/html/下

  2. 服务器:


    • 安装 apaphe2
    • 配置:vim /etc/httpd/conf/httpd.conf
      • 修改端口(默认 8080)
      • *将所有AllowOverride none 修改为AllowOverride All
  3. 访问:http://ip/dist/

后端

Koa

  1. 项目创建
  • 安装:
    • 创建 package.json:npm init -y
    • npm install koa
  • 目录结构:
    • 入口文件:app.js
    • 数据存放:data/
    • 中间件:middleware/
      • Koa_response_data.js
      • ...
    • 工具:utils/
  1. app.js
// 引入Koa
const Koa = require('koa')

// 创建app
const app = new Koa()

// 应用中间件
// 耗时中间件
app.use(require('./middleware/koa_response_duration'))
// 响应头中间件
app.use(require('./middleware/koa_response_header'))
// 逻辑处理中间件
app.use(require('./middleware/koa_response_data'))

// 监听端口
app.listen(9997)

const webSocketService = require('./service/websocket_service')
// 开启服务端的WebSocket监听
webSocketService.listen()
  1. koa_response_data.js
const path = require('path')
const getFileData = require('../utils/file_utils')

module.exports = async (ctx, next) => {
  let filePath = ctx.request.url.replace('/api', '')
  filePath = path.join(__dirname, `../data/${filePath}.json`)
  try {
    const res = await getFileData(filePath)
    ctx.response.body = res
  } catch (err) {
    const errObj = {
      message: '未获取到数据,请检查URL',
      status: 404
    }

    ctx.response.body = errObj
  }

  await next()
}
  1. 跨域:

    要满足同源策略(当前页面地址和ajax 发起请求的地址同协议,同域名,同端口),那就需要中间件设置响应头

koa_response_header.js

module.exports = async (ctx, next) => {
  await next()

  ctx.set('Content-Type', 'application/json;charset=utf-8')
  // 允许跨域
  ctx.set('Access-Control-Allow-Origin', '*')
  ctx.set(
    'Access-Control-Allow-Headers',
    'Content-Type, Content-Length, Authorization, Accept, X-Requested-With'
  )
  ctx.set('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS')
}
  1. 启动:node app.js

WebSocket

后端

  1. 安装:npm i ws -S
  2. app.js
const WebSocket = require('ws')
// 创建WebSocket服务端的对象, 绑定的端口号是9998
const wss = new WebSocket.Server({
  port: 9998
})
//连接事件监听,client 代表 socket 对象
wss.on('connection',client => {
  console.log('连接成功')
  // 对 client 对象进行 message 事件监听
  client.on('message',msg=>{
    console.log(msg)
    //向客户端发送数据
    client.send("hello,client")
  })
})

前端

xxx.html

...
<button id="connect">连接</button>
<button id="send" disabled="true">发送数据</button> <br>
  从服务端接收的数据如下: <br>
<span id="recv"></span>
<script>
    var connect = document.querySelector('#connect')
    var send = document.querySelector('#send')
    var recv = document.querySelector('#recv')
    let ws = null
    connect.onclick = function(){
      //连接 ws 服务器
      ws = new WebSocket('ws://localhost:9998')
      //连接成功事件
      ws.onopen = () => {
        console.log('连接服务端成功了...')
        //button 改为启用状态
        send.disabled = false
      }
      //连接失败事件
      ws.onclose = () => {
        console.log('连接服务器失败')
        send.disabled = true
      }
      //接收数据事件
      ws.onmessage = msg => {
        console.log('接收到从服务端发送过来的数据了')
        console.log(msg)
        recv.innerHTML = msg.data
      }
    }
    send.onclick = function(){
      //向服务端发送数据
      ws.send(JSON.stringify({
        action: 'themeChange',
        socketType: 'themeChange',
        chartName: '',
        value: 'chalk'
      }))
    }
</script>

技巧

Grid

App.vue

#app{
	height: 100%;
  margin: 0;
}

view.vue

<script>
beforeCreate () {
      document.querySelector('html').setAttribute('style', 'height: 100%;')
      document.querySelector('body').setAttribute('style', 'background-color:yellow;height: 100%;')
},
beforeDestroy () {
      document.querySelector('html').removeAttribute('style'),
  		document.querySelector('body').removeAttribute('style')
},

</script>

component.vue

.container{
    height: 100%;
    margin: 0;
}
~  ~  The   End  ~  ~


 赏 
感谢您的支持,我会继续努力哒!
支付宝收款码
tips
文章二维码 分类标签:技术vue
文章标题:Vue学习笔记
文章链接:http://120.46.217.131:82/archives/20/
最后编辑:2022 年 9 月 12 日 23:03 By Yang
许可协议: 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)

相关推荐

热门推荐

(*) 5 + 8 =
快来做第一个评论的人吧~