<repo_name>karencxx/vue-demo<file_sep>/mockserver/server.js
const http = require('http')
const url = require('url')

function start(route, handle) {

	function onRequest(req, res) {
		let pathname = url.parse(req.url).pathname;
		console.log('Request for ' + pathname + ' received.');

		route(handle, pathname, res); //将handle对象作为第一个参数传递给route()回调函数

		// res.writeHead(200, {'Content-Type': 'text/json'});
		// res.write('Hello World! ');

		let resp = {
			code : 0,
			time : +new Date(),
			data : {
				name : 'desmond',
				gender : 'male'
			}
		};

		// res.end(JSON.stringify(resp));//将resp转换为JSON字符串返回
	}

	http.createServer(onRequest).listen(8081, '127.0.0.1');
	console.log('Server has started.');
}

exports.start = start;

<file_sep>/src/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, { h } from 'vue';
import App from './App'
import router from './router'
import store from './vuex/store'
import directives from './directives/index'
import ViewUI from 'view-design'
import axios from 'axios'
import configComponents from './config-components'
import 'view-design/dist/styles/iview.css'
import './theme/index.less';

Vue.config.slient = false //取消Vue所有的日志与警告

require('./mock.js') //引入mock.js
Vue.prototype.$http = axios

Vue.use(router)
Vue.use(directives)
// Vue.use(ViewUI)
configComponents(Vue) //全局注册component

Vue.config.devtools = true
console.log(process.env, process.env.VUE_APP_API_ENV, 'env')
/* eslint-disable no-new */
let app = new Vue({
  store, //inject store to all children
  // el: '#app',
  router,
  // template: '<App/>',
  // components: { App }
  render: () => h(App),
})
let container = document.querySelector('#app')
console.log(container, 'container')
if(container) {
  container.innerHTML = ''
}

app.$mount(container)
//指定组件的渲染和观察期间未捕获错误的处理函数。这个处理函数被调用时，可获取错误信息和vue实例。
Vue.config.errorHandler = function(err, vm, info){

}<file_sep>/src/vuex/store.js
import Vue from 'vue'
import Vuex from 'vuex'
import * as actions from './actions'
import * as format from '../utils/dateFormat'

Vue.use(Vuex)

//the root, initial state object
const state = {
	notes: [],
	activeNote: {},
	count: 0
}

//define the possible mutations that can be applied to our state
// 同步函数
const mutations = {
	ADD_NOTE(state){
		const newNote = {
			text: 'Get a new note!',
			favorite: false,
			createTime: format.formatNow()
		}
		state.notes.push(newNote)
		state.activeNote = newNote
	},

	EDIT_NOTE(state,text){
		state.activeNote.text = text
	},

	EDIT_CONTENT(state, text){
		state.activeNote.content = text
		console.log(text, '======')
		console.log(state.activeNote.content.length)
	},

	DELETE_NOTE(state){
		state.notes = state.notes.filter(note => note != state.activeNote)
		if(state.notes[0]){
			state.activeNote = state.notes[0]
		}
	},

	TOGGLE_FAVORITE(state){
		state.activeNote.favorite = !state.activeNote.favorite
	},

	SET_ACTIVE_NOTE(state,note){
		state.activeNote = note
	}

}

const getters = {
  notes: state => state.notes,
  activeNote: state => state.activeNote,
  activeNoteText: state => state.activeNote.text,
  activeNoteContent: state => state.activeNote.content,
  createTime: state => state.activeNote.createTime,
  count: state => state.notes.length
}

//create the Vuex instance by combining the state and mutations objects
//then export the Vuex store for use by our components
export default new Vuex.Store({
	state,
	mutations,
	getters,
	actions
})<file_sep>/note.md
BFC GFC IFC FFC
BOX-level box 
普通流、浮动流、定位流
FC formatting context 格式化上下文
页面中的一块渲染区域，有一套渲染规则，
决定了其子元素如何布局以及和其他元素之间的关系和作用

会生成BFC
html
float != none 
overflow != visible
display: inline-block table-cell table-caption
position absolute fixed


自适应两栏布局
可以阻止元素被浮动元素覆盖
可以包含浮动元素--清除内部浮动
分属于不同的BFC时可以阻止margin重叠

