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