【JavaWeb学习】Vue 脚手架

1. 初始化脚手架

1.1. 安装

  • 初次使用前,全局安装@vue/cli npm install -g @vue/cli
  • 切换到要创建项目的目录,然后创建项目 vue create xxx
  • 进入项目目录并启动cd xxx ⟶ \longrightarrow npm run serve

备注:
设置淘宝镜像npm config set registry https://registry.npm.taobao.org
一般用两次Ctrl + c停掉脚手架。

1.2. 项目文件夹

  • .gitignore git 的忽略文件,配置不受git管理的文件或文件夹;
  • babel.config.js babel 的控制文件,配置参考 Vue CLI / Babel
  • package-lock.json 包版本控制文件;
  • package.json 应用包配置文件;
  • vue.config.js Vue 的控制文件,配置参考 Vue CLI;

Vue 脚手架隐藏了所有 webpack 配置,若想查看具体配置,可以执行vue inspect > output.js。所有在配置参考中出现的属性都可以在vue.config.js中自己设置,之后会用其中的设置替换掉默认配置。修改完之后要重新启动脚手架。其他的配置不可以改嗷!

  • src
    main.js 执行完npm run serve命令之后直接运行;
    assets 存放静态资源,图片、视频等;
    components 存放除了 App.vue 之外的所有组件;

创建项目时,main.js 中默认引入的是运行版本的 Vue, 因此如果用 template 配置模板,会报错 “ 缺少模板解析器 ”,解决方式有两种:引入完整版的vue import Vue from 'vue/dist/vue';用render函数进行渲染。bilibili
vue.js 是完整版的 Vue,包含核心功能和模板解析器,vue.runtime.xxx.js 是运行版的 Vue,只包含核心功能,没有模板解析器;
vue.runtime.xxx.js 不能使用 template 配置项,需要用 render 函数接收到的 createElement 函数去指定具体内容。

  • public
    xxx.icon 网页的页签图标;
    index.html 整个应用的界面。
文件目录
learn  
|-- README.md  
|-- babel.config.js  
|-- jsconfig.json  
|-- node_modules  
|-- package-lock.json  
|-- package.json  
|-- public  
|   |-- index.html  
|   |-- kirlant.ico  
|-- src  
|   |-- App.vue  
|   |-- assets  
|   |   |-- logo.png  
|   |-- components  
|   |   |-- School.vue  
|   |   |-- Student.vue  
|   |   |-- Wecome.vue  
|   |-- main.js  
|-- vue.config.js 

2. 使用

2.1. ref属性

  • 给元素或子组件注册引用信息,是 id 的替代者;
  • 应用在 html 标签上获取的是真实DOM元素,应用在组件标签上获取的是组件实例对象;
  • 获取:this.$refs.xxx
<!-- App.vue -->
<template>
    <div class="app">
        <Welcome/>
        <School ref="sch" />
        <Student id="stu" />
        <div class="show">
            <h3 v-text="msg" ref="title"></h3>
            <button ref="btn" @click="showDOM">show upper DOM</button>
        </div>
        
    </div>
</template>
<script>
    // 引入组件
    import Welcome from './components/Wecome';
    import School from './components/School';
    import Student from './components/Student';
    
    export default {
        name:'App',
        data(){
            return{
                msg:"Welcome to yyt's test"
            };
        },
        components:{
            Welcome,
            School,
            Student
        },
        methods:{
            showDOM(){
                console.log(this.$refs.title);  // 真实DOM元素
                console.log(this.$refs);  // 真实DOM元素
                console.log(this.$refs.sch);  // school组件的实例对象
            }
        }
    }
</script>
<style>
    .app{
        width: 400px;
        border: 2px solid #aaa;
        padding: 10px 0;
        
        display: flex;
        flex-wrap: wrap;
        flex-direction: column;
        align-content: center;
    }
    .show{  
        border-top: solid 1px #aaa;  
        text-align: center; 
    }
</style>

2.2. prop