update to Vue 3.0
update latest @vue/cli
vue add vue-next

vite <file_sep>/INFO.md
# 项目结构

>build -- webpack相关配置 cli3 已移除
```bash
 build.js -- webpack打包配置文件
 check-version.js -- 检查npm,nodejs版本
 utils.js -- 配置资源路径,配置css加载器
 vue-loader.conf.js -- 配置css加载器等
 webpack.base.conf.js -- webpack基础配置
 webpack.dev.conf.js -- 开发所用webpack配置
 webpack.prod.conf.js -- 打包用webp配置
```

>config -- 配置文件

>node_modules -- 存放依赖的目录

>src -- 源码
```bash
 assets -- 静态文件
 components -- 组件
 main.js -- 主入口js
 App.vue -- 项目入口组件
 router -- 路由
```

>package.json -- node配置文件

>.babelrc -- babel配置文件 cli3 已移除

>.editorconfig -- 编辑器配置

>.gitignore -- 配置git可忽略的文件
<file_sep>/src/utils/dateFormat.js
Date.prototype.format = function(format){
	var o = {
		"M+": this.getMonth() + 1,
		"d+": this.getDate(),
		"h+": this.getHours(),
		"m+": this.getMinutes(),
		"s+": this.getSeconds(),
		"q+": Math.floor((this.getMonth() + 3) / 3),
		"S+": this.getMilliseconds()
	}
	var week = ["星期日","星期一","星期二","星期三","星期四","星期五","星期六"]
	if(/(y+)/.test(format)) {
		format = format.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length))
	}
	if(/(w+)/.test(format)){
		format = format.replace(RegExp.$1, week[this.getDay()]);
	}
	for(var k in o){
		if(new RegExp("("+ k + ")").test(format)){
			format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length))
		}
	}
	return format
}

/**
*	js时间对象的格式化
*	eg: format = "yyyy-MM-dd hh:mm:ss"
*/
export function formatDate(format, pattern) {
	const Format = format ? format instanceof Date ? format : new Date(typeof format == "number" ? format : format.replace(/-/g, "/")) : new Date(),
		  Pattern = pattern || "yyyy-MM-dd hh:mm:ss"

	return Format.format(Pattern)
}

export function formatNow(pattern) {
	const Pattern = pattern || 'yyyy-MM-dd hh:mm:ss'
	return new Date().format(Pattern)
}

export function DateFormat(format) {
	return format ? format instanceof Date ? format : new Date(typeof format == "number" ? format : format.replace(/-/g, "/")) : new Date()	
}

export function formatTime(format) {
	return format ? DateFormat(format).valueOf() :  +new Date
}<file_sep>/src/components/custom-code.js
export default {
    name: 'customCode',
    props: {
        template: String, // template 模板
        js: String, // js 逻辑
        css: String, // css 样式
    },
    computed: {
        className() {
            // 生成唯一class, 主要用于做scoped的样式
            const uid = Math.random().toString(36).slice(2)
            return `custom-code-${uid}`
        },
        scopedStyle() {
            if(this.css) {
                const scope = `.${this.className}`
                const reg = /(^|\})\s*([^{]+)/g
                // 为class 加前缀， 做类似scope的效果
                return this.css.trim().replace(reg, (m, g1, g2) => {
                    return g1 ? `${g1} ${scope} ${g2}` : `${scope} ${g2}`;
                })
            }
            return ''
        },
        component() {
            // 把代码字符串转成JS对象
            const result = safeStringToObject(this.js)
            const component = result.value

            if(result.error) {
                console.log('js 脚本错误', result.error)
                result.error = {
                    msg: result.error.toString(),
                    type: 'js脚本错误'
                }
                result.value = { hasError: true }
                return result
            }
            // 去掉template前后标签
            const template = (this.template || '')
                                .replace(/^ *< *template *> | <\/ *template *> *$/g, '')
                                .trim()
            
            // 注入template或render，设定template优先级高于render
            if(this.template) {
                component.template = this.template
                component.render = undefined
            } else if(!component.render) {
                component.render = '<div>未提供模板或render函数</div>'
            }

            return result
        }
    },
    render() {
        const { component } = this
        return (
            <div class={this.className}>
                <style>{this.scopedStyle}</style>
                <component />
            </div>
        )
    }
}<file_sep>/index.js
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/mydb'); //连接上 mydb 数据库

