init project
This commit is contained in:
4
.eslintignore
Normal file
4
.eslintignore
Normal file
@@ -0,0 +1,4 @@
|
||||
build/
|
||||
config/
|
||||
dist/
|
||||
lib/
|
||||
41
.eslintrc.js
Normal file
41
.eslintrc.js
Normal file
@@ -0,0 +1,41 @@
|
||||
const eslintConfig = {
|
||||
"root": true,
|
||||
"parserOptions": {
|
||||
"parser": "babel-eslint",
|
||||
"ecmaVersion": 7,
|
||||
"sourceType": "module",
|
||||
"ecmaFeatures": {
|
||||
"jsx": true
|
||||
}
|
||||
},
|
||||
"env": {
|
||||
"browser": true,
|
||||
"es6": true,
|
||||
"node": true
|
||||
},
|
||||
"globals":{
|
||||
"console": true
|
||||
},
|
||||
"extends": [
|
||||
"plugin:vue/essential",
|
||||
"standard"
|
||||
],
|
||||
"plugins": [
|
||||
"vue"
|
||||
],
|
||||
"rules": {
|
||||
"no-var": 1,
|
||||
"no-alert": 1,
|
||||
"no-ternary": 0,
|
||||
"no-self-assign": 0,
|
||||
"standard/no-callback-literal": 0,
|
||||
"func-call-spacing": 0,
|
||||
"prefer-promise-reject-errors": 0,
|
||||
"no-unused-vars": 1,
|
||||
"no-debugger": 1,
|
||||
"no-console": 1,
|
||||
'no-useless-constructor': "off"
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = eslintConfig;
|
||||
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
node_modules/
|
||||
dist/
|
||||
lib/
|
||||
16
.npmignore
Normal file
16
.npmignore
Normal file
@@ -0,0 +1,16 @@
|
||||
.git
|
||||
CVS
|
||||
.svn
|
||||
.hg
|
||||
.lock-wscript
|
||||
.wafpickle-N
|
||||
.*.swp
|
||||
.DS_Store
|
||||
._*
|
||||
yarn.lock
|
||||
npm-debug.log
|
||||
.npmrc
|
||||
node_modules
|
||||
config.gypi
|
||||
*.orig
|
||||
package-lock.json
|
||||
26
README.md
26
README.md
@@ -1,2 +1,24 @@
|
||||
# hoc-element-affix
|
||||
固钉
|
||||
# @hoc-element/affix
|
||||
|
||||
 
|
||||
|
||||
📌 将页面元素固定在在可视范围内。
|
||||
|
||||
## Environment Support
|
||||
|
||||
* Vue 2.5.17
|
||||
|
||||
## Install
|
||||
|
||||
```shell
|
||||
npm install @hoc-element/affix
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```js
|
||||
import Vue from 'vue'
|
||||
import HocElementAffix from '@hoc-element/affix'
|
||||
|
||||
Vue.use(HocElementAffix)
|
||||
```
|
||||
|
||||
42
babelrc.js
Normal file
42
babelrc.js
Normal file
@@ -0,0 +1,42 @@
|
||||
const babelConfig = {
|
||||
presets: [
|
||||
[
|
||||
'@babel/preset-env',
|
||||
{
|
||||
targets: {
|
||||
chrome: '58',
|
||||
ie: '6'
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
plugins: [
|
||||
[
|
||||
'@babel/plugin-transform-runtime',
|
||||
{
|
||||
corejs: false,
|
||||
helpers: true,
|
||||
regenerator: true,
|
||||
useESModules: false
|
||||
}
|
||||
],
|
||||
'@babel/plugin-syntax-dynamic-import',
|
||||
'@babel/plugin-syntax-import-meta',
|
||||
['@babel/plugin-proposal-class-properties', { loose: true }],
|
||||
'@babel/plugin-proposal-json-strings',
|
||||
[
|
||||
'@babel/plugin-proposal-decorators',
|
||||
{
|
||||
legacy: true
|
||||
}
|
||||
],
|
||||
'@babel/plugin-proposal-function-sent',
|
||||
'@babel/plugin-proposal-export-default-from',
|
||||
'@babel/plugin-proposal-export-namespace-from',
|
||||
'@babel/plugin-proposal-numeric-separator',
|
||||
'@babel/plugin-proposal-throw-expressions',
|
||||
'@babel/plugin-transform-modules-commonjs'
|
||||
]
|
||||
}
|
||||
|
||||
module.exports = babelConfig
|
||||
75
package.json
Normal file
75
package.json
Normal file
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"name": "@hoc-element/affix",
|
||||
"version": "0.0.1",
|
||||
"main": "lib/hoc-el-affix.js",
|
||||
"description": "Affix 固钉",
|
||||
"author": "Wisdom <pdsu.wwz@foxmail.com>",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "NODE_ENV=production webpack --progress --colors --hide-modules"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/pdsuwwz/hoc-element-affix.git"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"dependencies": {
|
||||
"vue": "^2.5.17"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.0.0",
|
||||
"@babel/plugin-proposal-class-properties": "^7.0.0",
|
||||
"@babel/plugin-proposal-decorators": "^7.1.2",
|
||||
"@babel/plugin-proposal-export-default-from": "^7.0.0",
|
||||
"@babel/plugin-proposal-export-namespace-from": "^7.0.0",
|
||||
"@babel/plugin-proposal-function-sent": "^7.0.0",
|
||||
"@babel/plugin-proposal-json-strings": "^7.0.0",
|
||||
"@babel/plugin-proposal-numeric-separator": "^7.0.0",
|
||||
"@babel/plugin-proposal-throw-expressions": "^7.0.0",
|
||||
"@babel/plugin-syntax-dynamic-import": "^7.0.0",
|
||||
"@babel/plugin-syntax-import-meta": "^7.0.0",
|
||||
"@babel/plugin-transform-modules-commonjs": "^7.1.0",
|
||||
"@babel/plugin-transform-runtime": "^7.0.0",
|
||||
"@babel/preset-env": "^7.0.0",
|
||||
"@babel/runtime": "^7.1.2",
|
||||
"@babel/runtime-corejs2": "^7.1.2",
|
||||
"babel-eslint": "^10.0.3",
|
||||
"babel-loader": "8.0.0",
|
||||
"cross-env": "^5.0.5",
|
||||
"css-loader": "^0.28.7",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-config-standard": "^14.1.0",
|
||||
"eslint-friendly-formatter": "^4.0.1",
|
||||
"eslint-loader": "^3.0.3",
|
||||
"eslint-plugin-import": "^2.19.1",
|
||||
"eslint-plugin-jsx-a11y": "^6.2.3",
|
||||
"eslint-plugin-node": "^11.0.0",
|
||||
"eslint-plugin-promise": "^4.2.1",
|
||||
"eslint-plugin-standard": "^4.0.1",
|
||||
"eslint-plugin-vue": "^6.1.2",
|
||||
"file-loader": "^1.1.4",
|
||||
"friendly-errors-webpack-plugin": "^1.7.0",
|
||||
"node-notifier": "^6.0.0",
|
||||
"node-sass": "^4.5.3",
|
||||
"sass-loader": "^6.0.6",
|
||||
"vue-loader": "^15.8.3",
|
||||
"vue-template-compiler": "^2.4.4",
|
||||
"webpack": "^4.41.5",
|
||||
"webpack-cli": "^3.3.10"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not ie <= 8"
|
||||
],
|
||||
"keywords": [
|
||||
"vue",
|
||||
"element-ui",
|
||||
"hoc",
|
||||
"affix",
|
||||
"固钉",
|
||||
"组件化"
|
||||
]
|
||||
}
|
||||
85
src/components/ScrollAffix/index.vue
Normal file
85
src/components/ScrollAffix/index.vue
Normal file
@@ -0,0 +1,85 @@
|
||||
<template>
|
||||
<div
|
||||
ref="scroll-affix"
|
||||
:style="affixStyle"
|
||||
class="scroll-affix-container"
|
||||
>
|
||||
<slot/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Affix',
|
||||
props: {
|
||||
offsetTop: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
affixStyle: {
|
||||
position: 'absolute',
|
||||
top: 'initial'
|
||||
},
|
||||
instance: '',
|
||||
defaultInstancePosition: ''
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
this.$nextTick(() => {
|
||||
this.instance = this.$refs['scroll-affix']
|
||||
this.createAffix()
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
getInstanceRect () {
|
||||
return this.instance.getBoundingClientRect()
|
||||
},
|
||||
getWindowScrollTop () {
|
||||
return window.pageYOffset ||
|
||||
document.documentElement.scrollTop ||
|
||||
document.body.scrollTop
|
||||
},
|
||||
createAffix () {
|
||||
this.defaultInstancePosition = this.getInstanceRect().top
|
||||
this.beforeListener()
|
||||
document.addEventListener('scroll', this.scrollListener)
|
||||
},
|
||||
setFixedForInstance () {
|
||||
this.affixStyle = {
|
||||
position: 'fixed',
|
||||
top: `${this.offsetTop}px`
|
||||
}
|
||||
},
|
||||
beforeListener () {
|
||||
if (this.defaultInstancePosition < this.offsetTop) {
|
||||
this.setFixedForInstance()
|
||||
}
|
||||
this.defaultInstancePosition = this.getWindowScrollTop() + this.defaultInstancePosition
|
||||
},
|
||||
scrollListener () {
|
||||
const offsetTop = this.getInstanceRect().top
|
||||
const windowScrollTop = this.getWindowScrollTop()
|
||||
if (offsetTop <= this.offsetTop) {
|
||||
this.setFixedForInstance()
|
||||
}
|
||||
const isArrivalDefault = (this.defaultInstancePosition - this.offsetTop) >= windowScrollTop
|
||||
if (isArrivalDefault && this.affixStyle.position === 'fixed') {
|
||||
this.affixStyle = {}
|
||||
}
|
||||
}
|
||||
},
|
||||
beforeDestroy () {
|
||||
document.removeEventListener('scroll', this.scrollListener)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.scroll-affix-container {
|
||||
position: initial;
|
||||
top: initial;
|
||||
}
|
||||
</style>
|
||||
15
src/main.js
Normal file
15
src/main.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import HocElAffix from './components/ScrollAffix'
|
||||
|
||||
const install = function (Vue, opts = {}) {
|
||||
Vue.component('HocElAffix', HocElAffix)
|
||||
}
|
||||
|
||||
if (typeof window !== 'undefined' && window.Vue) {
|
||||
install(window.Vue)
|
||||
}
|
||||
|
||||
export default {
|
||||
version: '0.0.1',
|
||||
install,
|
||||
HocElAffix
|
||||
}
|
||||
123
webpack.config.js
Normal file
123
webpack.config.js
Normal file
@@ -0,0 +1,123 @@
|
||||
const path = require('path')
|
||||
const webpack = require('webpack')
|
||||
const { VueLoaderPlugin } = require('vue-loader')
|
||||
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin')
|
||||
const notifier = require('node-notifier')
|
||||
|
||||
function resolve (dir) {
|
||||
return path.join(__dirname, '.', dir)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
mode: 'production',
|
||||
entry: './src/main.js',
|
||||
output: {
|
||||
path: path.resolve(__dirname, './lib'),
|
||||
publicPath: '/lib/',
|
||||
filename: 'hoc-el-affix.js',
|
||||
libraryTarget: 'umd'
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
enforce: 'pre',
|
||||
test: /\.(vue|js)(\?.*)?$/,
|
||||
loader: 'eslint-loader',
|
||||
include: resolve('src'),
|
||||
options: {
|
||||
fix: true,
|
||||
failOnError: true,
|
||||
useEslintrc: true,
|
||||
configFile: resolve('.eslintrc.js'),
|
||||
formatter: require('eslint-friendly-formatter')
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
'vue-style-loader',
|
||||
'css-loader'
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.scss$/,
|
||||
use: [
|
||||
'vue-style-loader',
|
||||
'css-loader',
|
||||
'sass-loader'
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.sass$/,
|
||||
use: [
|
||||
'vue-style-loader',
|
||||
'css-loader',
|
||||
'sass-loader?indentedSyntax'
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.vue$/,
|
||||
use: {
|
||||
loader: 'vue-loader'
|
||||
},
|
||||
exclude: /node_modules/,
|
||||
include: resolve('src')
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: /node_modules/,
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
extends: resolve('babelrc.js')
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpg|gif|svg)$/,
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: '[name].[ext]?[hash]'
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
vue$: 'vue/dist/vue.esm.js',
|
||||
'@': resolve('src')
|
||||
},
|
||||
extensions: ['*', '.js', '.vue', '.json']
|
||||
},
|
||||
devServer: {
|
||||
historyApiFallback: true,
|
||||
disableHostCheck: true,
|
||||
inline: false,
|
||||
overlay: true,
|
||||
quiet: true
|
||||
},
|
||||
performance: {
|
||||
hints: false
|
||||
},
|
||||
devtool: 'source-map',
|
||||
plugins: [
|
||||
new VueLoaderPlugin(),
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
minimize: true
|
||||
}),
|
||||
new FriendlyErrorsWebpackPlugin({
|
||||
clearConsole: false,
|
||||
onErrors: (severity, errors) => {
|
||||
if (severity !== 'error') {
|
||||
return
|
||||
}
|
||||
const error = errors[0]
|
||||
notifier.notify({
|
||||
title: 'Webpack error',
|
||||
message: `${severity}: ${error.name}`,
|
||||
subtitle: error.file || ''
|
||||
})
|
||||
}
|
||||
})
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user