zf-6-vue (26天)
二.配置vue-config.js
let path = require('path');
let skeletionWebpackPlugin = require('vue-skeleton-webpack-plugin');
module.exports = {
publicPath:process.env.NODE_ENV === 'production'? '/vue-project':'/',
outputDir:'myassets', // 输出路径
assetsDir:'static', // 生成静态目录的文件夹
runtimeCompiler: true, // 是否可以使用template模板
parallel:require('os').cpus().length > 1, //多余1核cpu时 启动并行压缩
productionSourceMap:false, //生产环境下 不使用soruceMap
// https://github.com/neutrinojs/webpack-chain
chainWebpack:config=>{
// 控制webpack内部配置
config.resolve.alias.set('component',path.resolve(__dirname,'src/components'));
},
// https://github.com/survivejs/webpack-merge
configureWebpack:{
// 新增插件等
plugins:[
new SkeletonWebpackPlugin({
webpackConfig: {
entry: {
app: resolve('./src/skeleton.js')
}
}
})
]
},
devServer:{ // 配置代理
proxy:{
'/api':{
target:'http://a.zf.cn:3000',
changeOrigin:true
}
}
},
pages: {
index: { // 首页入口
entry: "./src/main.js"
},
other: { // 其他页面入口
entry: './src/a.js',
chunks:['other'] // 引入的资源
}
},
// 第三方插件配置
pluginOptions: {
'style-resources-loader': {
preProcessor: 'less',
patterns: [
// 插入全局样式
path.resolve(__dirname,'src/assets/common.less'),
],
}
}
}
三.封装axios
import axios from 'axios';
let baseUrl = process.env.NODE_ENV !== 'production'?'http://localhost:8080':'/';
class AjaxRequest{
constructor(){
this.baseURL = baseUrl; // 配置默认路径
this.requestQueue = {}; // 缓存当前请求队列 用来操作loading的显示或者隐藏
}
configInterceptors(instance,url){
// 配置请求拦截
instance.interceptors.request.use( (config) => {
// loading效果 开始请求前显示loading
if(Object.keys(this.requestQueue).length === 0){
console.log('显示loading');
}
this.requestQueue[url] = config.url;
return config;
});
// 配置响应拦截
instance.interceptors.response.use(res=>{
// 取消loading效果
delete this.requestQueue[url];
if(Object.keys(this.requestQueue).length === 0){
console.log('取消loading');
};
if(res.status !== 200){
return Promise.reject(res);
}else{
return res.data;
}
})
}
request(config){
// 创建一个axios实例
let instance = axios.create();
// axios(config);
config = {baseURL:this.baseURL,...config};
this.configInterceptors(instance,config.url);
return instance(config);
}
}
export default new AjaxRequest();
组件间通信 ===========================
安装工具
- npm install @vue-cli@3 -g
- npm install -g @vue/cli-service-global@3 -g
组件通信
-
父传递给子数据 props emit
-
$parent $children
-
$attrs $listeners
-
provide inject 和 context (可以在父组件中声明一个公共数据),在子组件中可以注入原理 (比较混乱,名称问题 他不会在业务代码中使用) 组件库 多级通信为了方便你可以使用provide
-
ref 获取真实dom元素,如果放到组件上 代表的是 当前组件的实例 ,父组件中可以直接获取子组件的方法或者数据
-
eventbus ( p a r e n t , parent, parent,children) 绑定 o n 只 能 通 过 绑 定 on 只能通过绑定 on只能通过绑定on的那个组件来触发 (混乱)
菜单组件 ====================
App.vue调用 menu.vue 传入data
menu.vue 简析data发现children渲染调用Resub渲染,没有的话调用item直接渲染
Resub 核心,发现children调用自己,否则调用item
<zf-submenu >
<!-- 标题 -->
<template slot="title">{{data.name}}</template>
<!-- 内容 -->
<template v-for="menu in data.children">
<!-- 3) 递归当前自己 -->
<a-sub :data="menu" :key="menu.id" v-if="menu.children"></a-sub>
<zf-menu-item v-else :key="menu.id">{{menu.name}}</zf-menu-item>
</template>
</zf-submenu>
</template>
message 应用组件
this.$message.success({
message: "你好",
duration: 3000
});
messge的源码
import MessageComponent from './Message.vue';
import Vue from 'vue';
// 单例
let instance;
let getVueInstance = () => {
// 此instance 是全局的
instance = new Vue({ // 就一个孩子
render: h => h(MessageComponent)
}).$mount();
// 把生成的结果放到页面
document.body.appendChild(instance.$el);
}
const Message = {
success(options) {
// 点击弹出层 需要将.vue文件挂载到 内存中
// 就是将这个 new Vue的操作 只做一次
// 默认如果实例不存在 我就创建一个实例
!instance && getVueInstance();
// 将渲染好的内容 放到 页面中
instance.$children[0].add({
...options,
type:'success'
});
// $mount() document.body.appendChild
// options 就是当前弹出来的框
// 通过数据来驱动
},
info(){
},
warn(){}
}
export {
Message
}
export default {
// _Vue 是当前的构造函数 ,默认Vue.use 就会使用调用这个方法
install(){
// 1) 注册全局组件 2) 注册全局指令 3) 往原型上添加方法 、属性
let $message = {}
Object.keys(Message).forEach(key=>{
$message[key] = Message[key];
})
// 一般使用新对象时 就采用拷贝的方式
Vue.prototype.$message = $message
}
}
// vuex vue-router 表格组件 ,单元测试 cli axios
// 讲项目实战
// render 函数
render
render函数和JSX应用(五)
一.模板缺陷
模板的最大特点是扩展难度大,不易扩展。可能会造成逻辑冗余
<Level :type="1">哈哈</Level>
<Level :type="2">哈哈</Level>
<Level :type="3">哈哈</Level>
Level组件需要对不同的type产生不同的标签
<template>
<h1 v-if="type==1">
<slot></slot>
</h1>
<h2 v-else-if="type==2">
<slot></slot>
</h2>
<h3 v-else-if="type==3">
<slot></slot>
</h3>
</template>
<script>
export default {
props: {
type: {
type: Number
}
}
};
</script>
二.函数式组件
函数式组件没有模板,只允许提供render函数
export default {
render(h) {
return h("h" + this.type, {}, this.$slots.default);
},
props: {
type: {
type: Number
}
}
};
复杂的逻辑变得非常简单
三.JSX应用
使用jsx会让代码看起来更加简洁易于读取
export default {
render(h) {
const tag = "h" + this.type;
return <tag>{this.$slots.default}</tag>;
},
props: {
type: {
type: Number
}
}
};
四.render方法订制组件
编写List组件可以根据用户传入的数据自动循环列表
<List :data="data"></List>
<script>
import List from "./components/List";
export default {
data() {
return { data: ["苹果", "香蕉", "橘子"] };
},
components: {
List
}
};
</script>
<!-- List组件渲染列表 -->
<template>
<div class="list">
<div v-for="(item,index) in data" :key="index">
<li>{{item}}</li>
</div>
</div>
</template>
<script>
export default {
props: {
data: Array,
default: () => []
}
};
</script>
通过render方法来订制组件,在父组件中传入render方法
<List :data="data" :render="render"></List>
render(h, name) {
return <span>{name}</span>;
}
我们需要createElement方法,就会想到可以编写个函数组件,将createElement方法传递出来
<template>
<div class="list">
<div v-for="(item,index) in data" :key="index">
<li v-if="!render">{{item}}</li>
<!-- 将render方法传到函数组件中,将渲染项传入到组件中,在内部回调这个render方法 -->
<ListItem v-else :item="item" :render="render"></ListItem>
</div>
</div>
</template>
<script>
import ListItem from "./ListItem";
export default {
components: {
ListItem
},
props: {
render: {
type: Function
},
data: Array,
default: () => []
}
};
</script>
ListItem.vue调用最外层的render方法,将createElement和当前项传递出来
<script>
export default {
props: {
render: {
type: Function
},
item: {}
},
render(h) {
return this.render(h, this.item);
}
};
</script>
五.scope-slot
使用v-slot 将内部值传即可
<List :arr="arr">
<template v-slot="{item}">
{{item}}
</template>
</List>
<div v-for="(item,key) in arr" :key="key">
<slot :item="item"></slot>
</div>
六.编写可编辑表格
基于iview使用jsx扩展成可编辑的表格
<template>
<div>
<Table :columns="columns" :data="data"></Table>
</div>
</template>
<script>
import Vue from 'vue';
export default {
methods:{
render(h,{column,index,row}){
let value = row[column.key];
return <div on-click={(e)=>this.changeIndex(e,index)} >
{this.index === index?
<i-input type="text" value={value} on-input={(value)=>{
this.handleChange(value,column,row)
}} onOn-enter={()=>this.enter(row,index)}/>:
<span>{value}</span>
}
</div>
},
enter(row,index){
this.data.splice(index,1,row);
this.index = -1;
},
handleChange(value,column,row){
row[column['key']]= value;
},
changeIndex(e,index){
this.index = index;
this.$nextTick(()=>{
e.currentTarget.getElementsByTagName("input")[0].focus()
})
}
},
data() {
return {
index:-1,
columns: [
{
title: 'Name',
key: 'name',
render:this.render
},
{
title: 'Age',
key: 'age',
},
{
title: 'Address',
key: 'address',
},
],
data: [
{
name: 'John Brown',
age: 18,
address: 'New York No. 1 Lake Park',
date: '2016-10-03',
},
{
name: 'Jim Green',
age: 24,
address: 'London No. 1 Lake Park',
date: '2016-10-01',
},
{
name: 'Joe Black',
age: 30,
address: 'Sydney No. 1 Lake Park',
date: '2016-10-02',
},
{
name: 'Jon Snow',
age: 26,
address: 'Ottawa No. 2 Lake Park',
date: '2016-10-04',
},
],
};
},
};
</script>