var Schema = mongoose.Schema;
var userSchema = new Schema({
	name: String,
	pass: String,
	email: String,
	createTime: Date,
	lastLogin: Date
})<file_sep>/src/router/index.js
import { createApp } from 'vue'
import Router from 'vue-router'
// import ViewUI from 'view-design'
import components from '@/router/components'

const app = createApp()
app.use(Router)
// Vue.use(ViewUI)
console.log('======', 'router/index')

const router = new Router({
	mode: 'history', // H5 history API
	routes: [
		// {
		//   path: '/hello',
		//   name: 'HelloWorld',
		//   component: components.HelloWorld
		// },
		{
			path: '/login',
			name: 'login',
			alias: '登录页面',
			component: components.Login
		},
		{
			path: '/',
			name: 'index',
			meta: {
				title: '目录页'
			},
			alias: '目录页面', //别名
			component: components.Home
		},
		{
			path: '/cssIndex',
			name: 'cssIndex',
			meta: {
				title: 'css练习专栏'
			},
			component: components.cssIndex
		},
		{
			path: '*',
			name: '404',
			alias: '404页面',
			component: components.NotFindPage
		},
		{
			path: '/note',
			name: 'note',
			alias: '笔记',
			component: components.Note
		},
		{
			path: '/easyToolbar',
			name: 'easyToolbar',
			alias: '超简易工具栏',
			component: components.easyToolbar
		},
		{
			path: '/mixin',
			name: 'mixin',
			alias: '混入mixin',
			component: components.Model
		},
		{
			path: '/test',
			name: 'test',
			alias: '测试页面',
			component: components.Test
		},
		{
			path: '/code',
			name: 'code',
			alias: '简易代码工具',
			component: components.Code
		},
		// {
		// 	path: '/scroll-css',
		// 	name: 'scroll-css',
		// 	alias: '',
		// 	component: components.ScrollCss
		// },
		{
			path: '/rate',
			name: 'rate',
			alias: '✨评价练习',
			component: components.Rate
		},
		{
			path: '/btn-hover',
			name: 'btn-hover',
			alias: '炫酷按钮',
			component: components.BtnHover
		},
		{
			path: '/panorama',
			name: 'panorama',
			alias: '全景图',
			component: components.Panorama
		},
		{
			path: '/scroll',
			name: 'scroll',
			alias: '上移置顶',
			component: components.Scroll
		},
		{
			path: '/myh5',
			name: 'myh5',
			alias: '移动web',
			component: components.Myh5
		},
		{
			path: '/mock',
			name: 'mock',
			alias: 'mock',
			component: components.MockDemo
		},
		{
			path: '/data',
			name: 'mock_data',
			alias: 'mock_data',
			component: components.Data
		},
		{
			path: '/css',
			name: 'css',
			alias: 'css',
			component: components.Css
		},
		{
			path: '/loading-animation',
			name: 'loading-animation',
			alias: 'loading动画',
			component: components.LoadingAnimation
		}, 
		{
			path:'/roller',
			name: 'roller',
			alias: '过山车动画',
			component: components.Roller
		},
		{
			path: '/bezier',
			name: 'bezier',
			alias: '曲线动效',
			component: components.Bezier
		},
		{
			path: '/mint',
			name: 'mintCandy',
			alias: '薄荷糖动画',
			component: components.MintCandy
		}, 
		{
			path: '/navHover',
			name: 'navHover',
			alias: '从按钮两侧滑入装饰元素的悬停特效',
			component: components.NavHover
		},
		{
			path: '/openPopup',
			name: 'openPopup',
			alias: '打开内容弹窗样式',
			component: components.openPopup
		},
		{
			path: '/cssModules',
			name: 'cssModules',
			alias: 'css-modules',
			component: components.cssModules
		},
		{
			path: '/ripples',
			name: 'ripples',
			alias: '水波荡漾',
			component: components.Ripples
		}, 
		{
			path: '/math',
			name: 'math',
			alias: '算术',
			component: components.Math
		},
		{
			path: '/lottie',
			name: 'lottie',
			alias: 'lottie动画',
			component: components.Lottie
		},
		{
			path: '/review',
			name: 'review',
			alias: '温故而知新',
			component: components.review
		},
		{
			path: '/charge',
			name: 'charge',
			alias: '苹果充电线',
			component: components.Charging
		},
		{
			path: '/airplane',
			name: 'airplane',
			alias: '飞机窗',
			component: components.Airplane
		},
		{
			path: '/collection',
			name: 'collection',
			alias: '集合',
			component: components.Collection
		},
		{
			path: '/border',
			name: 'border',
			alias: '边框集合',
			component: components.Border
		},
		{
			path: '/question',
			name: 'question',
			alias: '50个css基础问题',
			component: components.Questions
		},
		{
			path: '/whatisvue',
			name: 'whatisvue',
			alias: 'vue 解密',
			component: components.Whatisvue
		},
		{
			path: '/turntable',
			name: 'turntable',
			alias: '大转盘',
			component: components.Turntable
		},
		{
			path: '/optimization',
			name: 'optimization',
			alias: 'vue优化小技巧',
			component: components.Main
		},
		{
			path: '/dragon',
			name: 'dragon',
			alias: '画龙',
			component: components.Dragon
		}
	]
})