让组件接收外部传过来的数据。

  • 传递数据 <Demo name="xxx"/>
  • 接收数据
// 简单声明接收
props:['name']
//  接收的同时对数据进行类型限制
props:{
    name:String
}
// 接收的同时对数据进行类型限制、默认值指定、必要性设置
props:{
    name:{
        type:String,  // 数据类型
        required:true  // 该属性是必要的
        default:20  // 默认值,不和 required 同时设置
    }
}
  • 备注
    props 是只读的,Vue 底层会检测对props的修改,如果进行了修改,就会发出警告。若确实需要修改,则需要复制 props 的内容到 data中一份,然后修改 data 中的数据。

2.3. mixin

  • 把多个组件共用的配置提取成一个混入对象。
  • 定义并暴露混入:
export const yytMixin = {
	data(){
		return { ... }
	},
	methods:{
	...
	},
	... ...
}
  • 使用混入:
import {yytMixin, ...} from  '../mixin.js'
// 全局混入
Vue.mixin(yytMixin);
// 局部混入(配置对象,与data、methods等平级)
mixins:['yytMixin']

2.4. 插件

  • 用于增强Vue,本质上是包含 install 方法的一个对象,install 的第一个参数是 Vue,第二个以后的参数是插件使用者传递的数据。
  • 定义插件
对象.install = function(Vue, options){
	// 添加全局过滤器
	Vue.filter(...);
	// 添加全局指令
	Vue.directive(...);
	// 配置全局混入
	Vue.mixin(...);
	// 添加实例方法
	Vue.prorotype.方法名 = function(){...};
	Vue.prototype.属性名 = xxx;
};
  • 使用插件 main.js
import plugins from './plugins'
Vue.use(plugins)

2.5. scope样式

让样式在局部作用域生效,防止冲突。<style scoped>

3. 练习

todo-list案例
在这里插入图片描述

  • 组件化编码流程
    拆分静态组件: 按照功能点拆分,命名不能与html元素冲突;
    实现动态组件: 考虑好数据的存放位置,数据是一个组件在用还是多个组件在用 ——
    \qquad 一个组件:放在组件自身即可;
    \qquad 多个组件:放在它们共同的父组件上(状态提升);
    实现交互: 从绑定事件开始。
  • 使用props
    父组件 ⟶ \longrightarrow 子组件 通信
    子组件 ⟶ \longrightarrow 父组件 通信(需要父组件给子组件传一个函数,然后子组件调用这个函数)
    props传过来的若是对象类型的值,那么修改其中的属性值不会报错,但最好不要这样做。
  • 使用v-model
    不能绑定 props 传过来的值,因为 props 传过来的值不能修改。

4. 浏览器本地存储

  • 存储内容大小一般支持 5MB 左右(不同浏览器可能不一样);
  • 浏览器通过Window.sessionStorageWindow.localStorage实现本地存储机制;
  • 相关API
    xxxxxStorage.setItem('key','value')接收一个键和值作为参数,把键值对添加到存储中,如果键名存在,那么更新它对应的值;
    xxxxxStorage.getItem('key')接收一个键名作为参数,返回键对应的值;
    xxxxxStorage.removeItem('key')接收一个键名作为参数,并把该键名从存储中删除;
    xxxxxStorage.clear()清空存储中的所有数据。
  • 备注
    sessionStorage 存储的内容会随着浏览器窗口关闭而消失;
    localStorage 存储的内容需要手动清除才会消失;
    xxxxxStorage.getItem('key')如果对应的value获取不到,那么返回一个null
    JSON.parse(null)的结果依然是null

4.1. local storeage

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="icon" href="../imgs/kirlant.ico">
    <title>kirlant</title>
    <style>
        .root{
        width: 400px;
        border: 2px solid #aaa;
        padding: 10px 40px;
        }
        .title{
            font-weight: bold;
            text-align: center;
            border-bottom: solid 1.5px #aaa;
            padding-bottom: 5px;
        }
        .gap{
            padding: 10px 5px; 
            border-bottom: 1px solid #aaa;
            display: flex;
            flex-wrap: wrap;
            flex-direction: column;
            justify-content: center;
            align-content:center;
        }
        button{
            margin: 5px;
            width: 160px;
        }
    </style>