router.beforeEach((to, from, next) => {
	// ViewUI.LoadingBar.start()
	next()
})

router.afterEach(route => {
	// ViewUI.LoadingBar.finish()
})
export default router<file_sep>/src/mock.js
//尝试一下mockjs，mock数据
//添加mock规则
const Mock = require('mockjs');

//获取 mock.Random 对象
const Random = Mock.Random;

//mock data
const producerNewsData = function() {
	let articles = [];
	for(let i = 0; i < 100; i++) {
		let newArticleObject = {
			title: Random.csentence(5, 30), //Random.csentence( min,max )
			thumbnail_pic_s: Random.dataImage('300*350', 'mock的图片'), // Random.dataImage( size, test) 生成一段随机的 base64 图片编码
			author_name: Random.cname(), // Random.cname() 随机生成一个常见的中文姓名
			date: Random.date() + ' ' + Random.time() // Random.date()指示生成的日期字符串的格式，默认为yyyy-mm-dd: Random.time 返回一个随机时间字符串
		}

		articles.push(newArticleObject);
	}

	return {
		articles: articles
	}
}

//弹幕数据
const producerBarrage = function() {
	let arr = [];
	for(let i = 0; i < 50; i++) {
		let str = `${Random.first()}刚刚买了`;
		arr.push(str);
	}

	return {
		list: arr
	}
}

//滚动数据
const producerCarousel = function() {
	let arr = [];
	for(let i = 0; i < 10; i++) {
		let obj = {
			name: Random.first(),
			time: Random.time('HH:mm:ss'),
			from: Random.province()
		};
		arr.push(obj);
	}

	return {
		list: arr
	}
}

const randomWord = function () {
	let arr = [];
	let num = [];
	let id
	function getId () {
		return Random.integer(1,10)
	}
	for (let i = 0; i < 5; i++) {
		do {
			id = getId()
		}while (num.includes(id))
		num.push(id)
		arr.push({
			word: Random.word(),
			id: num[i],
			date: Random.now(),
			isCheck: Random.boolean()
		});
	}

	return {
		list: arr
	}
}

// Mock.mock( url, post/get, 返回的数据)
Mock.mock('/news/index', 'post', producerNewsData);
Mock.mock('/barrage/get', 'post', producerBarrage);
Mock.mock('/carousel/get', 'post', producerCarousel);
Mock.mock('/get/random', 'post', randomWord);
Mock.mock('/get/check', 'post', Random.boolean());




<file_sep>/test/add.js
const add = require('../qunit/add.js');

QUnit.module('add');

QUnit.test('add two numbers', assert => {
    assert.equal(add(1, 1), 2);
});

QUnit.test('unique value', assert => {
    const set = new Set([1,2,3,4,5,4])
    assert.deepEqual([...set], [1,2,3,4,5],'passed')
})

QUnit.test('NaN', assert => {
    const items = new Set([NaN, NaN])
    assert.ok(items.size === 1, 'passed')
})
<file_sep>/deploy.sh
#!/bin/bash
git_url=<EMAIL>:karencxx/vue-demo-dist.git
# git_url=https://github.com/karencxx/vue-demo-dist.git
source_dir=dist
dest=".deploy/master"