</head>
<body>
    <div class="root">
        <div class="title">Welcome to Kirlant's Test</div>
        <div class="gap">
            <button onclick="savaData()">save one data</button>
            <button onclick="readData()">read one data</button>
            <button onclick="delData()">delete one data</button>
            <button onclick="delAllData()">delete all data</button>
        </div>
    </div>
    <script type="text/javascript">
        let p = {
            name:'kirlant',
            age:16
        };
        let idx = 0;
        function savaData(){
            localStorage.setItem('person_'+idx,JSON.stringify(p));
            ++p.age;
            ++idx;
        };
        function readData(){
            const result = localStorage.getItem('person_2');
            console.log(JSON.parse(result));
        };
        function delData(){
            localStorage.removeItem('person_2');
        };
        function delAllData(){
            localStorage.clear();
        }
    </script>
</body>
</html>

4.2. session storage

function savaData(){
    sessionStorage.setItem('person_'+idx,JSON.stringify(p));
    ++p.age;
    ++idx;
};
function readData(){
    const result = sessionStorage.getItem('person_2');
    console.log(JSON.parse(result));
};
function delData(){
    sessionStorage.removeItem('person_2');
};
function delAllData(){
    sessionStorage.clear();
}

5. 组件自定义事件

  • 一种组件间通信的方式,适用于 子组件 ⟶ \longrightarrow 父组件;
  • 使用场景:A是父组件,B是子组件,B想给A传数据,那么就要在A中给B绑定自定义事件(事件的回调在A中);
  • 绑定自定义事件:
    方式一:在父组件中<sonComponentName @eventName="callbackName" /><sonComponentName v-on:eventName="callbackName" />
    方式二:在父组件中<sonComponentName ref="refName" /> ... mounted(){ this.$refs.refName.on("eventName", this.callbackName); }
    若想让自定义事件只能触发一次,可以使用once修饰符或$once方法。
  • 触发自定义事件:this.$emit('eventName', data);
  • 解绑自定义事件:this.$off('eventName');
  • 组件上可以绑定原生DOM事件,需要使用native修饰符;
  • 通过**this.$refs.refName.on("eventName", this.callbackName)**绑定自定义事件时,回调要么配置在methods中,要么用箭头函数,否则this指向会出问题。
    啾咪

6. 全局事件总线

一种组件间通信的方式,适用于任意组件间通信。

  • 安装 (我绑我自己???)
new Vue({
	...
	beforeCreate(){
		Vue.prototype.$bus = this; // 安装全局事件总线,$bus就是当前使用的 vm
	}
	...
})
  • 使用
    接收数据:A组件想接收数据,则在A组件中给$bus绑定自定义事件,事件的回调留在A组件自身
    提供数据:this.$bus.$emit( 'xxx', 数据 )
methods(){
	demo(data){...}
},
...
mounted(){
	this.$bus.$on('xxx', this.demo);
}

最好在beforeDestroy钩子中用$off解绑当前组件用到的事件。

7. 消息订阅与发布

一种组件间通信的方式,适用于任意组件间通信。

  • 安装: npm i pubsub-js
  • 引入: import pubsub from pubsub-js
  • 接收数据:A组件想接收数据,则在A组件中订阅消息,订阅的回调留在A组件自身;
methods(){
	demo(data){...};
},
...
mounted(){
	this.pid = pubsub.subscribe('xxx', this.demo); // 订阅消息
}
  • 提供数据:pubsub.publish('xxx', 数据)

最好在beforeDestroy钩子中用pubsub.unsubscribe(this.pid)取消订阅。

8. 动画与过渡

  • 作用
    在插入、更新或移除DOM元素时,在合适的时候给元素添加样式类名。
  • 写法
    a). 准备样式
    \quad 进入:v-enter起点;v-enter-active过程中;v-enter-to终点;
    \quad 离开:v-leave起点;v-leave-active过程中;v-leave-to终点;
    b). 用<transition>包裹要过渡的元素,并配置name属性
    备注:若有多个元素需要过渡,则需要使用<transition-group>,且每个元素都要指定key值。
<transition name="yyt">
    <div class="great" v-show="isShow">太强了!</div>
</transition>

9.配置代理

  • 方法一
    vue.config.js中添加如下配置:devServer: {proxy: 'http://localhost:5000'};
    优点:配置简单,请求资源时直接发给前端(8080)即可;
    缺点:不能配置多个代理,不能灵活控制是否走代理;
    工作方式:优先匹配前端资源,只有当请求了前端不存在的资源时,请求才会转发给服务器。
  • 方法二
    vue.config.js配置具体代理规则;
    优点:可以配置多个代理,可以灵活控制是否走代理;
    缺点:配置略微繁琐,且请求资源时必须加前缀。
devServer: {
    proxy: {
      '/api': { // 匹配所有以 '/api' 开头的请求路径
        target: 'http://localhost:5000', // 代理目标的基础路径
        pathRewrite:{'^/api':''},
        ws: true, // 用于支持 websocket
        changeOrigin: true //控制请求头中的host值
      },
      '/finish': {
        target: 'http://localhost:5001',
        pathRewrite:{'^/finish':''},
        ws: true, 
        changeOrigin: true
      }
    }
  }

changeOrigin默认值为true;
设置为 true 时,服务器收到的请求头中的host为 localhost:5000(服务器的端口号);
设置为 false 时,服务器收到的请求头中的host为 localhost:8080(代理服务器实际的端口号)

10. 插槽

作用: 让父组件可以向子组件指定位置插入html结构,也是一种组件间通信的方式,适用于 父组件 ⟶ \longrightarrow 子组件;
分类: 默认插槽,具名插槽,作用域插槽;
使用方式:

  • 默认插槽
<!-- 父组件中 -->
<OneCategory>
    <div>html结构</div>
</OneCategory>
<!-- 子组件中 -->
<template>
	<div>
	<!-- 定义插槽 -->
	<slot>插槽默认内容</slot>
	</div>
</template>
  • 具名插槽
<!-- 父组件中 -->
<OneCategory">
	<template slot="name1">
		<div>html结构</div>
	</template>
    <template v-slot:name2>
		<div>html结构</div>
	</template>
</OneCategory>
<!-- 子组件中 -->
<template>
	<div>
	<!-- 定义插槽 -->
	<slot name="name1">插槽默认内容</slot>
	<slot name="name2">插槽默认内容</slot>
	</div>
</template>
  • 作用域插槽
    数据在子组件自身,但根据数据生成的结构要由使用它的父组件决定。
<!-- 父组件中 -->
<div class="container">
    <!-- 父组件中 -->
    <OneCategory title="游戏">
        <template slot-scope="data">
            <ul><li v-for="(item, index) in data.games" :key="index">{{item}}</li></ul>
        </template>
    </OneCategory>
    <OneCategory title="游戏">
        <template slot-scope="data">
            <ol><li v-for="(item, index) in data.games" :key="index">{{item}}</li></ol>
        </template>
    </OneCategory>
    <OneCategory title="游戏">
        <template slot-scope="data">
            <h4 v-for="(item, index) in data.games" :key="index">{{item}}</h4>
        </template>
    </OneCategory>
</div>
<!-- 子组件中 -->
<template>
    <div class="category">
        <h3>{{title}}</h3>
        <!-- 定义一个插槽,等待组件的使用者进行填充 -->
        <slot :games="games"></slot>
    </div>
</template>
<script>
    export default {
        name:"OneCategory",
        props:['title'],
        data(){
            return { games:['红色警戒','穿越火线','劲舞团','超级玛丽']}
        }
    }
</script>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值