# 当发生错误时中止脚本
set -e

if [ ! -d $dest ]; then
    git clone $git_url $dest --depth=1
fi

# 记录现在的目录位置
cur=`pwd`

# 进入git目录
cd $dest

# git checkout .
git add .
git stash

# reset为线上最新版本
git pull origin master
git reset --hard origin/master
    
# 然后再pull一下
git pull origin master

# 回到原来的目录
echo ---back
cd $cur

# 构建
echo +++run build script
npm run build
echo ---build end

echo +++cpCode start
# 复制代码 , --exclude排除不需要传输的文件模式
rsync -r --delete --exclude='.git' $source_dir/. $dest
echo ---cpCode end

# cd 到构建输出的目录下
cd $dest

echo +++commit start
# 部署到自定义域名
git add .
git commit -m "commit in `date '+%Y-%m-%d %H:%M:%S'`"

# 部署到远程git
git push origin master
echo ---commit end

cd -

exit<file_sep>/src/mixins/code-generate.js

export const generate = {
	data() {
		return {
			html: ''
		}
	},
	methods: {
		genHtml(data) {
			console.log(data, 'gen html element');

			if(data.type == "table") {
				let a = `<table class="`;

				for(let i = 0; i < data.theadClass.length; i++){
					a += `${data.theadClass[i]} `;
				}
				a += `">
						<thead>
						<tr>`;
				
				for(let i = 0; i < data.column; i++){
					a += `<th>${data.thead[i]? data.thead[i] : ''}</th>`;
				}
				a += `</tr>
						</thead>
						<tbody>
							<tr>`;

				for(let i = 0; i < data.column; i++){
					a += data.tbody[i] ? `<td>{{ ${data.tbody[i]} }}</td>` : `<td></td>`;
				}

				a +=`</tr>
						</tbody>
							</table>`;

				this.html = a;
			}

			if(data.type == "form") {}

			return this.html;
		}
	},
	mounted() {
	}

}<file_sep>/src/directives/index.js
import Vue from 'vue'

//注册一个全局自定义指令 'v-focus'

const focus = Vue.directive('focus', {
	//当被绑定的元素插入到 DOM 中时
	inserted: function (el) {
		//聚焦元素
		console.log('自动聚焦')
		el.focus()
	}
})

// export default {
// 	focus
// }

<file_sep>/vue.config.js
const path = require('path')
const resolve = dir => path.join(__dirname, dir)

module.exports = {
    publicPath: '/',
    outputDir: 'dist',
    assetsDir: 'static',
    productionSourceMap: false,
    lintOnSave: false,
    devServer: {
        port: 8080,
        proxy: '', //设置代理
        inline: true, // 实时刷新
        hot: true
    },
    css: {
        requireModuleExtension: false, // 启用css modules
        extract: true, // 是否使用css分离插件
        sourceMap: false,
        loaderOptions: {
            less: {
                javascriptEnabled: true,
                globalVars: {
                    global_prefix: 'ssss'
                }
            }
        }
    },
    chainWebpack: config => {
        config
        .plugin('html')
        .tap(args => {
            if(process.env.dev) {
                args[0].template = './public/index.html'
            }
            return args
        })

        config.resolve.alias
            .set('static', resolve('public/static'))
            .set('@', resolve('src'))
    },
    configureWebpack: config => {
        if(process.env.NODE_ENV === 'production') {
            // 为生产环境修改配置
        } else {
        
            // 为开发环境修改配置
        }
    }
}<file_sep>/src/config-components.js
//命名用-连接
const componentsList = [
  { prefix: 'v-', name: 'global' }
]

export default function(Vue) {
  componentsList.forEach(function(item, index) {
    // let url = './global-components/' + item.name + '.vue';
    // require(url);
    //上面的写法会报错,url被认为是字符串,因此不能被解析

    /**
     * add the require .default
     * add .default to require('xxx.vue') or import('xxx.vue') it will work right
     * vue-loader- 13.0.0 will set the vue component as a esModule by default. 
     * Before 13.0.0 vue-loader set the vue component as CommonJsModule
     * esModule只读引用
     */
    let comp = require('./global-components/' + item.name + '.vue').default;

    Vue.component(`v-${item.name}`, comp);
  })
}
